| #include <u.h> |
| #include <sys/time.h> |
| #include <sys/resource.h> |
| #include "threadimpl.h" |
| |
| #undef waitpid |
| #undef pipe |
| #undef wait |
| |
| static int sigpid; |
| static int threadpassfd; |
| static int gotsigchld; |
| |
| static void |
| child(void) |
| { |
| int status, pid; |
| struct rlimit rl; |
| |
| notedisable("sys: child"); |
| pid = waitpid(sigpid, &status, 0); |
| if(pid < 0){ |
| fprint(2, "%s: wait: %r\n", argv0); |
| _exit(97); |
| } |
| if(WIFEXITED(status)) |
| _exit(WEXITSTATUS(status)); |
| if(WIFSIGNALED(status)){ |
| /* |
| * Make sure we don't scribble over the nice |
| * core file that our child just wrote out. |
| */ |
| rl.rlim_cur = 0; |
| rl.rlim_max = 0; |
| setrlimit(RLIMIT_CORE, &rl); |
| |
| signal(WTERMSIG(status), SIG_DFL); |
| raise(WTERMSIG(status)); |
| _exit(98); /* not reached */ |
| } |
| if(WIFSTOPPED(status)){ |
| fprint(2, "%s: wait pid %d stopped\n", argv0, pid); |
| return; |
| } |
| #ifdef WIFCONTINUED |
| if(WIFCONTINUED(status)){ |
| fprint(2, "%s: wait pid %d continued\n", argv0, pid); |
| return; |
| } |
| #endif |
| fprint(2, "%s: wait pid %d status 0x%ux\n", argv0, pid, status); |
| _exit(99); |
| } |
| |
| static void |
| sigpass(int sig) |
| { |
| if(sigpid == 1){ |
| gotsigchld = 1; |
| return; |
| } |
| |
| if(sig == SIGCHLD) |
| child(); |
| else |
| kill(sigpid, sig); |
| } |
| |
| static int sigs[] = |
| { |
| SIGHUP, SIGINT, SIGQUIT, SIGILL, |
| SIGTRAP, SIGABRT, SIGBUS, SIGFPE, |
| SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, |
| SIGALRM, SIGTERM, SIGCHLD, SIGSTOP, |
| /*SIGTSTP, SIGTTIN, SIGTTOU,*/ SIGURG, |
| SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, |
| #ifdef SIGWINCH |
| SIGWINCH, |
| #endif |
| #ifdef SIGIO |
| SIGIO, |
| #endif |
| #ifdef SIGEMT |
| SIGEMT, |
| #endif |
| #ifdef SIGPWR |
| SIGPWR, |
| #endif |
| #ifdef SIGINFO |
| SIGINFO, |
| #endif |
| SIGSYS |
| }; |
| |
| void |
| _threadsetupdaemonize(void) |
| { |
| int i, n, pid; |
| int p[2]; |
| char buf[20]; |
| |
| sigpid = 1; |
| |
| if(pipe(p) < 0) |
| sysfatal("passer pipe: %r"); |
| |
| /* hide these somewhere they won't cause harm */ |
| /* can't go too high: NetBSD max is 64, for example */ |
| if(dup(p[0], 28) < 0 || dup(p[1], 29) < 0) |
| sysfatal("passer pipe dup: %r"); |
| close(p[0]); |
| close(p[1]); |
| p[0] = 28; |
| p[1] = 29; |
| |
| /* close on exec */ |
| if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0) |
| sysfatal("passer pipe pipe fcntl: %r"); |
| |
| noteenable("sys: child"); |
| signal(SIGCHLD, sigpass); |
| switch(pid = fork()){ |
| case -1: |
| sysfatal("passer fork: %r"); |
| default: |
| close(p[1]); |
| break; |
| case 0: |
| notedisable("sys: child"); |
| signal(SIGCHLD, SIG_DFL); |
| /* rfork(RFNOTEG); */ |
| close(p[0]); |
| threadpassfd = p[1]; |
| return; |
| } |
| |
| sigpid = pid; |
| if(gotsigchld) |
| sigpass(SIGCHLD); |
| |
| for(i=0; i<nelem(sigs); i++){ |
| struct sigaction sa; |
| |
| memset(&sa, 0, sizeof sa); |
| sa.sa_handler = sigpass; |
| sa.sa_flags |= SA_RESTART; |
| sigaction(sigs[i], &sa, nil); |
| } |
| |
| for(;;){ |
| n = read(p[0], buf, sizeof buf-1); |
| if(n == 0){ /* program exited */ |
| child(); |
| } |
| if(n > 0) |
| break; |
| print("passer read: %r\n"); |
| } |
| buf[n] = 0; |
| _exit(atoi(buf)); |
| } |
| |
| void |
| _threaddaemonize(void) |
| { |
| if(threadpassfd >= 0){ |
| write(threadpassfd, "0", 1); |
| close(threadpassfd); |
| threadpassfd = -1; |
| } |
| } |