*** empty log message ***
[bpt/emacs.git] / src / unexaix.c
CommitLineData
76998edb
JB
1/* Dumping and loading data areas, for Emacs under AIX.
2 (It may also work on other kinds of system V.)
3 Copyright (C) 1990 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 1, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
19the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21/* This is based on a public domain program written by IBM. */
22
23/*************** SYSTEM DEFINES *********************************/
24
25#include "config.h"
26#include "paths.h"
27#include <sys/types.h>
28#include <sys/files.h>
29#include <fcntl.h>
30#include <sys/mode.h>
31#include <sys/ipc.h>
32#include <sys/shm.h>
33#include <malloc.h>
34#include <stdio.h> /* MWW */
35#include "lisp.h"
36
37/*************** LOCAL DEFINES **********************************/
38
39struct data_header /* saved data header */
40{
41 char *start; /* dump _data addr */
42 char *end; /* dump _end addr */
43 char *sbrk1; /* dump original sbrk addr */
44 char *sbrk2; /* dump final sbrk addr */
45 int puresize; /* size of pure data dumped */
46};
47
48#define EMACSSHMKEY "EMACSSHMKEY"
49#define EMACS_DATA_FILE "EMACS-DATA"
50#define NEW_SHMGET_FLAGS (IPC_CREAT | S_IWUSR | S_IRUSR \
51 | S_IWGRP | S_IRGRP | S_IWOTH | S_IROTH)
52#define OLD_SHMAT_FLAGS SHM_RDONLY
53#define OLD_SHMGET_FLAGS (S_IRUSR | S_IRGRP | S_IROTH)
54#define OLD_OPEN_FLAGS O_RDONLY
55#define NEW_OPEN_FLAGS (O_RDWR | O_CREAT | O_TRUNC)
56
57/*************** EXTERNAL / GLOBAL DATA AREA ********************/
58
59extern char _data; /* start of data addr */
60extern char _end; /* end of all data + 1 addr */
61static char *original_sbrk; /* sbrk when dump first run */
62
63void
64map_in_data (use_dumped_data)
65 int use_dumped_data;
66{
67 int bufsize; /* malloc buffer size */
68 struct data_header dh; /* saved data header */
69 int fd; /* saved data file descriptor */
70 char *finaladdr; /* last addr in bucket */
71 char *ipckey = getenv (EMACSSHMKEY); /* env ipc key string */
72 int length; /* dumped data lengths */
73 char *newaddr; /* new malloc buffer addr */
74 int numblks; /* number of remaining mallocs */
75 int shmid; /* shared memory id */
76 key_t shmkey; /* shared memory key */
77 /* Note that using malloc here may not be safe. */
78 char name[sizeof (PATH_EXEC) + sizeof (EMACS_DATA_FILE) + 2];
79
80 /* Consume remaining malloc space without increasing */
81 /* the end of data space */
82 original_sbrk = sbrk (0);
83 for (bufsize = 16; bufsize < getpagesize (); bufsize *= 2)
84 {
85 while ((newaddr = (char *)malloc (bufsize - 8)) < original_sbrk)
86 ;
87 for (numblks = (getpagesize () / bufsize) - 1; numblks > 0; numblks--)
88 malloc (bufsize - 8);
89 finaladdr = sbrk (0);
90 }
91 original_sbrk = sbrk (0);
92
93 /* If we don't want the dumped data, get an unshared segment. */
94 if (!use_dumped_data)
95 {
96 shmid = shmget (IPC_PRIVATE, PURESIZE, NEW_SHMGET_FLAGS);
97 if (shmid == -1
98 || shmat (shmid, (char *)PURE_SEG_BITS, 0) == -1)
99 {
100 fprintf (stderr, "emacs: failure obtaining new unshared memory segment.\n");
101 exit (1);
102 }
103 return;
104 }
105
106 /* Compute the file name with the dumped data. */
107 strcpy (name, PATH_EXEC);
108 strcat (name, "/");
109 strcat (name, EMACS_DATA_FILE);
110
111 /* Open the file and make sure the addresses have not changed. */
112 fd = open (name, OLD_OPEN_FLAGS, 0);
113 if (fd < 0)
114 {
115 fprintf (stderr, "emacs: failure opening `%s'\n", name);
116 exit (1);
117 }
118 if (read (fd, (char *)&dh, sizeof (dh)) != sizeof (dh)
119 || dh.start != &_data
120 || dh.end != &_end
121 || dh.sbrk1 != original_sbrk
122 || dh.puresize != PURESIZE)
123 {
124 fprintf (stderr, "emacs: header mismatch in `%s'\n", name);
125 exit (1);
126 }
127
128 /* Load in the unshared contents. */
129 if (!(length = dh.end - dh.start)
130 || read (fd, (char *)&_data, length) != length
131 || !(length = dh.sbrk2 - dh.sbrk1)
132 || brk (dh.sbrk2) == -1
133 || read (fd, dh.sbrk1, length) != length)
134 {
135 fprintf (stderr, "emacs: failure loading unshared data.\n");
136 exit (1);
137 }
138
139 /* Determine ipc key from environment or default */
140 if (ipckey && *ipckey)
141 shmkey = atoi (ipckey);
142 else
143 shmkey = SHMKEY;
144
145 /* Attach to "pure data" shared memory segment */
146 if ((shmid = shmget (shmkey, 0, 0)) == -1
147 || (newaddr = shmat (shmid, (char *)PURE_SEG_BITS, OLD_SHMAT_FLAGS)) == -1)
148 {
149 /* We were unable to open an existing segment. Make a new one. */
150 struct shmid_ds buf;
151
152 /* First get rid of the one we tried to get. */
153 shmdt ((char *)PURE_SEG_BITS);
154 shmctl (shmid, IPC_RMID, 0);
155
156 /* If we could not write the data file,
157 don't make a shared segment that we could write.
158 Make an unshared segment instead. */
159 if (access (name, W_OK) == 0)
160 {
161 shmid = shmget (IPC_PRIVATE, PURESIZE, NEW_SHMGET_FLAGS);
162 if (shmid == -1
163 || shmat (shmid, (char *)PURE_SEG_BITS, 0) == -1)
164 {
165 fprintf (stderr, "emacs: failure obtaining new unshared memory segment.\n");
166 exit (1);
167 }
168
169 /* Load the proper data into it. */
170 if (read (fd, PURE_SEG_BITS, PURESIZE) != PURESIZE)
171 {
172 fprintf (stderr, "emacs: failure loading shared memory data.\n");
173 shmdt ((char *)PURE_SEG_BITS);
174 shmctl (shmid, IPC_RMID, 0);
175 exit (1);
176 }
177
178 close (fd);
179 return;
180 }
181
182 /* Allocate the new shared segment and arrange to write it. */
183 if ((shmid = shmget (shmkey, PURESIZE, NEW_SHMGET_FLAGS)) == -1
184 || shmat (shmid, (char *)PURE_SEG_BITS, 0) == -1)
185 {
186 fprintf (stderr, "emacs: failure obtaining new shared memory segment.\n");
187 shmdt ((char *)PURE_SEG_BITS);
188 shmctl (shmid, IPC_RMID, 0);
189 exit (1);
190 }
191
192 /* Load the proper data into it. */
193 if (read (fd, PURE_SEG_BITS, PURESIZE) != PURESIZE)
194 {
195 fprintf (stderr, "emacs: failure loading shared memory data.\n");
196 shmdt ((char *)PURE_SEG_BITS);
197 shmctl (shmid, IPC_RMID, 0);
198 exit (1);
199 }
200
201 /* Detach from the segment and bring it back readonly. */
202 shmdt ((char *)PURE_SEG_BITS);
203
204 shmctl (shmid, IPC_STAT, &buf);
205 buf.shm_perm.mode = OLD_SHMGET_FLAGS;
206 shmctl (shmid, IPC_SET, &buf);
207
208 newaddr = shmat (shmid, (char *)PURE_SEG_BITS, OLD_SHMAT_FLAGS);
209 if (newaddr == -1)
210 {
211 fprintf (stderr, "emacs: failure reattaching shared memory segment.\n");
212 shmctl (shmid, IPC_RMID, 0);
213 exit (1);
214 }
215 }
216
217 close (fd);
218}
219
220/* Dump the appropriate parts of memory into a file named NEW
221 from which the shared segment can be initialized. */
222
223void
224map_out_data (new)
225 char *new;
226{
227 struct data_header dh; /* saved data header */
228 int fd; /* saved data file descriptor */
229 int length; /* dumped data length; */
230
231
232 /* Create "saved data" file header */
233 dh.start = &_data;
234 dh.end = &_end;
235 dh.sbrk1 = original_sbrk;
236 dh.sbrk2 = sbrk (0);
237 dh.puresize = PURESIZE;
238
239 /* Create new "saved data" dump file */
240 unlink (new);
241 fd = open (new, NEW_OPEN_FLAGS, 0666);
242 if (fd < 0)
243 report_file_error ("Opening dump file", Fcons (build_string (new), Qnil));
244
245 /* Write saved header and data */
246 length = sizeof (dh);
247 if (write (fd, (char *)&dh, length) != length)
248 report_file_error ("Writing dump file header",
249 Fcons (build_string (new), Qnil));
250 length = dh.end - dh.start;
251 if (write (fd, dh.start, length) != length)
252 report_file_error ("Writing low core in dump file",
253 Fcons (build_string (new), Qnil));
254 length = dh.sbrk2 - dh.sbrk1;
255 if (write (fd, dh.sbrk1, length) != length)
256 report_file_error ("Writing heap in dump file",
257 Fcons (build_string (new), Qnil));
258 length = PURESIZE;
259 if (write (fd, PURE_SEG_BITS, length) != length)
260 report_file_error ("Writing pure data in dump file",
261 Fcons (build_string (new), Qnil));
262 close (fd);
263}