shithub: npe

ref: 2aee89298cbbf5c1b4d50e70733b52ae75c706fd
dir: /libnpe/wait.c/

View raw version
#include <npe.h>
#include <signal.h>

static struct {
	char	*msg;	/* just check prefix */
	int	num;
} sigtab[] = {
	{"interrupt",				SIGINT},
	{"sys: trap: illegal instruction",	SIGILL},
	{"sys: trap: reserved instruction",	SIGILL},
	{"sys: trap: reserved",			SIGILL},
	{"sys: trap: arithmetic overflow",	SIGFPE},
	{"abort",				SIGABRT},
	{"sys: fp:",				SIGFPE},
	{"exit",				SIGKILL},
	{"die",					SIGKILL},
	{"kill",				SIGKILL},
	{"sys: trap: bus error",		SIGSEGV},
	{"sys: trap: address error",		SIGSEGV},
	{"sys: trap: TLB",			SIGSEGV},
	{"term",				SIGTERM},
};
#define NSIGTAB ((sizeof sigtab)/(sizeof (sigtab[0])))

int
_stringsig(char *nam)
{
	int i;

	for(i = 0; i<NSIGTAB; i++)
		if(strncmp(nam, sigtab[i].msg, strlen(sigtab[i].msg)) == 0)
			return sigtab[i].num;
	return 0;
}


/*
 * status not yet collected for processes that have exited
 */
typedef struct Waited Waited;
struct Waited {
	Waitmsg*	msg;
	Waited*	next;
};
static Waited *wd;

static Waitmsg *
lookpid(int pid)
{
	Waited **wl, *w;
	Waitmsg *msg;

	for(wl = &wd; (w = *wl) != nil; wl = &w->next)
		if(pid <= 0 || w->msg->pid == pid){
			msg = w->msg;
			*wl = w->next;
			free(w);
			return msg;
		}
	return 0;
}

static void
addpid(Waitmsg *msg)
{
	Waited *w;

	w = malloc(sizeof(*w));
	if(w == nil){
		/* lost it; what can we do? */
		free(msg);
		return;
	}
	w->msg = msg;
	w->next = wd;
	wd = w;
}

static int
waitstatus(Waitmsg *w)
{
	int r, t;
	char *bp, *ep;

	r = 0;
	t = 0;
	if(w->msg[0]){
		/* message is 'prog pid:string' */
		bp = w->msg;
		while(*bp){
			if(*bp++ == ':')
				break;
		}
		if(*bp == 0)
			bp = w->msg;
		r = strtol(bp, &ep, 10);
		if(*ep == 0){
			if(r < 0 || r >= 256)
				r = 1;
		}else{
			t = _stringsig(bp);
			if(t == 0)
				r = 1;
		}
	}
	return (r<<8) | t;
}

int
npe_waitpid(int wpid, int *status, int options)
{
	char pname[50];
	Dir *d;
	Waitmsg *w;

	w = lookpid(wpid);
	if(w == nil){
		if(options & WNOHANG){
			snprintf(pname, sizeof(pname), "/proc/%d/wait", getpid());
			d = dirstat(pname);
			if(d != nil && d->length == 0){
				free(d);
				return 0;
			}
			free(d);
		}
		for(;;){
			w = wait();
			if(w == nil){
				return -1;
			}
			if(wpid <= 0 || w->pid == wpid)
				break;
			addpid(w);
		}
	}
	if(status != nil)
		*status = waitstatus(w);
	wpid = w->pid;
	free(w);
	return wpid;

}