summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2018-01-06 17:37:42 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2018-01-06 18:20:23 +0900
commitba16dee6b3d5f84e0184c86b64d5fe54e32b4966 (patch)
treebe4899bbdae19fa6d9f526c8699c6b65b504d0fd
parent2fb80270ba978d3d30915007b275cdbd57b3e433 (diff)
ecore signal - move to using a pipe (and optional thread) tfor signals
this should remove any races in catching signals. it should also be portable. as well.
-rw-r--r--src/lib/ecore/ecore_signal.c811
1 files changed, 301 insertions, 510 deletions
diff --git a/src/lib/ecore/ecore_signal.c b/src/lib/ecore/ecore_signal.c
index 3d743a21cd..e4f33de815 100644
--- a/src/lib/ecore/ecore_signal.c
+++ b/src/lib/ecore/ecore_signal.c
@@ -10,166 +10,175 @@
10#include <signal.h> 10#include <signal.h>
11#include <unistd.h> 11#include <unistd.h>
12#include <assert.h> 12#include <assert.h>
13#include <fcntl.h>
14#include <pthread.h>
13 15
14#include "Ecore.h" 16#include "Ecore.h"
15#include "ecore_private.h" 17#include "ecore_private.h"
16 18
17/* make mono happy - this is evil though... */ 19/* make mono happy - this is evil though... */
18#undef SIGPWR 20#undef SIGPWR
19/* valgrind in some versions/setups uses SIGRT's... hmmm */
20 21
21typedef void (*Signal_Handler)(int sig, siginfo_t *si, void *foo); 22#define ECORE_SIGNAL_THREAD 1
22
23static void _ecore_signal_callback_set(int sig,
24 Signal_Handler func);
25static void _ecore_signal_callback_ignore(int sig,
26 siginfo_t *si,
27 void *foo);
28static void _ecore_signal_callback_sigchld(int sig,
29 siginfo_t *si,
30 void *foo);
31static void _ecore_signal_callback_sigusr1(int sig,
32 siginfo_t *si,
33 void *foo);
34static void _ecore_signal_callback_sigusr2(int sig,
35 siginfo_t *si,
36 void *foo);
37static void _ecore_signal_callback_sighup(int sig,
38 siginfo_t *si,
39 void *foo);
40static void _ecore_signal_callback_sigquit(int sig,
41 siginfo_t *si,
42 void *foo);
43static void _ecore_signal_callback_sigint(int sig,
44 siginfo_t *si,
45 void *foo);
46static void _ecore_signal_callback_sigterm(int sig,
47 siginfo_t *si,
48 void *foo);
49#ifdef SIGPWR
50static void _ecore_signal_callback_sigpwr(int sig,
51 siginfo_t *si,
52 void *foo);
53#endif
54 23
55static void _ecore_signal_exe_exit_delay(void *data, const Efl_Event *event); 24static void _ecore_signal_exe_exit_delay(void *data, const Efl_Event *event);
25static void _ecore_signal_waitpid(Eina_Bool once, siginfo_t info);
26static void _ecore_signal_generic_free(void *data, void *event);
56 27
57//#define MAXSIGQ 256 // 32k 28typedef void (*Signal_Handler)(int sig, siginfo_t *si, void *foo);
58#define MAXSIGQ 64 // 8k
59
60static volatile sig_atomic_t sig_count = 0;
61static volatile sig_atomic_t sigchld_count = 0;
62static volatile sig_atomic_t sigusr1_count = 0;
63static volatile sig_atomic_t sigusr2_count = 0;
64static volatile sig_atomic_t sighup_count = 0;
65static volatile sig_atomic_t sigquit_count = 0;
66static volatile sig_atomic_t sigint_count = 0;
67static volatile sig_atomic_t sigterm_count = 0;
68#ifdef SIGPWR
69static volatile sig_atomic_t sigpwr_count = 0;
70#endif
71 29
72static volatile siginfo_t sigchld_info[MAXSIGQ]; 30#ifdef ECORE_SIGNAL_THREAD
73static volatile siginfo_t sigusr1_info[MAXSIGQ]; 31static Eina_Thread sig_thread;
74static volatile siginfo_t sigusr2_info[MAXSIGQ]; 32static Eina_Bool sig_thread_exists = EINA_FALSE;
75static volatile siginfo_t sighup_info [MAXSIGQ];
76static volatile siginfo_t sigquit_info[MAXSIGQ];
77static volatile siginfo_t sigint_info [MAXSIGQ];
78static volatile siginfo_t sigterm_info[MAXSIGQ];
79#ifdef SIGPWR
80static volatile siginfo_t sigpwr_info [MAXSIGQ];
81#endif 33#endif
34static int sig_pipe[2] = { -1, -1 }; // [0] == read, [1] == write
35static Eo *sig_pipe_handler = NULL;
82 36
83#if defined(SIG_ATOMIC_MAX) 37typedef struct _Signal_Data
84# if SIG_ATOMIC_MAX == INT64_MAX 38{
85/* Basically FreeBSD on 64bits */ 39 int sig;
86# define PRIdSIGATOMIC PRId64 40 siginfo_t info;
87# elif SIG_ATOMIC_MAX == UINT64_MAX 41} Signal_Data;
88# define PRIdSIGATOMIC PRIu64
89# elif SIG_ATOMIC_MAX == UINT32_MAX
90# define PRIdSIGATOMIC PRIu32
91# else
92/* everybody else seems to go for int */
93# define PRIdSIGATOMIC PRId32
94# endif
95#else
96# define PRIdSIGATOMIC "d"
97#endif
98 42
99void 43static Eina_Bool
100_ecore_signal_shutdown(void) 44_ecore_signal_pipe_read(void)
101{ 45{
102 _ecore_signal_callback_set(SIGPIPE, (Signal_Handler)SIG_DFL); 46 Signal_Data sdata;
103 _ecore_signal_callback_set(SIGALRM, (Signal_Handler)SIG_DFL); 47 int ret;
104 // XXX: consider using new clone4 features: 48
105 // http://code.qt.io/cgit/qt/qtbase.git/tree/src/3rdparty/forkfd/forkfd.c 49 ret = read(sig_pipe[0], &sdata, sizeof(sdata));
106 // https://lkml.org/lkml/2015/3/12/1060 50 if (ret != sizeof(sdata)) return EINA_FALSE;
107 // https://lkml.org/lkml/2015/3/12/1044 51 switch (sdata.sig)
108 _ecore_signal_callback_set(SIGCHLD, (Signal_Handler)SIG_DFL); 52 {
109 _ecore_signal_callback_set(SIGUSR1, (Signal_Handler)SIG_DFL); 53 case SIGPIPE:
110 _ecore_signal_callback_set(SIGUSR2, (Signal_Handler)SIG_DFL); 54 break;
111 _ecore_signal_callback_set(SIGHUP, (Signal_Handler)SIG_DFL); 55 case SIGALRM:
112 _ecore_signal_callback_set(SIGQUIT, (Signal_Handler)SIG_DFL); 56 break;
113 _ecore_signal_callback_set(SIGINT, (Signal_Handler)SIG_DFL); 57 case SIGCHLD:
114 _ecore_signal_callback_set(SIGTERM, (Signal_Handler)SIG_DFL); 58 _ecore_signal_waitpid(EINA_FALSE, sdata.info);
59 break;
60 case SIGUSR1:
61 case SIGUSR2:
62 {
63 Ecore_Event_Signal_User *e = _ecore_event_signal_user_new();
64 if (e)
65 {
66 if (sdata.sig == SIGUSR1) e->number = 1;
67 else e->number = 2;
68 e->data = sdata.info;
69 ecore_event_add(ECORE_EVENT_SIGNAL_USER, e,
70 _ecore_signal_generic_free, NULL);
71 }
72 }
73 break;
74 case SIGHUP:
75 {
76 Ecore_Event_Signal_Hup *e = _ecore_event_signal_hup_new();
77 if (e)
78 {
79 e->data = sdata.info;
80 ecore_event_add(ECORE_EVENT_SIGNAL_HUP, e,
81 _ecore_signal_generic_free, NULL);
82 }
83 }
84 break;
85 case SIGQUIT:
86 case SIGINT:
87 case SIGTERM:
88 {
89 Ecore_Event_Signal_Exit *e = _ecore_event_signal_exit_new();
90 if (e)
91 {
92 if (sdata.sig == SIGQUIT) e->quit = 1;
93 else if (sdata.sig == SIGINT) e->interrupt = 1;
94 else e->terminate = 1;
95 e->data = sdata.info;
96 ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
97 _ecore_signal_generic_free, NULL);
98 }
99 }
100 break;
115#ifdef SIGPWR 101#ifdef SIGPWR
116 _ecore_signal_callback_set(SIGPWR, (Signal_Handler)SIG_DFL); 102 case SIGPWR:
117 sigpwr_count = 0; 103 {
104 Ecore_Event_Signal_Power *e = _ecore_event_signal_power_new();
105 if (e)
106 {
107 e->data = sdata.info;
108 ecore_event_add(ECORE_EVENT_SIGNAL_POWER, e,
109 _ecore_signal_generic_free, NULL);
110 }
111 }
112 break;
118#endif 113#endif
119 sigchld_count = 0; 114 default:
120 sigusr1_count = 0; 115 break;
121 sigusr2_count = 0; 116 }
122 sighup_count = 0; 117 return EINA_TRUE;
123 sigquit_count = 0;
124 sigint_count = 0;
125 sigterm_count = 0;
126 sig_count = 0;
127} 118}
128 119
129void 120static void
130_ecore_signal_init(void) 121_ecore_signal_cb_read(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
131{ 122{
132 _ecore_signal_callback_set(SIGPIPE, _ecore_signal_callback_ignore); 123 while (_ecore_signal_pipe_read());
133 _ecore_signal_callback_set(SIGALRM, _ecore_signal_callback_ignore);
134 _ecore_signal_callback_set(SIGCHLD, _ecore_signal_callback_sigchld);
135 _ecore_signal_callback_set(SIGUSR1, _ecore_signal_callback_sigusr1);
136 _ecore_signal_callback_set(SIGUSR2, _ecore_signal_callback_sigusr2);
137 _ecore_signal_callback_set(SIGHUP, _ecore_signal_callback_sighup);
138 _ecore_signal_callback_set(SIGQUIT, _ecore_signal_callback_sigquit);
139 _ecore_signal_callback_set(SIGINT, _ecore_signal_callback_sigint);
140 _ecore_signal_callback_set(SIGTERM, _ecore_signal_callback_sigterm);
141#ifdef SIGPWR
142 _ecore_signal_callback_set(SIGPWR, _ecore_signal_callback_sigpwr);
143#endif
144} 124}
145 125
146void 126static void
147_ecore_signal_received_process(Eo *obj, Efl_Loop_Data *pd) 127_ecore_signal_cb_del(void *data EINA_UNUSED, const Efl_Event *event)
148{ 128{
149 while (_ecore_signal_count_get(obj, pd)) _ecore_signal_call(obj, pd); 129 if (event->object == sig_pipe_handler) sig_pipe_handler = NULL;
150} 130}
151 131
152int 132EFL_CALLBACKS_ARRAY_DEFINE(_event_watch,
153_ecore_signal_count_get(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd EINA_UNUSED) 133 { EFL_LOOP_HANDLER_EVENT_READ, _ecore_signal_cb_read },
134 { EFL_EVENT_DEL, _ecore_signal_cb_del });
135
136static void
137_ecore_signal_callback(int sig, siginfo_t *si, void *foo EINA_UNUSED)
154{ 138{
155 return sig_count; 139 Signal_Data sdata;
140
141 sdata.sig = sig;
142 sdata.info = *si;
143 if (sdata.sig >= 0) write(sig_pipe[1], &sdata, sizeof(sdata));
156} 144}
157 145
158static void 146static void
159_ecore_signal_generic_free(void *data EINA_UNUSED, void *event) 147_ecore_signal_callback_set(int sig, Signal_Handler func)
160{ 148{
161 free(event); 149 struct sigaction sa;
150
151#ifdef ECORE_SIGNAL_THREAD
152 if (eina_thread_self() != sig_thread)
153 {
154 fprintf(stderr, "Ecore sig handler NOT called from sigwatcher thread\n");
155 }
156#endif
157 sa.sa_sigaction = func;
158 sa.sa_flags = SA_RESTART | SA_SIGINFO;
159 sigemptyset(&sa.sa_mask);
160 sigaction(sig, &sa, NULL);
162} 161}
163 162
164void 163static void
165_ecore_signal_call(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED) 164_signalhandler_setup(void)
166{ 165{
167 volatile sig_atomic_t n; 166 sigset_t newset;
168 sigset_t oldset, newset; 167
169 int tot; 168 _ecore_signal_callback_set(SIGPIPE, _ecore_signal_callback);
169 _ecore_signal_callback_set(SIGALRM, _ecore_signal_callback);
170 _ecore_signal_callback_set(SIGCHLD, _ecore_signal_callback);
171 _ecore_signal_callback_set(SIGUSR1, _ecore_signal_callback);
172 _ecore_signal_callback_set(SIGUSR2, _ecore_signal_callback);
173 _ecore_signal_callback_set(SIGHUP, _ecore_signal_callback);
174 _ecore_signal_callback_set(SIGQUIT, _ecore_signal_callback);
175 _ecore_signal_callback_set(SIGINT, _ecore_signal_callback);
176 _ecore_signal_callback_set(SIGTERM, _ecore_signal_callback);
177#ifdef SIGPWR
178 _ecore_signal_callback_set(SIGPWR, _ecore_signal_callback);
179#endif
170 180
171 if (sig_count == 0) return; 181#ifndef _WIN32
172 eina_evlog("+signals", NULL, 0.0, NULL);
173 sigemptyset(&newset); 182 sigemptyset(&newset);
174 sigaddset(&newset, SIGPIPE); 183 sigaddset(&newset, SIGPIPE);
175 sigaddset(&newset, SIGALRM); 184 sigaddset(&newset, SIGALRM);
@@ -180,430 +189,138 @@ _ecore_signal_call(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
180 sigaddset(&newset, SIGQUIT); 189 sigaddset(&newset, SIGQUIT);
181 sigaddset(&newset, SIGINT); 190 sigaddset(&newset, SIGINT);
182 sigaddset(&newset, SIGTERM); 191 sigaddset(&newset, SIGTERM);
183#ifdef SIGPWR 192# ifdef SIGPWR
184 sigaddset(&newset, SIGPWR); 193 sigaddset(&newset, SIGPWR);
194# endif
195 pthread_sigmask(SIG_UNBLOCK, &newset, NULL);
185#endif 196#endif
186 sigprocmask(SIG_BLOCK, &newset, &oldset); 197}
187 if (sigchld_count > MAXSIGQ)
188 WRN("%"PRIdSIGATOMIC" SIGCHLD in queue. max queue size %i. losing "
189 "siginfo for extra signals.", sigchld_count, MAXSIGQ);
190 tot = sigchld_count + sigusr1_count + sigusr2_count +
191 sighup_count + sigquit_count + sigint_count + sigterm_count
192#ifdef SIGPWR
193 + sigpwr_count
194#endif
195 ;
196
197 if (sig_count != tot)
198 {
199 ERR("sig_count (%"PRIdSIGATOMIC") != actual totals (%i) ",
200 sig_count, tot);
201 sig_count = tot;
202 }
203
204 for (n = 0; n < sigchld_count; n++)
205 {
206 pid_t pid;
207 int status;
208
209 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
210 {
211 Ecore_Exe_Event_Del *e;
212
213 /* FIXME: If this process is set respawn, respawn with a suitable backoff
214 * period for those that need too much respawning.
215 */
216 e = _ecore_exe_event_del_new();
217 if (e)
218 {
219 if (WIFEXITED(status))
220 {
221 e->exit_code = WEXITSTATUS(status);
222 e->exited = 1;
223 }
224 else if (WIFSIGNALED(status))
225 {
226 e->exit_signal = WTERMSIG(status);
227 e->signalled = 1;
228 }
229 e->pid = pid;
230 e->exe = _ecore_exe_find(pid);
231
232 if ((n < MAXSIGQ) && (sigchld_info[n].si_signo))
233 e->data = sigchld_info[n]; /* No need to clone this. */
234
235 if ((e->exe) &&
236 (ecore_exe_flags_get(e->exe) &
237 (ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR)))
238 {
239 /* We want to report the Last Words of the exe, so delay this event.
240 * This is twice as relevant for stderr.
241 * There are three possibilities here -
242 * 1 There are no Last Words.
243 * 2 There are Last Words, they are not ready to be read.
244 * 3 There are Last Words, they are ready to be read.
245 *
246 * For 1 we don't want to delay, for 3 we want to delay.
247 * 2 is the problem. If we check for data now and there
248 * is none, then there is no way to differentiate 1 and 2.
249 * If we don't delay, we may loose data, but if we do delay,
250 * there may not be data and the exit event never gets sent.
251 *
252 * Any way you look at it, there has to be some time passed
253 * before the exit event gets sent. So the strategy here is
254 * to setup a timer event that will send the exit event after
255 * an arbitrary, but brief, time.
256 *
257 * This is probably paranoid, for the less paraniod, we could
258 * check to see for Last Words, and only delay if there are any.
259 * This has it's own set of problems.
260 */
261 Efl_Loop_Timer *doomsday_clock =
262 _ecore_exe_doomsday_clock_get(e->exe);
263 efl_del(doomsday_clock);
264 doomsday_clock =
265 efl_add(EFL_LOOP_TIMER_CLASS, obj,
266 efl_loop_timer_interval_set(efl_added, 0.1),
267 efl_event_callback_add
268 (efl_added, EFL_LOOP_TIMER_EVENT_TICK,
269 _ecore_signal_exe_exit_delay, e));
270 _ecore_exe_doomsday_clock_set(e->exe, doomsday_clock);
271 }
272 else
273 {
274 ecore_event_add(ECORE_EXE_EVENT_DEL, e,
275 _ecore_exe_event_del_free, NULL);
276 }
277 }
278 }
279 sig_count--;
280 }
281 sigchld_count = 0;
282
283 if (sigusr1_count > MAXSIGQ)
284 WRN("%"PRIdSIGATOMIC" SIGUSR1 in queue. max queue size %i. losing "
285 "siginfo for extra signals.", sigusr1_count, MAXSIGQ);
286 for (n = 0; n < sigusr1_count; n++)
287 {
288 Ecore_Event_Signal_User *e;
289
290 e = _ecore_event_signal_user_new();
291 if (e)
292 {
293 e->number = 1;
294
295 if ((n < MAXSIGQ) && (sigusr1_info[n].si_signo))
296 e->data = sigusr1_info[n];
297
298 ecore_event_add(ECORE_EVENT_SIGNAL_USER, e,
299 _ecore_signal_generic_free, NULL);
300 }
301 sig_count--;
302 }
303 sigusr1_count = 0;
304
305 if (sigusr2_count > MAXSIGQ)
306 WRN("%"PRIdSIGATOMIC" SIGUSR2 in queue. max queue size %i. losing "
307 "siginfo for extra signals.", sigusr2_count, MAXSIGQ);
308 for (n = 0; n < sigusr2_count; n++)
309 {
310 Ecore_Event_Signal_User *e;
311
312 e = _ecore_event_signal_user_new();
313 if (e)
314 {
315 e->number = 2;
316
317 if ((n < MAXSIGQ) && (sigusr2_info[n].si_signo))
318 e->data = sigusr2_info[n];
319
320 ecore_event_add(ECORE_EVENT_SIGNAL_USER, e,
321 _ecore_signal_generic_free, NULL);
322 }
323 sig_count--;
324 }
325 sigusr2_count = 0;
326
327 if (sighup_count > MAXSIGQ)
328 WRN("%"PRIdSIGATOMIC" SIGHUP in queue. max queue size %i. losing "
329 "siginfo for extra signals.", sighup_count, MAXSIGQ);
330 for (n = 0; n < sighup_count; n++)
331 {
332 Ecore_Event_Signal_Hup *e;
333
334 e = _ecore_event_signal_hup_new();
335 if (e)
336 {
337 if ((n < MAXSIGQ) && (sighup_info[n].si_signo))
338 e->data = sighup_info[n];
339
340 ecore_event_add(ECORE_EVENT_SIGNAL_HUP, e,
341 _ecore_signal_generic_free, NULL);
342 }
343 sig_count--;
344 }
345 sighup_count = 0;
346
347 if (sigquit_count > MAXSIGQ)
348 WRN("%"PRIdSIGATOMIC" SIGQUIT in queue. max queue size %i. losing "
349 "siginfo for extra signals.", sigquit_count, MAXSIGQ);
350 for (n = 0; n < sigquit_count; n++)
351 {
352 Ecore_Event_Signal_Exit *e;
353
354 e = _ecore_event_signal_exit_new();
355 if (e)
356 {
357 e->quit = 1;
358
359 if ((n < MAXSIGQ) && (sigquit_info[n].si_signo))
360 e->data = sigquit_info[n];
361
362 ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
363 _ecore_signal_generic_free, NULL);
364 }
365 sig_count--;
366 }
367 sigquit_count = 0;
368
369 if (sigint_count > MAXSIGQ)
370 WRN("%"PRIdSIGATOMIC" SIGINT in queue. max queue size %i. losing "
371 "siginfo for extra signals.", sigint_count, MAXSIGQ);
372 for (n = 0; n < sigint_count; n++)
373 {
374 Ecore_Event_Signal_Exit *e;
375
376 e = _ecore_event_signal_exit_new();
377 if (e)
378 {
379 e->interrupt = 1;
380
381 if ((n < MAXSIGQ) && (sigint_info[n].si_signo))
382 e->data = sigint_info[n];
383 198
384 ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, 199static void *
385 _ecore_signal_generic_free, NULL); 200_ecore_signal_thread_watcher(void *data EINA_UNUSED, Eina_Thread t)
386 } 201{
387 sig_count--; 202 eina_thread_cancellable_set(EINA_FALSE, NULL);
388 } 203 eina_thread_name_set(t, "Esigwatcher");
389 sigint_count = 0; 204 _signalhandler_setup();
205 for (;;) pause();
206 return NULL;
207}
390 208
391 if (sigterm_count > MAXSIGQ) 209static void
392 WRN("%"PRIdSIGATOMIC" SIGTERM in queue. max queue size %i. losing " 210_ecore_signal_pipe_init(void)
393 "siginfo for extra signals.", sigterm_count, MAXSIGQ); 211{
394 for (n = 0; n < sigterm_count; n++) 212 if (sig_pipe[0] == -1)
395 { 213 {
396 Ecore_Event_Signal_Exit *e; 214 if (pipe(sig_pipe) != 0)
397
398 e = _ecore_event_signal_exit_new();
399 if (e)
400 { 215 {
401 e->terminate = 1; 216 sig_pipe[0] = -1;
402 217 return;
403 if ((n < MAXSIGQ) && (sigterm_info[n].si_signo))
404 e->data = sigterm_info[n];
405
406 ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
407 _ecore_signal_generic_free, NULL);
408 } 218 }
409 sig_count--; 219 eina_file_close_on_exec(sig_pipe[0], EINA_TRUE);
220 eina_file_close_on_exec(sig_pipe[1], EINA_TRUE);
221 fcntl(sig_pipe[0], F_SETFL, O_NONBLOCK);
410 } 222 }
411 sigterm_count = 0; 223#ifdef ECORE_SIGNAL_THREAD
412 224 if (!sig_thread_exists)
413#ifdef SIGPWR
414 if (sigpwr_count > MAXSIGQ)
415 WRN("%"PRIdSIGATOMIC" SIGPWR in queue. max queue size %i. losing "
416 "siginfo for extra signals.", sigpwr_count, MAXSIGQ);
417 for (n = 0; n < sigpwr_count; n++)
418 { 225 {
419 Ecore_Event_Signal_Power *e; 226 if (!eina_thread_create(&sig_thread, EINA_THREAD_NORMAL,
420 227 -1, _ecore_signal_thread_watcher, NULL))
421 e = _ecore_event_signal_power_new();
422 if (e)
423 { 228 {
424 if ((n < MAXSIGQ) && (sigpwr_info[n].si_signo)) 229 close(sig_pipe[0]);
425 e->data = sigpwr_info[n]; 230 close(sig_pipe[1]);
426 231 sig_pipe[0] = -1;
427 ecore_event_add(ECORE_EVENT_SIGNAL_POWER, e, 232 sig_pipe[1] = -1;
428 _ecore_signal_generic_free, NULL); 233 return;
429 } 234 }
430 sig_count--; 235 sig_thread_exists = EINA_TRUE;
431 } 236 }
432 sigpwr_count = 0; 237#else
238 _signalhandler_setup();
433#endif 239#endif
434 sig_count = 0; 240 if (!sig_pipe_handler)
435 241 sig_pipe_handler =
436 sigprocmask(SIG_SETMASK, &oldset, NULL); 242 efl_add(EFL_LOOP_HANDLER_CLASS, ML_OBJ,
437 eina_evlog("-signals", NULL, 0.0, NULL); 243 efl_loop_handler_fd_set(efl_added, sig_pipe[0]),
244 efl_loop_handler_active_set(efl_added, EFL_LOOP_HANDLER_FLAGS_READ),
245 efl_event_callback_array_add(efl_added, _event_watch(), NULL));
438} 246}
439 247
440static void 248static void
441_ecore_signal_callback_set(int sig, 249_ecore_signal_pipe_shutdown(void)
442 Signal_Handler func)
443{ 250{
444 struct sigaction sa; 251 if (sig_pipe[0] != -1)
445
446 sa.sa_sigaction = func;
447 sa.sa_flags = SA_RESTART | SA_SIGINFO;
448 sigemptyset(&sa.sa_mask);
449 sigaction(sig, &sa, NULL);
450}
451
452static void
453_ecore_signal_callback_ignore(int sig EINA_UNUSED,
454 siginfo_t *si EINA_UNUSED,
455 void *foo EINA_UNUSED)
456{
457}
458
459static void
460_ecore_signal_callback_sigchld(int sig EINA_UNUSED,
461 siginfo_t *si,
462 void *foo EINA_UNUSED)
463{
464 volatile sig_atomic_t n;
465 n = sigchld_count;
466 if (n < MAXSIGQ)
467 { 252 {
468 if (si) 253 close(sig_pipe[0]);
469 sigchld_info[n] = *si; 254 close(sig_pipe[1]);
470 else 255 sig_pipe[0] = -1;
471 sigchld_info[n].si_signo = 0; 256 sig_pipe[1] = -1;
472 } 257 }
473 258 if (sig_pipe_handler)
474 sigchld_count++;
475 sig_count++;
476}
477
478static void
479_ecore_signal_callback_sigusr1(int sig EINA_UNUSED,
480 siginfo_t *si,
481 void *foo EINA_UNUSED)
482{
483 volatile sig_atomic_t n;
484 n = sigusr1_count;
485 if (n < MAXSIGQ)
486 { 259 {
487 if (si) 260 efl_del(sig_pipe_handler);
488 sigusr1_info[n] = *si; 261 sig_pipe_handler = NULL;
489 else
490 sigusr1_info[n].si_signo = 0;
491 } 262 }
492 sigusr1_count++;
493 sig_count++;
494} 263}
495 264
496static void 265static void
497_ecore_signal_callback_sigusr2(int sig EINA_UNUSED, 266_ecore_signal_cb_fork(void *data EINA_UNUSED)
498 siginfo_t *si,
499 void *foo EINA_UNUSED)
500{ 267{
501 volatile sig_atomic_t n; 268 _ecore_signal_pipe_shutdown();
502 n = sigusr2_count; 269#ifdef ECORE_SIGNAL_THREAD
503 if (n < MAXSIGQ) 270 sig_thread_exists = EINA_FALSE;
504 { 271#endif
505 if (si) 272 _ecore_signal_pipe_init();
506 sigusr2_info[n] = *si;
507 else
508 sigusr2_info[n].si_signo = 0;
509 }
510 sigusr2_count++;
511 sig_count++;
512} 273}
513 274
514static void 275void
515_ecore_signal_callback_sighup(int sig EINA_UNUSED, 276_ecore_signal_init(void)
516 siginfo_t *si,
517 void *foo EINA_UNUSED)
518{ 277{
519 volatile sig_atomic_t n; 278#ifndef _WIN32
520 n = sighup_count; 279 sigset_t newset;
521 if (n < MAXSIGQ)
522 {
523 if (si)
524 sighup_info[n] = *si;
525 else
526 sighup_info[n].si_signo = 0;
527 }
528 sighup_count++;
529 sig_count++;
530}
531 280
532static void 281 sigemptyset(&newset);
533_ecore_signal_callback_sigquit(int sig EINA_UNUSED, 282 sigaddset(&newset, SIGPIPE);
534 siginfo_t *si, 283 sigaddset(&newset, SIGALRM);
535 void *foo EINA_UNUSED) 284 sigaddset(&newset, SIGCHLD);
536{ 285 sigaddset(&newset, SIGUSR1);
537 volatile sig_atomic_t n; 286 sigaddset(&newset, SIGUSR2);
538 n = sigquit_count; 287 sigaddset(&newset, SIGHUP);
539 if (n < MAXSIGQ) 288 sigaddset(&newset, SIGQUIT);
540 { 289 sigaddset(&newset, SIGINT);
541 if (si) 290 sigaddset(&newset, SIGTERM);
542 sigquit_info[n] = *si; 291# ifdef SIGPWR
543 else 292 sigaddset(&newset, SIGPWR);
544 sigquit_info[n].si_signo = 0; 293# endif
545 } 294 pthread_sigmask(SIG_BLOCK, &newset, NULL);
546 sigquit_count++; 295#endif
547 sig_count++; 296 _ecore_signal_pipe_init();
297 ecore_fork_reset_callback_add(_ecore_signal_cb_fork, NULL);
548} 298}
549 299
550static void 300void
551_ecore_signal_callback_sigint(int sig EINA_UNUSED, 301_ecore_signal_shutdown(void)
552 siginfo_t *si,
553 void *foo EINA_UNUSED)
554{ 302{
555 volatile sig_atomic_t n; 303 ecore_fork_reset_callback_del(_ecore_signal_cb_fork, NULL);
556 n = sigint_count; 304 _ecore_signal_pipe_shutdown();
557 if (n < MAXSIGQ) 305 // we probably should restore.. but not a good idea
558 { 306 // pthread_sigmask(SIG_SETMASK, &sig_oldset, NULL);
559 if (si)
560 sigint_info[n] = *si;
561 else
562 sigint_info[n].si_signo = 0;
563 }
564 sigint_count++;
565 sig_count++;
566} 307}
567 308
568static void 309void
569_ecore_signal_callback_sigterm(int sig EINA_UNUSED, 310_ecore_signal_received_process(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd EINA_UNUSED)
570 siginfo_t *si,
571 void *foo EINA_UNUSED)
572{ 311{
573 volatile sig_atomic_t n; 312 // do nothing - the efl loop handler read event will handle it
574 n = sigterm_count;
575 if (n < MAXSIGQ)
576 {
577 if (si)
578 sigterm_info[n] = *si;
579 else
580 sigterm_info[n].si_signo = 0;
581 }
582 sigterm_count++;
583 sig_count++;
584} 313}
585 314
586#ifdef SIGPWR 315int
587static void 316_ecore_signal_count_get(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd EINA_UNUSED)
588_ecore_signal_callback_sigpwr(int sig EINA_UNUSED,
589 siginfo_t *si,
590 void *foo EINA_UNUSED)
591{ 317{
592 volatile sig_atomic_t n; 318 // we will always have 0 signals be3cause they will instead be read from
593 n = sigpwr_count; 319 // a pipe fd and placed in a queue/list that
594 if (n < MAXSIGQ) 320 // _ecore_signal_received_process() will then walk and process/do
595 { 321 return 0;
596 if (si)
597 sigpwr_info[n] = *si;
598 else
599 sigpwr_info[n].si_signo = 0;
600 }
601 sigpwr_count++;
602 sig_count++;
603} 322}
604 323
605#endif
606
607static void 324static void
608_ecore_signal_exe_exit_delay(void *data, const Efl_Event *event) 325_ecore_signal_exe_exit_delay(void *data, const Efl_Event *event)
609{ 326{
@@ -616,3 +333,77 @@ _ecore_signal_exe_exit_delay(void *data, const Efl_Event *event)
616 efl_del(event->object); 333 efl_del(event->object);
617} 334}
618 335
336static void
337_ecore_signal_waitpid(Eina_Bool once, siginfo_t info)
338{
339 pid_t pid;
340 int status;
341
342 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
343 {
344 Ecore_Exe_Event_Del *e = _ecore_exe_event_del_new();
345
346 //FIXME: If this process is set respawn, respawn with a suitable backoff
347 // period for those that need too much respawning.
348 if (e)
349 {
350 if (WIFEXITED(status))
351 {
352 e->exit_code = WEXITSTATUS(status);
353 e->exited = 1;
354 }
355 else if (WIFSIGNALED(status))
356 {
357 e->exit_signal = WTERMSIG(status);
358 e->signalled = 1;
359 }
360 e->pid = pid;
361 e->exe = _ecore_exe_find(pid);
362 e->data = info; // No need to clone this.
363 if ((e->exe) &&
364 (ecore_exe_flags_get(e->exe) &
365 (ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR)))
366 {
367 /* We want to report the Last Words of the exe, so delay this event.
368 * This is twice as relevant for stderr.
369 * There are three possibilities here -
370 * 1 There are no Last Words.
371 * 2 There are Last Words, they are not ready to be read.
372 * 3 There are Last Words, they are ready to be read.
373 *
374 * For 1 we don't want to delay, for 3 we want to delay.
375 * 2 is the problem. If we check for data now and there
376 * is none, then there is no way to differentiate 1 and 2.
377 * If we don't delay, we may loose data, but if we do delay,
378 * there may not be data and the exit event never gets sent.
379 *
380 * Any way you look at it, there has to be some time passed
381 * before the exit event gets sent. So the strategy here is
382 * to setup a timer event that will send the exit event after
383 * an arbitrary, but brief, time.
384 *
385 * This is probably paranoid, for the less paraniod, we could
386 * check to see for Last Words, and only delay if there are any.
387 * This has it's own set of problems. */
388 efl_del(_ecore_exe_doomsday_clock_get(e->exe));
389
390 Efl_Loop_Timer *doomsday_clock =
391 efl_add(EFL_LOOP_TIMER_CLASS, ML_OBJ,
392 efl_loop_timer_interval_set(efl_added, 0.1),
393 efl_event_callback_add
394 (efl_added, EFL_LOOP_TIMER_EVENT_TICK,
395 _ecore_signal_exe_exit_delay, e));
396 _ecore_exe_doomsday_clock_set(e->exe, doomsday_clock);
397 }
398 else ecore_event_add(ECORE_EXE_EVENT_DEL, e,
399 _ecore_exe_event_del_free, NULL);
400 }
401 if (once) break;
402 }
403}
404
405static void
406_ecore_signal_generic_free(void *data EINA_UNUSED, void *event)
407{
408 free(event);
409}