|
|
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;
}