1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "bl_sig_child.h"
4 
5 #ifndef USE_WIN32API
6 
7 #include <errno.h> /* EINTR */
8 #include <signal.h>
9 #include <sys/wait.h>
10 
11 #endif
12 
13 #include "bl_debug.h"
14 #include "bl_mem.h" /* realloc/free */
15 
16 typedef struct sig_child_event_listener {
17   void *self;
18   void (*exited)(void *, pid_t);
19 
20 } sig_child_event_listener_t;
21 
22 /* --- static variables --- */
23 
24 static sig_child_event_listener_t *listeners;
25 static u_int num_listeners;
26 
27 /* --- static functions --- */
28 
29 #ifndef USE_WIN32API
30 
sig_child(int sig)31 static void sig_child(int sig) {
32   pid_t pid;
33 
34 #ifdef DEBUG
35   bl_debug_printf(BL_DEBUG_TAG " SIG CHILD received.\n");
36 #endif
37 
38   while (1) {
39     if ((pid = waitpid(-1, NULL, WNOHANG)) <= 0) {
40       if (pid == -1 && errno == EINTR) {
41         errno = 0;
42         continue;
43       }
44 
45       break;
46     }
47 
48     bl_trigger_sig_child(pid);
49   }
50 
51   /* reset */
52   signal(SIGCHLD, sig_child);
53 }
54 
55 #endif
56 
57 /* --- global functions --- */
58 
bl_sig_child_start(void)59 void bl_sig_child_start(void) {
60 #ifndef USE_WIN32API
61   signal(SIGCHLD, sig_child);
62 #endif
63 }
64 
bl_sig_child_stop(void)65 void bl_sig_child_stop(void) {
66 #ifndef USE_WIN32API
67   signal(SIGCHLD, SIG_DFL);
68 #endif
69 }
70 
bl_sig_child_final(void)71 void bl_sig_child_final(void) {
72 #ifndef USE_WIN32API
73   signal(SIGCHLD, SIG_DFL);
74 #endif
75   free(listeners);
76   listeners = NULL;
77 }
78 
bl_add_sig_child_listener(void * self,void (* exited)(void *,pid_t))79 int bl_add_sig_child_listener(void *self, void (*exited)(void *, pid_t)) {
80   void *p;
81 
82   if ((p = realloc(listeners, sizeof(*listeners) * (num_listeners + 1))) == NULL) {
83 #ifdef DEBUG
84     bl_warn_printf(BL_DEBUG_TAG " realloc failed.\n");
85 #endif
86 
87     return 0;
88   }
89 
90   listeners = p;
91 
92   listeners[num_listeners].self = self;
93   listeners[num_listeners].exited = exited;
94 
95   num_listeners++;
96 
97   return 1;
98 }
99 
bl_remove_sig_child_listener(void * self,void (* exited)(void *,pid_t))100 int bl_remove_sig_child_listener(void *self, void (*exited)(void *, pid_t)) {
101   u_int count;
102 
103   for (count = 0; count < num_listeners; count++) {
104     if (listeners[count].self == self && listeners[count].exited == exited) {
105       listeners[count] = listeners[--num_listeners];
106 
107       /*
108        * memory area of listener is not shrunk.
109        */
110 
111       return 1;
112     }
113   }
114 
115   return 0;
116 }
117 
bl_trigger_sig_child(pid_t pid)118 void bl_trigger_sig_child(pid_t pid) {
119   u_int count;
120 
121   for (count = 0; count < num_listeners; count++) {
122     (*listeners[count].exited)(listeners[count].self, pid);
123   }
124 }
125