|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T p
Length: 8560 (0x2170) Types: TextFile Names: »process.c«
└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89 └─⟦e10a7c8ba⟧ »./UNRELEASED/xgdb.tar.Z« └─⟦ae30648b5⟧ └─⟦this⟧ »./process.c«
\f #ifndef lint static char rcsid[] = "$Header: process.c,v 1.1 89/07/05 15:36:17 hubbard Exp $"; #endif /* * * Copyright 1988, 1989 * PCS Computer Systeme, GmbH * Munich, West Germany * * All rights reserved. * * This is unsupported software and is subject to change without notice. * PCS makes no representations about the suitability of this software * for any purpose. It is supplied "as is" without express or implied * warranty. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of PCS Computer Systeme not be used in * advertising or publicity pertaining to distribution of the software * without specific, written prior permission. * */ /* * Author: Jordan K. Hubbard * For: PCS Computer Systems, GmbH. * Why: Why not? * When: February 10th, 1989. * * $Log: process.c,v $ * Revision 1.1 89/07/05 15:36:17 hubbard * Initial revision * * */ #include "xgdb.h" #include <sys/socket.h> #include <errno.h> Queue ProcQueue; /* * Glue for dealing with the inferior debugger process using pipes. * VMS users might want to use virtual mailboxes or something. * * It may appear at first glance that the inferior process handling is * overly complex for what would seem to be a sole debugger process, but * not all debuggers will support xgdb's command set, making it perhaps * necessary to emulate certain functions by spawning off specialized * unix processes. Should this be necessary, the mechanism is provided. */ /* * Turn on process handling. If process handling is turned off, it's * the responsibilty of the function disabling it to wait() for any * processes that may be outstanding and deal with their process * queue entries accordinly. */ void enableProcessHandling() { static void handleProcessTermination(); Entry("enableProcessHandling"); signal(SIGCHLD, handleProcessTermination); Leave_void; } /* * Turn off the process handling. */ void disableProcessHandling() { Entry("disableProcessHandling"); signal(SIGCHLD, SIG_IGN); Leave_void; } /* * Temporarily suspend the process handler. */ void suspendProcessHandling() { Entry("suspendProcessHandling"); #ifdef SYSV sighold(SIGCHLD); #else /* BSD? */ sigsetmask(1 << (SIGCHLD - 1)); #endif Leave_void; } /* * Resume process handling. */ void resumeProcessHandling() { Entry("resumeProcessHandling"); #ifdef SYSV sigrelse(SIGCHLD); #else /* BSD? */ sigsetmask(0); #endif Leave_void; } /* * Given a PID, find the process descriptor for it. */ Process *lookupProcessByPID(pid) int pid; { Process *tmp; Entry("lookupProcessByPID"); ASSERT(NULLP(pid)); for (tmp = FIRST(&ProcQueue, Process); tmp; tmp = NEXT(tmp)) if (tmp->pid == pid) Leave(tmp); Leave((Process *)NULL); } /* * Given a process descriptor and a status, print an informative message * about its demise in the debugger message window. */ void displayTerminationStatus(pd, status) Process *pd; int status; { String msg[256]; Entry("displayTerminationStatus"); if (status & 0xff00 == 0) sprintf(msg, "process '%s' caught signal %d\n", pd->name, status & 0xff); else sprintf(msg, "process '%s' terminated with exit status %04x\n", pd->name, status & 0xff00); viewAppendText(pd->view, msg, strlen(msg)); Leave_void; } /* * Hey, somebody croaked. wait() to see why the process died and then * call its termination handler (diefunc) if it has one. If it doesn't, * just print an informative message (the handler is free to do the same * if it so wishes). */ static void handleProcessTermination() { int pid, reason; Process *tmp; Entry("handleProcessTermination"); pid = wait(&reason); if (tmp = lookupProcessByPID(pid)) { if (tmp->diefunc) (*(tmp->diefunc))(tmp, reason); else displayTerminationStatus(tmp, reason); removeQueueEntry(&ProcQueue, tmp); XtFree(tmp); } else { puke("%p: Dead Process number #%d is unknown! Status = %x", pid, reason); } #ifdef SYSV /* gotta reset */ enableProcessHandling(); #endif Leave_void; } /* * Given a program name, the arguments to call it with and I/O and termination * handlers (possibly NULL), create a new process and return its descriptor. * This function should be used to create any work processes needed by xgdb. */ Process *launchProcess(name, args, in_p, out_p, term) String name; String *args; VoidFuncP in_p, out_p; VoidFuncP term; { int in[2], out[2]; Process *tmp; Entry("launchProcess"); ASSERT(NULLP(name)); NEW(tmp, Process); addQueueEntry(&ProcQueue, tmp); tmp->name = name; tmp->diefunc = term; tmp->infunc = in_p; tmp->outfunc = out_p; tmp->in_id = tmp->out_id = 0; if (pipe(in) < 0 || pipe(out) < 0) { puke("%p: Can't create input or output pipe."); Leave((Process *)NULL); } if (tmp->pid = fork()) { /* daddy */ tmp->in_channel = in[0]; tmp->out_channel = out[1]; close(in[1]); close(out[0]); if (in_p) tmp->in_id = XtAddInput(tmp->in_channel, XtInputReadMask, in_p, (caddr_t)tmp); if (out_p) tmp->out_id = XtAddInput(tmp->out_channel, XtInputWriteMask, out_p, (caddr_t)tmp); Leave(tmp); } else { /* junior */ int fl; close(0); close(1); close(2); dup2(out[0], 0); dup2(in[1], 1); dup2(in[1], 2); for (fl = 3; fl < NFILES; fl++) close(fl); setpgrp(0, getpid()); execvp(name, args); _exit(127); } Leave_void; } static Process *victim; /* * See nukeProcess() below. */ static void dieBotch() { char msg[255]; Entry("dieBotch"); sprintf(msg, "Hmmm. Can't seem to kill '%s' for some reason. Oh well.\n", victim->name); if (victim->view) viewAppendText(victim->view, msg, strlen(msg)); else puke("%p: %s", msg); Leave_void; } /* * Given a process entry, burn it. We *DON'T* call the process's termination * handler as we assume that this is premeditated murder. To get a process * to die more normally, send it a signal with sendProcessSignal(). */ void nukeProcess(proc) Process *proc; { Entry("nukeProcess"); ASSERT(NULLP(proc)); disableProcessHandling(); /* turn off termination checking */ /* Set this so dieBotch() can figure out who's holding out */ victim = proc; /* Take us out of the queue of interesting processes */ removeQueueEntry(&ProcQueue, proc); /* BLAM! */ sendProcessSignal(proc, SIGKILL); /* Make my day. */ /* Close down */ if (proc->in_id) XtRemoveInput(proc->in_id); if (proc->out_id) XtRemoveInput(proc->out_id); close(proc->in_channel); close(proc->out_channel); /* * Wait for the process to croak. Of course, if it's in * a really bad state, we'll be screwed [wait() will wedge] * so we play it cautious and set an alarm(). */ signal(SIGALRM, dieBotch); alarm(10); if (wait(0) < 0) /* alarm went off */ sleep(4); /* Give the user a chance to see the message */ alarm(0); signal(SIGALRM, SIG_DFL); XtFree(proc); Leave_void; } /* * Send a signal to a process. */ void sendProcessSignal(pd, sig) Process *pd; int sig; { Entry("sendProcessSignal"); ASSERT(NULLP(pd)); #ifdef DEBUG debug("%p: About to send signal #%d to process %d", sig, pd->pid); #endif DEBUG kill(pd->pid, sig); Leave_void; } /* * Send a string to a process. */ void sendToProcess(pd, str) Process *pd; String str; { Cardinal len, actual; Entry("sendToProcess"); ASSERT(NULLP(pd) || NULLP(str)); #ifdef SYSV suspendProcessHandling(); /* non-restartable syscalls. Puke. */ #endif #ifdef DEBUG debug("%p: To %x, sending '%s'", pd, str); #endif DEBUG len = strlen(str); actual = write(pd->out_channel, str, len); if (actual != len) { puke("%p: Write to %d failed. Bytes tried=%d, sent=%d", pd->out_channel, len, actual); } #ifdef SYSV resumeProcessHandling(); /* Ok to get SIGCHLD's now */ #endif Leave_void; }