# HG changeset patch # User Jim Blandy # Date 656709341 0 # Node ID 2968112113f95c885983b9e608f8b7ee4830fa95 # Parent d649664df7e0b253aa2ea5ee6649a884ca56abb0 Initial revision diff -r d649664df7e0 -r 2968112113f9 src/unexaix.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/unexaix.c Tue Oct 23 19:15:41 1990 +0000 @@ -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 +#include +#include +#include +#include +#include +#include +#include /* 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); +}