magic/utils/child.c

258 lines
4.4 KiB
C

/*************************************************************************
*
* (c) 1997 California Institute of Technology
* Department of Computer Science
* Pasadena, CA 91125.
* All Rights Reserved
*
* $Header$
*
*************************************************************************/
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include "utils/utils.h"
#include "utils/malloc.h"
/*------------------------------------------------------------------------
* Internal list management
*------------------------------------------------------------------------*/
struct Wait_List {
int pid; /* FIXME pid_t */
int status;
int pending;
struct Wait_List *next;
};
static struct Wait_List *wl = NULL;
static void
make_finished(
int pid,
int *status)
{
struct Wait_List *l;
l = wl;
while (l) {
if (l->pid == pid) {
l->pending = 0;
l->status = *status;
return;
}
l = l->next;
}
return;
}
static void
add_pending_to_list(
int pid)
{
struct Wait_List *l;
l = (struct Wait_List *) mallocMagic((unsigned)(sizeof(struct Wait_List)));
l->next = wl;
l->pid = pid;
l->status = -1;
l->pending = 1;
wl = l;
return;
}
static int
find_pid(
int pid,
int *status)
{
struct Wait_List *l;
l = wl;
while (l) {
if (l->pid == pid) {
*status = l->status;
return l->pending;
}
l = l->next;
}
return -1;
}
static int
get_next(
int *status)
{
struct Wait_List *l, *prev;
int pid;
prev = NULL;
l = wl;
while (l) {
if (!l->pending) {
pid = l->pid;
*status = l->status;
if (prev)
prev->next = l->next;
else
wl = l->next;
freeMagic(l);
return pid;
}
prev = l;
l = l->next;
}
return -1;
}
static void
delete_from_list(
int pid)
{
struct Wait_List *l, *prev;
prev = NULL;
l = wl;
while (l) {
if (l->pid == pid) {
if (prev)
prev->next = l->next;
else
wl = l->next;
freeMagic(l);
return;
}
prev = l;
l = l->next;
}
}
/*------------------------------------------------------------------------
*
* Wait --
*
* Wait for a process to terminate. Returns the pid that you waited
* for, along with the exit status in *status.
*
* Returns -1 on an attempt to wait for a pid which wasn't ever
* forked.
*
* If you want to wait for a particular pid, use WaitPid instead
* of Wait.
*
* Results:
* The pid that finished, along with the status.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
int
Wait(
int *status)
{
int pid;
int p_status = 0;
pid = get_next(&p_status);
if (pid != -1) {
if (status)
*status = p_status;
return pid;
}
if (wl) {
do {
pid = wait(&p_status);
} while (pid < 0 && errno == EINTR);
delete_from_list (pid);
if (status)
*status = p_status;
return pid;
}
else
/* nothing to wait for */
return -1;
}
/*------------------------------------------------------------------------
*
* WaitPid --
*
* Wait for a particular process to terminate.
*
* Returns -1 on an attempt to wait for a pid which wasn't ever
* forked.
*
* If you want to wait for a particular pid, use WaitPid instead
* of Wait.
*
* Results:
* The pid that finished, along with the status.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
int
WaitPid(
int pid,
int *status)
{
int stat;
int n_pid, n_status;
stat = find_pid (pid,&n_status);
if (stat == -1)
return -1;
if (stat == 0) {
delete_from_list (pid);
if (status)
*status = n_status;
return 1;
}
do {
do {
n_pid = wait(&n_status);
} while (n_pid < 0 && errno == EINTR);
make_finished (n_pid, &n_status);
} while (n_pid != pid && n_pid != -1);
if (n_pid == -1) return -1;
delete_from_list (pid);
if (status)
*status = n_status;
return 1;
}
/*------------------------------------------------------------------------
*
* ForkChildAdd --
*
* Fork, along with updating the wait list structure.
*
* Results:
* The pid that finished, along with the status.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
void
ForkChildAdd(
int pid)
{
add_pending_to_list (pid);
}