|  | /* | 
|  | Plan 9 from User Space src/lib9/await.c | 
|  | http://code.swtch.com/plan9port/src/tip/src/lib9/await.c | 
|  |  | 
|  | Copyright 2001-2007 Russ Cox.  All Rights Reserved. | 
|  | Portions Copyright 2009 The Go Authors.  All Rights Reserved. | 
|  |  | 
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | 
|  | of this software and associated documentation files (the "Software"), to deal | 
|  | in the Software without restriction, including without limitation the rights | 
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
|  | copies of the Software, and to permit persons to whom the Software is | 
|  | furnished to do so, subject to the following conditions: | 
|  |  | 
|  | The above copyright notice and this permission notice shall be included in | 
|  | all copies or substantial portions of the Software. | 
|  |  | 
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE | 
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
|  | THE SOFTWARE. | 
|  | */ | 
|  |  | 
|  | #define NOPLAN9DEFINES | 
|  | #include <u.h> | 
|  | #include <libc.h> | 
|  |  | 
|  | #include <signal.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/wait.h> | 
|  | #include <sys/time.h> | 
|  | #include <sys/resource.h> | 
|  |  | 
|  | #ifndef WCOREDUMP	/* not on Mac OS X Tiger */ | 
|  | #define WCOREDUMP(status) 0 | 
|  | #endif | 
|  |  | 
|  | static struct { | 
|  | int sig; | 
|  | char *str; | 
|  | } tab[] = { | 
|  | SIGHUP,		"hangup", | 
|  | SIGINT,		"interrupt", | 
|  | SIGQUIT,		"quit", | 
|  | SIGILL,		"sys: illegal instruction", | 
|  | SIGTRAP,		"sys: breakpoint", | 
|  | SIGABRT,		"sys: abort", | 
|  | #ifdef SIGEMT | 
|  | SIGEMT,		"sys: emulate instruction executed", | 
|  | #endif | 
|  | SIGFPE,		"sys: fp: trap", | 
|  | SIGKILL,		"sys: kill", | 
|  | SIGBUS,		"sys: bus error", | 
|  | SIGSEGV,		"sys: segmentation violation", | 
|  | SIGALRM,		"alarm", | 
|  | SIGTERM,		"kill", | 
|  | SIGURG,		"sys: urgent condition on socket", | 
|  | SIGSTOP,		"sys: stop", | 
|  | SIGTSTP,		"sys: tstp", | 
|  | SIGCONT,		"sys: cont", | 
|  | SIGCHLD,		"sys: child", | 
|  | SIGTTIN,		"sys: ttin", | 
|  | SIGTTOU,		"sys: ttou", | 
|  | #ifdef SIGIO	/* not on Mac OS X Tiger */ | 
|  | SIGIO,		"sys: i/o possible on fd", | 
|  | #endif | 
|  | SIGXCPU,		"sys: cpu time limit exceeded", | 
|  | SIGXFSZ,		"sys: file size limit exceeded", | 
|  | SIGVTALRM,	"sys: virtual time alarm", | 
|  | SIGPROF,		"sys: profiling timer alarm", | 
|  | #ifdef SIGWINCH	/* not on Mac OS X Tiger */ | 
|  | SIGWINCH,	"sys: window size change", | 
|  | #endif | 
|  | #ifdef SIGINFO | 
|  | SIGINFO,		"sys: status request", | 
|  | #endif | 
|  | SIGUSR1,		"sys: usr1", | 
|  | SIGUSR2,		"sys: usr2", | 
|  | SIGPIPE,		"sys: write on closed pipe", | 
|  | }; | 
|  |  | 
|  | char* | 
|  | _p9sigstr(int sig, char *tmp) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for(i=0; i<nelem(tab); i++) | 
|  | if(tab[i].sig == sig) | 
|  | return tab[i].str; | 
|  | if(tmp == nil) | 
|  | return nil; | 
|  | sprint(tmp, "sys: signal %d", sig); | 
|  | return tmp; | 
|  | } | 
|  |  | 
|  | int | 
|  | _p9strsig(char *s) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for(i=0; i<nelem(tab); i++) | 
|  | if(strcmp(s, tab[i].str) == 0) | 
|  | return tab[i].sig; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static Waitmsg* | 
|  | _wait(int pid4, int opt) | 
|  | { | 
|  | int pid, status, cd; | 
|  | struct rusage ru; | 
|  | char tmp[64]; | 
|  | ulong u, s; | 
|  | Waitmsg *w; | 
|  |  | 
|  | w = malloc(sizeof *w + 200); | 
|  | if(w == nil) | 
|  | return nil; | 
|  | memset(w, 0, sizeof *w); | 
|  | w->msg = (char*)&w[1]; | 
|  |  | 
|  | for(;;){ | 
|  | /* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */ | 
|  | if(pid4 == -1) | 
|  | pid = wait3(&status, opt, &ru); | 
|  | else | 
|  | pid = wait4(pid4, &status, opt, &ru); | 
|  | if(pid <= 0) { | 
|  | free(w); | 
|  | return nil; | 
|  | } | 
|  | u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000); | 
|  | s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000); | 
|  | w->pid = pid; | 
|  | w->time[0] = u; | 
|  | w->time[1] = s; | 
|  | w->time[2] = u+s; | 
|  | if(WIFEXITED(status)){ | 
|  | if(status) | 
|  | sprint(w->msg, "%d", status); | 
|  | return w; | 
|  | } | 
|  | if(WIFSIGNALED(status)){ | 
|  | cd = WCOREDUMP(status); | 
|  | sprint(w->msg, "signal: %s", _p9sigstr(WTERMSIG(status), tmp)); | 
|  | if(cd) | 
|  | strcat(w->msg, " (core dumped)"); | 
|  | return w; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Waitmsg* | 
|  | p9wait(void) | 
|  | { | 
|  | return _wait(-1, 0); | 
|  | } | 
|  |  | 
|  | Waitmsg* | 
|  | p9waitfor(int pid) | 
|  | { | 
|  | return _wait(pid, 0); | 
|  | } | 
|  |  | 
|  | Waitmsg* | 
|  | p9waitnohang(void) | 
|  | { | 
|  | return _wait(-1, WNOHANG); | 
|  | } | 
|  |  | 
|  | int | 
|  | p9waitpid(void) | 
|  | { | 
|  | int status; | 
|  | return wait(&status); | 
|  | } |