110
|
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
|
|
5 This file is part of GNU Emacs.
|
|
6
|
|
7 GNU Emacs is free software; you can redistribute it and/or modify
|
|
8 it under the terms of the GNU General Public License as published by
|
|
9 the Free Software Foundation; either version 1, or (at your option)
|
|
10 any later version.
|
|
11
|
|
12 GNU Emacs is distributed in the hope that it will be useful,
|
|
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15 GNU General Public License for more details.
|
|
16
|
|
17 You should have received a copy of the GNU General Public License
|
|
18 along with GNU Emacs; see the file COPYING. If not, write to
|
|
19 the 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
|
|
39 struct 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
|
|
59 extern char _data; /* start of data addr */
|
|
60 extern char _end; /* end of all data + 1 addr */
|
|
61 static char *original_sbrk; /* sbrk when dump first run */
|
|
62
|
|
63 void
|
|
64 map_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
|
|
223 void
|
|
224 map_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 }
|