ast@cs.vu.nl (Andy Tanenbaum) (07/01/87)
: This is a shar archive. Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin
echo Extracting \f\o\r\k\e\x\i\t\.\c
sed 's/^X//' > \f\o\r\k\e\x\i\t\.\c << '+ END-OF-FILE '\f\o\r\k\e\x\i\t\.\c
X/* This file deals with creating processes (via FORK) and deleting them (via
X * EXIT/WAIT). When a process forks, a new slot in the 'mproc' table is
X * allocated for it, and a copy of the parent's core image is made for the
X * child. Then the kernel and file system are informed. A process is removed
X * from the 'mproc' table when two events have occurred: (1) it has exited or
X * been killed by a signal, and (2) the parent has done a WAIT. If the process
X * exits first, it continues to occupy a slot until the parent does a WAIT.
X *
X * The entry points into this file are:
X * do_fork: perform the FORK system call
X * do_mm_exit: perform the EXIT system call (by calling mm_exit())
X * mm_exit: actually do the exiting
X * do_wait: perform the WAIT system call
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/callnr.h"
X#include "../h/error.h"
X#include "const.h"
X#include "glo.h"
X#include "mproc.h"
X#include "param.h"
X
X#define LAST_FEW 2 /* last few slots reserved for superuser */
X
XPRIVATE next_pid = INIT_PROC_NR+1; /* next pid to be assigned */
XPRIVATE process_group = 1; /* next process grp to be assigned */
X
X/* Some C compilers require static declarations to precede their first use. */
X
X/*===========================================================================*
X * do_fork *
X *===========================================================================*/
XPUBLIC int do_fork()
X{
X/* The process pointed to by 'mp' has forked. Create a child process. */
X
X register struct mproc *rmp; /* pointer to parent */
X register struct mproc *rmc; /* pointer to child */
X int i, child_nr, t;
X char *sptr, *dptr;
X long prog_bytes;
X phys_clicks prog_clicks, child_base;
X long parent_abs, child_abs;
X extern phys_clicks alloc_mem();
X
X /* If tables might fill up during FORK, don't even start since recovery half
X * way through is such a nuisance.
X */
X
X rmp = mp;
X if (procs_in_use == NR_PROCS) return(EAGAIN);
X if (procs_in_use >= NR_PROCS - LAST_FEW && rmp->mp_effuid != 0)return(EAGAIN);
X
X /* Determine how much memory to allocate. */
X prog_clicks = (phys_clicks) rmp->mp_seg[T].mem_len + rmp->mp_seg[D].mem_len +
X rmp->mp_seg[S].mem_len;
X#ifdef i8088
X prog_clicks += rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_len; /* gap too */
X#endif
X prog_bytes = (long) prog_clicks << CLICK_SHIFT;
X if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(EAGAIN);
X
X /* Create a copy of the parent's core image for the child. */
X child_abs = (long) child_base << CLICK_SHIFT;
X parent_abs = (long) rmp->mp_seg[T].mem_phys << CLICK_SHIFT;
X i = mem_copy(ABS, 0, parent_abs, ABS, 0, child_abs, prog_bytes);
X if ( i < 0) panic("do_fork can't copy", i);
X
X /* Find a slot in 'mproc' for the child process. A slot must exist. */
X for (rmc = &mproc[0]; rmc < &mproc[NR_PROCS]; rmc++)
X if ( (rmc->mp_flags & IN_USE) == 0) break;
X
X /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
X child_nr = rmc - mproc; /* slot number of the child */
X procs_in_use++;
X sptr = (char *) rmp; /* pointer to parent's 'mproc' slot */
X dptr = (char *) rmc; /* pointer to child's 'mproc' slot */
X i = sizeof(struct mproc); /* number of bytes in a proc slot. */
X while (i--) *dptr++ = *sptr++;/* copy from parent slot to child's */
X
X /* Set process group. */
X if (who == INIT_PROC_NR) rmc->mp_procgrp = process_group++;
X
X rmc->mp_parent = who; /* record child's parent */
X rmc->mp_seg[T].mem_phys = child_base;
X rmc->mp_seg[D].mem_phys = child_base + rmc->mp_seg[T].mem_len;
X rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys +
X (rmp->mp_seg[S].mem_phys - rmp->mp_seg[D].mem_phys);
X rmc->mp_exitstatus = 0;
X rmc->mp_sigstatus = 0;
X
X /* Find a free pid for the child and put it in the table. */
X do {
X t = 0; /* 't' = 0 means pid still free */
X next_pid = (next_pid < 30000 ? next_pid + 1 : INIT_PROC_NR + 1);
X for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++)
X if (rmp->mp_pid == next_pid) {
X t = 1;
X break;
X }
X rmc->mp_pid = next_pid; /* assign pid to child */
X } while (t);
X
X /* Tell kernel and file system about the (now successful) FORK. */
X sys_fork(who, child_nr, rmc->mp_pid);
X tell_fs(FORK, who, child_nr, 0);
X
X /* Report child's memory map to kernel. */
X sys_newmap(child_nr, rmc->mp_seg);
X
X /* Reply to child to wake it up. */
X reply(child_nr, 0, 0, NIL_PTR);
X return(next_pid); /* child's pid */
X}
X
X
X/*===========================================================================*
X * do_mm_exit *
X *===========================================================================*/
XPUBLIC int do_mm_exit()
X{
X/* Perform the exit(status) system call. The real work is done by mm_exit(),
X * which is also called when a process is killed by a signal.
X */
X
X mm_exit(mp, status);
X dont_reply = TRUE; /* don't reply to newly terminated process */
X return(OK); /* pro forma return code */
X}
X
X
X/*===========================================================================*
X * mm_exit *
X *===========================================================================*/
XPUBLIC mm_exit(rmp, exit_status)
Xregister struct mproc *rmp; /* pointer to the process to be terminated */
Xint exit_status; /* the process' exit status (for parent) */
X{
X/* A process is done. If parent is waiting for it, clean it up, else hang. */
X
X /* How to terminate a process is determined by whether or not the
X * parent process has already done a WAIT. Test to see if it has.
X */
X rmp->mp_exitstatus = (char) exit_status; /* store status in 'mproc' */
X
X if (mproc[rmp->mp_parent].mp_flags & WAITING)
X cleanup(rmp); /* release parent and tell everybody */
X else
X rmp->mp_flags |= HANGING; /* Parent not waiting. Suspend proc */
X
X /* If the exited process has a timer pending, kill it. */
X if (rmp->mp_flags & ALARM_ON) set_alarm(rmp - mproc, (unsigned) 0);
X
X /* Tell the kernel and FS that the process is no longer runnable. */
X sys_xit(rmp->mp_parent, rmp - mproc);
X tell_fs(EXIT, rmp - mproc, 0, 0); /* file system can free the proc slot */
X}
X
X
X/*===========================================================================*
X * do_wait *
X *===========================================================================*/
XPUBLIC int do_wait()
X{
X/* A process wants to wait for a child to terminate. If one is already waiting,
X * go clean it up and let this WAIT call terminate. Otherwise, really wait.
X */
X
X register struct mproc *rp;
X register int children;
X
X /* A process calling WAIT never gets a reply in the usual way via the
X * reply() in the main loop. If a child has already exited, the routine
X * cleanup() sends the reply to awaken the caller.
X */
X
X /* Is there a child waiting to be collected? */
X children = 0;
X for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
X if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who) {
X children++;
X if (rp->mp_flags & HANGING) {
X cleanup(rp); /* a child has already exited */
X dont_reply = TRUE;
X return(OK);
X }
X }
X }
X
X /* No child has exited. Wait for one, unless none exists. */
X if (children > 0) { /* does this process have any children? */
X mp->mp_flags |= WAITING;
X dont_reply = TRUE;
X return(OK); /* yes - wait for one to exit */
X } else
X return(ECHILD); /* no - parent has no children */
X}
X
X
X/*===========================================================================*
X * cleanup *
X *===========================================================================*/
XPRIVATE cleanup(child)
Xregister struct mproc *child; /* tells which process is exiting */
X{
X/* Clean up the remains of a process. This routine is only called if two
X * conditions are satisfied:
X * 1. The process has done an EXIT or has been killed by a signal.
X * 2. The process' parent has done a WAIT.
X *
X * It releases the memory, if that has not been done yet. Whether it has or
X * has not been done depends on the order of the EXIT and WAIT calls.
X */
X
X register struct mproc *parent, *rp;
X int init_waiting, child_nr;
X unsigned int r;
X phys_clicks s;
X
X child_nr = child - mproc;
X parent = &mproc[child->mp_parent];
X
X /* Wakeup the parent. */
X r = child->mp_sigstatus & 0377;
X r = r | (child->mp_exitstatus << 8);
X reply(child->mp_parent, child->mp_pid, r, NIL_PTR);
X
X /* Release the memory occupied by the child. */
X s = (phys_clicks) child->mp_seg[S].mem_vir + child->mp_seg[S].mem_len;
X if (child->mp_flags & SEPARATE) s += child->mp_seg[T].mem_len;
X free_mem(child->mp_seg[T].mem_phys, s); /* free the memory */
X
X /* Update flags. */
X child->mp_flags &= ~HANGING; /* turn off HANGING bit */
X child->mp_flags &= ~PAUSED; /* turn off PAUSED bit */
X parent->mp_flags &= ~WAITING; /* parent is no longer waiting */
X child->mp_flags &= ~IN_USE; /* release the table slot */
X procs_in_use--;
X
X /* If exiting process has children, disinherit them. INIT is new parent. */
X init_waiting = (mproc[INIT_PROC_NR].mp_flags & WAITING ? 1 : 0);
X for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
X if (rp->mp_parent == child_nr) {
X /* 'rp' points to a child to be disinherited. */
X rp->mp_parent = INIT_PROC_NR; /* init takes over */
X if (init_waiting && (rp->mp_flags & HANGING) ) {
X /* Init was waiting. */
X cleanup(rp); /* recursive call */
X init_waiting = 0;
X }
X }
X }
X}
+ END-OF-FILE forkexit.c
chmod 'u=rw,g=r,o=r' \f\o\r\k\e\x\i\t\.\c
set `sum \f\o\r\k\e\x\i\t\.\c`
sum=$1
case $sum in
48964) :;;
*) echo 'Bad sum in '\f\o\r\k\e\x\i\t\.\c >&2
esac
echo Extracting \s\i\g\n\a\l\.\c
sed 's/^X//' > \s\i\g\n\a\l\.\c << '+ END-OF-FILE '\s\i\g\n\a\l\.\c
X/* This file handles signals, which are asynchronous events and are generally
X * a messy and unpleasant business. Signals can be generated by the KILL
X * system call, or from the keyboard (SIGINT) or from the clock (SIGALRM).
X * In all cases control eventually passes to check_sig() to see which processes
X * can be signalled. The actual signalling is done by sig_proc().
X *
X * The entry points into this file are:
X * do_signal: perform the SIGNAL system call
X * do_kill: perform the KILL system call
X * do_ksig: accept a signal originating in the kernel (e.g., SIGINT)
X * sig_proc: interrupt or terminate a signalled process
X * do_alarm: perform the ALARM system call by calling set_alarm()
X * set_alarm: tell the clock task to start or stop a timer
X * do_pause: perform the PAUSE system call
X * unpause: check to see if process is suspended on anything
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/callnr.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "../h/signal.h"
X#include "../h/stat.h"
X#include "const.h"
X#include "glo.h"
X#include "mproc.h"
X#include "param.h"
X
X#define DUMP_SIZE 256 /* buffer size for core dumps */
X#define CORE_MODE 0777 /* mode to use on core image files */
X#define DUMPED 0200 /* bit set in status when core dumped */
X
XPRIVATE message m_sig;
X
X/*===========================================================================*
X * do_signal *
X *===========================================================================*/
XPUBLIC int do_signal()
X{
X/* Perform the signal(sig, func) call by setting bits to indicate that a signal
X * is to be caught or ignored.
X */
X
X int mask;
X
X if (sig < 1 || sig > NR_SIGS) return(EINVAL);
X if (sig == SIGKILL) return(OK); /* SIGKILL may not ignored/caught */
X mask = 1 << (sig - 1); /* singleton set with 'sig' bit on */
X
X /* All this func does is set the bit maps for subsequent sig processing. */
X if (func == SIG_IGN) {
X mp->mp_ignore |= mask;
X mp->mp_catch &= ~mask;
X } else if (func == SIG_DFL) {
X mp->mp_ignore &= ~mask;
X mp->mp_catch &= ~mask;
X } else {
X mp->mp_ignore &= ~mask;
X mp->mp_catch |= mask;
X mp->mp_func = func;
X }
X return(OK);
X}
X
X
X/*===========================================================================*
X * do_kill *
X *===========================================================================*/
XPUBLIC int do_kill()
X{
X/* Perform the kill(pid, kill_sig) system call. */
X
X return check_sig(pid, kill_sig, mp->mp_effuid);
X}
X
X
X/*===========================================================================*
X * do_ksig *
X *===========================================================================*/
XPUBLIC int do_ksig()
X{
X/* Certain signals, such as segmentation violations and DEL, originate in the
X * kernel. When the kernel detects such signals, it sets bits in a bit map.
X * As soon is MM is awaiting new work, the kernel sends MM a message containing
X * the process slot and bit map. That message comes here. The File System
X * also uses this mechanism to signal writing on broken pipes (SIGPIPE).
X */
X
X register struct mproc *rmp;
X int i, proc_id, proc_nr, id;
X unshort sig_map; /* bits 0 - 15 for sigs 1 - 16 */
X
X /* Only kernel and FS may make this call. */
X if (who != HARDWARE && who != FS_PROC_NR) return(EPERM);
X
X proc_nr = mm_in.PROC1;
X rmp = &mproc[proc_nr];
X if ( (rmp->mp_flags & IN_USE) == 0 || (rmp->mp_flags & HANGING) ) return(OK);
X proc_id = rmp->mp_pid;
X sig_map = (unshort) mm_in.SIG_MAP;
X mp = &mproc[0]; /* pretend kernel signals are from MM */
X mp->mp_procgrp = rmp->mp_procgrp; /* get process group right */
X
X /* Stack faults are passed from kernel to MM as pseudo-signal 16. */
X if (sig_map == 1 << (STACK_FAULT - 1)) {
X stack_fault(proc_nr);
X return(OK);
X }
X
X /* Check each bit in turn to see if a signal is to be sent. Unlike
X * kill(), the kernel may collect several unrelated signals for a process
X * and pass them to MM in one blow. Thus loop on the bit map. For SIGINT
X * and SIGQUIT, use proc_id 0, since multiple processes may have to signalled.
X */
X for (i = 0; i < NR_SIGS; i++) {
X id = (i+1 == SIGINT || i+1 == SIGQUIT ? 0 : proc_id);
X if ( (sig_map >> i) & 1) check_sig(id, i + 1, SUPER_USER);
X }
X
X dont_reply = TRUE; /* don't reply to the kernel */
X return(OK);
X}
X
X
X/*===========================================================================*
X * check_sig *
X *===========================================================================*/
XPRIVATE int check_sig(proc_id, sig_nr, send_uid)
Xint proc_id; /* pid of process to signal, or 0 or -1 */
Xint sig_nr; /* which signal to send (1-16) */
Xuid send_uid; /* identity of process sending the signal */
X{
X/* Check to see if it is possible to send a signal. The signal may have to be
X * sent to a group of processes. This routine is invoked by the KILL system
X * call, and also when the kernel catches a DEL or other signal. SIGALRM too.
X */
X
X register struct mproc *rmp;
X int count, send_sig;
X unshort mask;
X extern unshort core_bits;
X
X if (sig_nr < 1 || sig_nr > NR_SIGS) return(EINVAL);
X count = 0; /* count # of signals sent */
X mask = 1 << (sig_nr - 1);
X
X /* Search the proc table for processes to signal. Several tests are made:
X * - if proc's uid != sender's, and sender is not superuser, don't signal
X * - if specific process requested (i.e., 'procpid' > 0, check for match
X * - if a process has already exited, it can't receive signals
X * - if 'proc_id' is 0 signal everyone in same process group except caller
X */
X for (rmp = &mproc[INIT_PROC_NR + 1]; rmp < &mproc[NR_PROCS]; rmp++ ) {
X if ( (rmp->mp_flags & IN_USE) == 0) continue;
X send_sig = TRUE; /* if it's FALSE at end of loop, don't signal */
X if (send_uid != rmp->mp_effuid && send_uid != SUPER_USER)send_sig=FALSE;
X if (proc_id > 0 && proc_id != rmp->mp_pid) send_sig = FALSE;
X if (rmp->mp_flags & HANGING) send_sig = FALSE; /*don't wake the dead*/
X if (proc_id == 0 && mp->mp_procgrp != rmp->mp_procgrp) send_sig = FALSE;
X if (send_uid == SUPER_USER && proc_id == -1) send_sig = TRUE;
X
X /* SIGALARM is a little special. When a process exits, a clock signal
X * can arrive just as the timer is being turned off. Also, turn off
X * ALARM_ON bit when timer goes off to keep it accurate.
X */
X if (sig_nr == SIGALRM) {
X if ( (rmp->mp_flags & ALARM_ON) == 0) continue;
X rmp->mp_flags &= ~ALARM_ON;
X }
X
X if (send_sig == FALSE || rmp->mp_ignore & mask) continue;
X count++;
X
X /* Send the signal or kill the process, possibly with core dump. */
X sig_proc(rmp, sig_nr);
X
X /* If process is hanging on PAUSE, WAIT, tty, pipe, etc. release it. */
X unpause(rmp - mproc); /* check to see if process is paused */
X if (proc_id > 0) break; /* only one process being signalled */
X }
X
X /* If the calling process has killed itself, don't reply. */
X if ((mp->mp_flags & IN_USE) == 0 || (mp->mp_flags & HANGING))dont_reply =TRUE;
X return(count > 0 ? OK : ESRCH);
X}
X
X
X/*===========================================================================*
X * sig_proc *
X *===========================================================================*/
XPUBLIC sig_proc(rmp, sig_nr)
Xregister struct mproc *rmp; /* pointer to the process to be signalled */
Xint sig_nr; /* signal to send to process (1-16) */
X{
X/* Send a signal to a process. Check to see if the signal is to be caught.
X * If so, the pc, psw, and signal number are to be pushed onto the process'
X * stack. If the stack cannot grow or the signal is not to be caught, kill
X * the process.
X */
X
X unshort mask;
X int core_file;
X vir_bytes new_sp;
X extern unshort core_bits;
X
X if ( (rmp->mp_flags & IN_USE) == 0) return; /* if already dead forget it */
X mask = 1 << (sig_nr - 1);
X if (rmp->mp_catch & mask) {
X /* Signal should be caught. */
X rmp->mp_catch &= ~mask; /* disable further signals */
X sys_getsp(rmp - mproc, &new_sp);
X new_sp -= SIG_PUSH_BYTES;
X if (adjust(rmp, rmp->mp_seg[D].mem_len, new_sp) == OK) {
X sys_sig(rmp - mproc, sig_nr, rmp->mp_func);
X return; /* successful signal */
X }
X }
X
X /* Signal should not or cannot be caught. Take default action. */
X core_file = ( core_bits >> (sig_nr - 1 )) & 1;
X rmp->mp_sigstatus = (char) sig_nr;
X if (core_file) dump_core(rmp); /* dump core */
X mm_exit(rmp, 0); /* terminate process */
X}
X
X
X/*===========================================================================*
X * do_alarm *
X *===========================================================================*/
XPUBLIC int do_alarm()
X{
X/* Perform the alarm(seconds) system call. */
X
X register int r;
X unsigned sec;
X
X sec = (unsigned) seconds;
X r = set_alarm(who, sec);
X return(r);
X}
X
X
X/*===========================================================================*
X * set_alarm *
X *===========================================================================*/
XPUBLIC int set_alarm(proc_nr, sec)
Xint proc_nr; /* process that wants the alarm */
Xunsigned sec; /* how many seconds delay before the signal */
X{
X/* This routine is used by do_alarm() to set the alarm timer. It is also
X * to turn the timer off when a process exits with the timer still on.
X */
X
X int remaining;
X
X m_sig.m_type = SET_ALARM;
X m_sig.CLOCK_PROC_NR = proc_nr;
X m_sig.DELTA_TICKS = HZ * sec;
X if (sec != 0)
X mproc[proc_nr].mp_flags |= ALARM_ON; /* turn ALARM_ON bit on */
X else
X mproc[proc_nr].mp_flags &= ~ALARM_ON; /* turn ALARM_ON bit off */
X
X /* Tell the clock task to provide a signal message when the time comes. */
X if (sendrec(CLOCK, &m_sig) != OK) panic("alarm er", NO_NUM);
X remaining = (int) m_sig.SECONDS_LEFT;
X return(remaining);
X}
X
X
X/*===========================================================================*
X * do_pause *
X *===========================================================================*/
XPUBLIC int do_pause()
X{
X/* Perform the pause() system call. */
X
X mp->mp_flags |= PAUSED; /* turn on PAUSE bit */
X dont_reply = TRUE;
X return(OK);
X}
X
X
X/*===========================================================================*
X * unpause *
X *===========================================================================*/
XPUBLIC unpause(pro)
Xint pro; /* which process number */
X{
X/* A signal is to be sent to a process. It that process is hanging on a
X * system call, the system call must be terminated with EINTR. Possible
X * calls are PAUSE, WAIT, READ and WRITE, the latter two for pipes and ttys.
X * First check if the process is hanging on PAUSE or WAIT. If not, tell FS,
X * so it can check for READs and WRITEs from pipes, ttys and the like.
X */
X
X register struct mproc *rmp;
X
X rmp = &mproc[pro];
X
X /* Check to see if process is hanging on PAUSE call. */
X if ( (rmp->mp_flags & PAUSED) && (rmp->mp_flags & HANGING) == 0) {
X rmp->mp_flags &= ~PAUSED; /* turn off PAUSED bit */
X reply(pro, EINTR, 0, NIL_PTR);
X return;
X }
X
X /* Check to see if process is hanging on a WAIT call. */
X if ( (rmp->mp_flags & WAITING) && (rmp->mp_flags & HANGING) == 0) {
X rmp->mp_flags &= ~ WAITING; /* turn off WAITING bit */
X reply(pro, EINTR, 0, NIL_PTR);
X return;
X }
X
X /* Process is not hanging on an MM call. Ask FS to take a look. */
X tell_fs(UNPAUSE, pro, 0, 0);
X
X return;
X}
X
X
X/*===========================================================================*
X * dump_core *
X *===========================================================================*/
XPRIVATE dump_core(rmp)
Xregister struct mproc *rmp; /* whose core is to be dumped */
X{
X/* Make a core dump on the file "core", if possible. */
X
X struct stat s_buf, d_buf;
X char buf[DUMP_SIZE];
X int i, r, s, er1, er2, slot;
X vir_bytes v_buf;
X long len, a, c, ct, dest;
X struct mproc *xmp;
X extern char core_name[];
X
X
X /* Change to working directory of dumpee. */
X slot = rmp - mproc;
X tell_fs(CHDIR, slot, 0, 0);
X
X /* Can core file be written? */
X if (rmp->mp_realuid != rmp->mp_effuid) {
X tell_fs(CHDIR, 0, 1, 0); /* go back to MM's directory */
X return;
X }
X xmp = mp; /* allowed() looks at 'mp' */
X mp = rmp;
X r = allowed(core_name, &s_buf, W_BIT); /* is core_file writable */
X s = allowed(".", &d_buf, W_BIT); /* is directory writable? */
X mp = xmp;
X if (r >= 0) close(r);
X if (s >= 0) close(s);
X if (rmp->mp_effuid == SUPER_USER) r = 0; /* su can always dump core */
X
X if (s >= 0 && (r >= 0 || r == ENOENT)) {
X /* Either file is writable or it doesn't exist & dir is writable */
X r = creat(core_name, CORE_MODE);
X tell_fs(CHDIR, 0, 1, 0); /* go back to MM's own dir */
X if (r < 0) return;
X rmp->mp_sigstatus |= DUMPED;
X
X /* First loop through segments and write each length on core file. */
X for (i = 0; i < NR_SEGS; i++) {
X len = rmp->mp_seg[i].mem_len << CLICK_SHIFT;
X if (write(r, (char *) &len, sizeof len) < 0) {
X close(r);
X return;
X }
X }
X
X /* Now loop through segments and write the segments themselves out. */
X v_buf = (vir_bytes) buf;
X dest = (long) v_buf;
X for (i = 0; i < NR_SEGS; i++) {
X a = (phys_bytes) rmp->mp_seg[i].mem_vir << CLICK_SHIFT;
X c = (phys_bytes) rmp->mp_seg[i].mem_len << CLICK_SHIFT;
X
X /* Loop through a segment, dumping it. */
X while (c > 0) {
X ct = MIN(c, DUMP_SIZE);
X er1 = mem_copy(slot, i, a, MM_PROC_NR, D, dest, ct);
X er2 = write(r, buf, (int) ct);
X if (er1 < 0 || er2 < 0) {
X close(r);
X return;
X }
X a += ct;
X c -= ct;
X }
X }
X } else {
X tell_fs(CHDIR, 0, 1, 0); /* go back to MM's own dir */
X close(r);
X return;
X }
X
X close(r);
X}
+ END-OF-FILE signal.c
chmod 'u=rw,g=r,o=r' \s\i\g\n\a\l\.\c
set `sum \s\i\g\n\a\l\.\c`
sum=$1
case $sum in
09347) :;;
*) echo 'Bad sum in '\s\i\g\n\a\l\.\c >&2
esac
exit 0