blob: e047ab02e249bdb5e530befb7d667c140dee27c0 [file] [log] [blame]
#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;
}
}