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