28 #include <sys/types.h>
38 static void waitpipe_sigchld(
int signo,siginfo_t *siginfo,
void *ucontext);
43 static struct waitpipectl waitpipe = { NULL,NULL,NULL };
45 .sa_sigaction = waitpipe_sigchld,
46 .sa_flags = SA_SIGINFO,
50 return waitpipe_sigchld(signo,siginfo,NULL);
53 static void waitpipe_sigchld(
int signo,siginfo_t *siginfo,
void *ucontext) {
60 pid = siginfo->si_pid;
61 if (signo == SIGCHLD && pid > 0) {
68 pid,siginfo->si_code,siginfo->si_status);
70 pipefds = (
int *)g_hash_table_lookup(waitpipe.
pids,
71 (gpointer)(uintptr_t)pid);
80 if (write(pipefds[1],
"",1) < 0)
81 verror(
"write(fd %d): %s\n",pipefds[1],strerror(errno));
126 vwarn(
"global waitpipe already initialized!\n");
133 waitpipe.
pids = g_hash_table_new(g_direct_hash,g_direct_equal);
134 waitpipe.
readfds = g_hash_table_new(g_direct_hash,g_direct_equal);
142 vwarn(
"global waitpipe already initialized!\n");
149 waitpipe.
pids = g_hash_table_new(g_direct_hash,g_direct_equal);
150 waitpipe.
readfds = g_hash_table_new(g_direct_hash,g_direct_equal);
153 if (
sigaction(SIGCHLD,&waitpipe_act,NULL)) {
154 g_hash_table_destroy(waitpipe.
pids);
155 g_hash_table_destroy(waitpipe.
readfds);
156 waitpipe.
pids = NULL;
159 verror(
"sigaction: %s\n",strerror(errno));
168 g_hash_table_destroy(waitpipe.
pids);
169 g_hash_table_destroy(waitpipe.
readfds);
171 waitpipe.
pids = NULL;
189 if (!waitpipe.
pids) {
190 verror(
"waitpipe not initialized!\n");
195 pipefds =
malloc(
sizeof(*pipefds)*2);
201 verror(
"pipe: %s\n",strerror(errno));
218 fcntl(pipefds[0],F_SETFL,fcntl(pipefds[0],F_GETFL) | O_NONBLOCK);
219 fcntl(pipefds[1],F_SETFL,fcntl(pipefds[1],F_GETFL) | O_NONBLOCK);
225 fcntl(pipefds[0],F_SETFD,FD_CLOEXEC);
226 fcntl(pipefds[1],F_SETFD,FD_CLOEXEC);
229 g_hash_table_insert(waitpipe.
pids,
230 (gpointer)(uintptr_t)pid,(gpointer)(uintptr_t)pipefds);
233 g_hash_table_insert(waitpipe.
readfds,
234 (gpointer)(uintptr_t)pipefds[0],
235 (gpointer)(uintptr_t)pid);
242 memset(&si,0,
sizeof(si));
243 rc = waitid(P_PID,pid,&si,WNOHANG | WEXITED | WNOWAIT);
245 if (errno == ECHILD) {
246 if (kill(pid,0) < 0 && errno == ESRCH) {
248 g_hash_table_remove(waitpipe.
pids,(gpointer)(uintptr_t)pid);
249 g_hash_table_remove(waitpipe.
readfds,(gpointer)(uintptr_t)pipefds[0]);
253 vwarn(
"pid %d disappeared before it could be added: %s!\n",
254 pid,strerror(errno));
260 vwarn(
"pid %d disappeared before it could be added: %s!\n",
261 pid,strerror(errno));
266 else if (rc == 0 && si.si_pid == pid) {
267 if (!g_hash_table_lookup(waitpipe.
pids,(gpointer)(uintptr_t)pid)) {
268 vwarn(
"pid %d exited before we tracked it; notifying.\n",pid);
272 vwarn(
"pid %d exited before we fully tracked it; notification"
273 " already in progress.\n",pid);
287 if (!waitpipe.
pids) {
288 verror(
"waitpipe not initialized!\n");
293 pipefds = (
int *)g_hash_table_lookup(waitpipe.
pids,(gpointer)(uintptr_t)pid);
295 g_hash_table_remove(waitpipe.
pids,(gpointer)(uintptr_t)pid);
296 g_hash_table_remove(waitpipe.
readfds,(gpointer)(uintptr_t)pipefds[0]);
313 if (!waitpipe.
pids) {
314 verror(
"waitpipe not initialized!\n");
319 pipefds = (
int *)g_hash_table_lookup(waitpipe.
pids,
320 (gpointer)(uintptr_t)pid);
321 if (pipefds && pipefds[0])
333 if (!waitpipe.
pids) {
334 verror(
"waitpipe not initialized!\n");
339 pid = (int)(uintptr_t)g_hash_table_lookup(waitpipe.
readfds,
340 (gpointer)(uintptr_t)readfd);
357 if (!waitpipe.
pids) {
358 verror(
"waitpipe not initialized!\n");
363 pipefds = (
int *)g_hash_table_lookup(waitpipe.
pids,(gpointer)(uintptr_t)pid);
365 while ((rc = read(pipefds[0],buf,
sizeof(buf)))) {
367 if (errno == EAGAIN || errno == EWOULDBLOCK)
369 else if (errno == EINTR)
373 verror(
"read pipefd(pid %d): %s\n",pid,strerror(errno));
382 pid,pipefds[1],pipefds[0],retval);
void(* alt_handler)(int, siginfo_t *, void *)
int waitpipe_remove(int pid)
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
int waitpipe_is_initialized(void)
#define verror(format,...)
#define vwarn(format,...)
int waitpipe_get(int pid)
int waitpipe_init_ext(void(*alt_handler)(int, siginfo_t *, void *))
int waitpipe_drain(int pid)
#define vdebug(devel, areas, flags, format,...)
void waitpipe_notify(int signo, siginfo_t *siginfo)
int waitpipe_add(int pid)
int waitpipe_init_auto(void(*alt_handler)(int, siginfo_t *, void *))
void * malloc(size_t size)
int waitpipe_get_pid(int readfd)