| /* |
| 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); |
| } |