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