DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T p

⟦871a5a77b⟧ TextFile

    Length: 8560 (0x2170)
    Types: TextFile
    Names: »process.c«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦e10a7c8ba⟧ »./UNRELEASED/xgdb.tar.Z« 
        └─⟦ae30648b5⟧ 
            └─⟦this⟧ »./process.c« 

TextFile

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