#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 voidchild(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 voidsigpass(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; }}
#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;
}
}