summaryrefslogtreecommitdiff
path: root/src/unexaix.c
diff options
context:
space:
mode:
authorJim Blandy <jimb@redhat.com>1990-10-23 19:15:41 +0000
committerJim Blandy <jimb@redhat.com>1990-10-23 19:15:41 +0000
commita2ee4ec2287717ecbf482dcc8dd920498bc62e54 (patch)
tree973a6ea4a9b0f0ecc62312db4cf6769643ff2956 /src/unexaix.c
parent9471caf8697590e91e9daf6935c2a5ec6e860b01 (diff)
downloademacs-a2ee4ec2287717ecbf482dcc8dd920498bc62e54.tar.gz
Initial revision
Diffstat (limited to 'src/unexaix.c')
-rw-r--r--src/unexaix.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/src/unexaix.c b/src/unexaix.c
new file mode 100644
index 00000000000..2957f966902
--- /dev/null
+++ b/src/unexaix.c
@@ -0,0 +1,263 @@
+/* Dumping and loading data areas, for Emacs under AIX.
+ (It may also work on other kinds of system V.)
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This is based on a public domain program written by IBM. */
+
+/*************** SYSTEM DEFINES *********************************/
+
+#include "config.h"
+#include "paths.h"
+#include <sys/types.h>
+#include <sys/files.h>
+#include <fcntl.h>
+#include <sys/mode.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <malloc.h>
+#include <stdio.h> /* MWW */
+#include "lisp.h"
+
+/*************** LOCAL DEFINES **********************************/
+
+struct data_header /* saved data header */
+{
+ char *start; /* dump _data addr */
+ char *end; /* dump _end addr */
+ char *sbrk1; /* dump original sbrk addr */
+ char *sbrk2; /* dump final sbrk addr */
+ int puresize; /* size of pure data dumped */
+};
+
+#define EMACSSHMKEY "EMACSSHMKEY"
+#define EMACS_DATA_FILE "EMACS-DATA"
+#define NEW_SHMGET_FLAGS (IPC_CREAT | S_IWUSR | S_IRUSR \
+ | S_IWGRP | S_IRGRP | S_IWOTH | S_IROTH)
+#define OLD_SHMAT_FLAGS SHM_RDONLY
+#define OLD_SHMGET_FLAGS (S_IRUSR | S_IRGRP | S_IROTH)
+#define OLD_OPEN_FLAGS O_RDONLY
+#define NEW_OPEN_FLAGS (O_RDWR | O_CREAT | O_TRUNC)
+
+/*************** EXTERNAL / GLOBAL DATA AREA ********************/
+
+extern char _data; /* start of data addr */
+extern char _end; /* end of all data + 1 addr */
+static char *original_sbrk; /* sbrk when dump first run */
+
+void
+map_in_data (use_dumped_data)
+ int use_dumped_data;
+{
+ int bufsize; /* malloc buffer size */
+ struct data_header dh; /* saved data header */
+ int fd; /* saved data file descriptor */
+ char *finaladdr; /* last addr in bucket */
+ char *ipckey = getenv (EMACSSHMKEY); /* env ipc key string */
+ int length; /* dumped data lengths */
+ char *newaddr; /* new malloc buffer addr */
+ int numblks; /* number of remaining mallocs */
+ int shmid; /* shared memory id */
+ key_t shmkey; /* shared memory key */
+ /* Note that using malloc here may not be safe. */
+ char name[sizeof (PATH_EXEC) + sizeof (EMACS_DATA_FILE) + 2];
+
+ /* Consume remaining malloc space without increasing */
+ /* the end of data space */
+ original_sbrk = sbrk (0);
+ for (bufsize = 16; bufsize < getpagesize (); bufsize *= 2)
+ {
+ while ((newaddr = (char *)malloc (bufsize - 8)) < original_sbrk)
+ ;
+ for (numblks = (getpagesize () / bufsize) - 1; numblks > 0; numblks--)
+ malloc (bufsize - 8);
+ finaladdr = sbrk (0);
+ }
+ original_sbrk = sbrk (0);
+
+ /* If we don't want the dumped data, get an unshared segment. */
+ if (!use_dumped_data)
+ {
+ shmid = shmget (IPC_PRIVATE, PURESIZE, NEW_SHMGET_FLAGS);
+ if (shmid == -1
+ || shmat (shmid, (char *)PURE_SEG_BITS, 0) == -1)
+ {
+ fprintf (stderr, "emacs: failure obtaining new unshared memory segment.\n");
+ exit (1);
+ }
+ return;
+ }
+
+ /* Compute the file name with the dumped data. */
+ strcpy (name, PATH_EXEC);
+ strcat (name, "/");
+ strcat (name, EMACS_DATA_FILE);
+
+ /* Open the file and make sure the addresses have not changed. */
+ fd = open (name, OLD_OPEN_FLAGS, 0);
+ if (fd < 0)
+ {
+ fprintf (stderr, "emacs: failure opening `%s'\n", name);
+ exit (1);
+ }
+ if (read (fd, (char *)&dh, sizeof (dh)) != sizeof (dh)
+ || dh.start != &_data
+ || dh.end != &_end
+ || dh.sbrk1 != original_sbrk
+ || dh.puresize != PURESIZE)
+ {
+ fprintf (stderr, "emacs: header mismatch in `%s'\n", name);
+ exit (1);
+ }
+
+ /* Load in the unshared contents. */
+ if (!(length = dh.end - dh.start)
+ || read (fd, (char *)&_data, length) != length
+ || !(length = dh.sbrk2 - dh.sbrk1)
+ || brk (dh.sbrk2) == -1
+ || read (fd, dh.sbrk1, length) != length)
+ {
+ fprintf (stderr, "emacs: failure loading unshared data.\n");
+ exit (1);
+ }
+
+ /* Determine ipc key from environment or default */
+ if (ipckey && *ipckey)
+ shmkey = atoi (ipckey);
+ else
+ shmkey = SHMKEY;
+
+ /* Attach to "pure data" shared memory segment */
+ if ((shmid = shmget (shmkey, 0, 0)) == -1
+ || (newaddr = shmat (shmid, (char *)PURE_SEG_BITS, OLD_SHMAT_FLAGS)) == -1)
+ {
+ /* We were unable to open an existing segment. Make a new one. */
+ struct shmid_ds buf;
+
+ /* First get rid of the one we tried to get. */
+ shmdt ((char *)PURE_SEG_BITS);
+ shmctl (shmid, IPC_RMID, 0);
+
+ /* If we could not write the data file,
+ don't make a shared segment that we could write.
+ Make an unshared segment instead. */
+ if (access (name, W_OK) == 0)
+ {
+ shmid = shmget (IPC_PRIVATE, PURESIZE, NEW_SHMGET_FLAGS);
+ if (shmid == -1
+ || shmat (shmid, (char *)PURE_SEG_BITS, 0) == -1)
+ {
+ fprintf (stderr, "emacs: failure obtaining new unshared memory segment.\n");
+ exit (1);
+ }
+
+ /* Load the proper data into it. */
+ if (read (fd, PURE_SEG_BITS, PURESIZE) != PURESIZE)
+ {
+ fprintf (stderr, "emacs: failure loading shared memory data.\n");
+ shmdt ((char *)PURE_SEG_BITS);
+ shmctl (shmid, IPC_RMID, 0);
+ exit (1);
+ }
+
+ close (fd);
+ return;
+ }
+
+ /* Allocate the new shared segment and arrange to write it. */
+ if ((shmid = shmget (shmkey, PURESIZE, NEW_SHMGET_FLAGS)) == -1
+ || shmat (shmid, (char *)PURE_SEG_BITS, 0) == -1)
+ {
+ fprintf (stderr, "emacs: failure obtaining new shared memory segment.\n");
+ shmdt ((char *)PURE_SEG_BITS);
+ shmctl (shmid, IPC_RMID, 0);
+ exit (1);
+ }
+
+ /* Load the proper data into it. */
+ if (read (fd, PURE_SEG_BITS, PURESIZE) != PURESIZE)
+ {
+ fprintf (stderr, "emacs: failure loading shared memory data.\n");
+ shmdt ((char *)PURE_SEG_BITS);
+ shmctl (shmid, IPC_RMID, 0);
+ exit (1);
+ }
+
+ /* Detach from the segment and bring it back readonly. */
+ shmdt ((char *)PURE_SEG_BITS);
+
+ shmctl (shmid, IPC_STAT, &buf);
+ buf.shm_perm.mode = OLD_SHMGET_FLAGS;
+ shmctl (shmid, IPC_SET, &buf);
+
+ newaddr = shmat (shmid, (char *)PURE_SEG_BITS, OLD_SHMAT_FLAGS);
+ if (newaddr == -1)
+ {
+ fprintf (stderr, "emacs: failure reattaching shared memory segment.\n");
+ shmctl (shmid, IPC_RMID, 0);
+ exit (1);
+ }
+ }
+
+ close (fd);
+}
+
+/* Dump the appropriate parts of memory into a file named NEW
+ from which the shared segment can be initialized. */
+
+void
+map_out_data (new)
+ char *new;
+{
+ struct data_header dh; /* saved data header */
+ int fd; /* saved data file descriptor */
+ int length; /* dumped data length; */
+
+
+ /* Create "saved data" file header */
+ dh.start = &_data;
+ dh.end = &_end;
+ dh.sbrk1 = original_sbrk;
+ dh.sbrk2 = sbrk (0);
+ dh.puresize = PURESIZE;
+
+ /* Create new "saved data" dump file */
+ unlink (new);
+ fd = open (new, NEW_OPEN_FLAGS, 0666);
+ if (fd < 0)
+ report_file_error ("Opening dump file", Fcons (build_string (new), Qnil));
+
+ /* Write saved header and data */
+ length = sizeof (dh);
+ if (write (fd, (char *)&dh, length) != length)
+ report_file_error ("Writing dump file header",
+ Fcons (build_string (new), Qnil));
+ length = dh.end - dh.start;
+ if (write (fd, dh.start, length) != length)
+ report_file_error ("Writing low core in dump file",
+ Fcons (build_string (new), Qnil));
+ length = dh.sbrk2 - dh.sbrk1;
+ if (write (fd, dh.sbrk1, length) != length)
+ report_file_error ("Writing heap in dump file",
+ Fcons (build_string (new), Qnil));
+ length = PURESIZE;
+ if (write (fd, PURE_SEG_BITS, length) != length)
+ report_file_error ("Writing pure data in dump file",
+ Fcons (build_string (new), Qnil));
+ close (fd);
+}