Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore / ecore_signal.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <sys/wait.h>
8 #include <signal.h>
9 #include <unistd.h>
10 #include <assert.h>
11
12 #include "Ecore.h"
13 #include "ecore_private.h"
14
15 /* make mono happy - this is evil though... */
16 #undef SIGPWR
17 /* valgrind in some versions/setups uses SIGRT's... hmmm */
18
19 typedef void (*Signal_Handler)(int sig, siginfo_t *si, void *foo);
20
21 static void _ecore_signal_callback_set(int            sig,
22                                        Signal_Handler func);
23 static void _ecore_signal_callback_ignore(int        sig,
24                                           siginfo_t *si,
25                                           void      *foo);
26 static void _ecore_signal_callback_sigchld(int        sig,
27                                            siginfo_t *si,
28                                            void      *foo);
29 static void _ecore_signal_callback_sigusr1(int        sig,
30                                            siginfo_t *si,
31                                            void      *foo);
32 static void _ecore_signal_callback_sigusr2(int        sig,
33                                            siginfo_t *si,
34                                            void      *foo);
35 static void _ecore_signal_callback_sighup(int        sig,
36                                           siginfo_t *si,
37                                           void      *foo);
38 static void _ecore_signal_callback_sigquit(int        sig,
39                                            siginfo_t *si,
40                                            void      *foo);
41 static void _ecore_signal_callback_sigint(int        sig,
42                                           siginfo_t *si,
43                                           void      *foo);
44 static void _ecore_signal_callback_sigterm(int        sig,
45                                            siginfo_t *si,
46                                            void      *foo);
47 #ifdef SIGPWR
48 static void _ecore_signal_callback_sigpwr(int        sig,
49                                           siginfo_t *si,
50                                           void      *foo);
51 #endif
52
53 static Eina_Bool _ecore_signal_exe_exit_delay(void *data);
54
55 //#define MAXSIGQ 256 // 32k
56 #define MAXSIGQ 64 // 8k
57
58 static volatile sig_atomic_t sig_count = 0;
59 static volatile sig_atomic_t sigchld_count = 0;
60 static volatile sig_atomic_t sigusr1_count = 0;
61 static volatile sig_atomic_t sigusr2_count = 0;
62 static volatile sig_atomic_t sighup_count = 0;
63 static volatile sig_atomic_t sigquit_count = 0;
64 static volatile sig_atomic_t sigint_count = 0;
65 static volatile sig_atomic_t sigterm_count = 0;
66 #ifdef SIGPWR
67 static volatile sig_atomic_t sigpwr_count = 0;
68 #endif
69
70 static volatile siginfo_t sigchld_info[MAXSIGQ];
71 static volatile siginfo_t sigusr1_info[MAXSIGQ];
72 static volatile siginfo_t sigusr2_info[MAXSIGQ];
73 static volatile siginfo_t sighup_info[MAXSIGQ];
74 static volatile siginfo_t sigquit_info[MAXSIGQ];
75 static volatile siginfo_t sigint_info[MAXSIGQ];
76 static volatile siginfo_t sigterm_info[MAXSIGQ];
77 #ifdef SIGPWR
78 static volatile siginfo_t sigpwr_info[MAXSIGQ];
79 #endif
80
81 void
82 _ecore_signal_shutdown(void)
83 {
84    _ecore_signal_callback_set(SIGPIPE, (Signal_Handler)SIG_DFL);
85    _ecore_signal_callback_set(SIGALRM, (Signal_Handler)SIG_DFL);
86    _ecore_signal_callback_set(SIGCHLD, (Signal_Handler)SIG_DFL);
87    _ecore_signal_callback_set(SIGUSR1, (Signal_Handler)SIG_DFL);
88    _ecore_signal_callback_set(SIGUSR2, (Signal_Handler)SIG_DFL);
89    _ecore_signal_callback_set(SIGHUP, (Signal_Handler)SIG_DFL);
90    _ecore_signal_callback_set(SIGQUIT, (Signal_Handler)SIG_DFL);
91    _ecore_signal_callback_set(SIGINT, (Signal_Handler)SIG_DFL);
92    _ecore_signal_callback_set(SIGTERM, (Signal_Handler)SIG_DFL);
93 #ifdef SIGPWR
94    _ecore_signal_callback_set(SIGPWR, (Signal_Handler)SIG_DFL);
95    sigpwr_count = 0;
96 #endif
97    sigchld_count = 0;
98    sigusr1_count = 0;
99    sigusr2_count = 0;
100    sighup_count = 0;
101    sigquit_count = 0;
102    sigint_count = 0;
103    sigterm_count = 0;
104    sig_count = 0;
105 }
106
107 void
108 _ecore_signal_init(void)
109 {
110    _ecore_signal_callback_set(SIGPIPE, _ecore_signal_callback_ignore);
111    _ecore_signal_callback_set(SIGALRM, _ecore_signal_callback_ignore);
112    _ecore_signal_callback_set(SIGCHLD, _ecore_signal_callback_sigchld);
113    _ecore_signal_callback_set(SIGUSR1, _ecore_signal_callback_sigusr1);
114    _ecore_signal_callback_set(SIGUSR2, _ecore_signal_callback_sigusr2);
115    _ecore_signal_callback_set(SIGHUP, _ecore_signal_callback_sighup);
116    _ecore_signal_callback_set(SIGQUIT, _ecore_signal_callback_sigquit);
117    _ecore_signal_callback_set(SIGINT, _ecore_signal_callback_sigint);
118    _ecore_signal_callback_set(SIGTERM, _ecore_signal_callback_sigterm);
119 #ifdef SIGPWR
120    _ecore_signal_callback_set(SIGPWR, _ecore_signal_callback_sigpwr);
121 #endif
122 }
123
124 void
125 _ecore_signal_received_process(void)
126 {
127    while (_ecore_signal_count_get()) _ecore_signal_call();
128 }
129
130 int
131 _ecore_signal_count_get(void)
132 {
133    return sig_count;
134 }
135
136 static void
137 _ecore_signal_generic_free(void *data __UNUSED__,
138                            void *event)
139 {
140    free(event);
141 }
142
143 void
144 _ecore_signal_call(void)
145 {
146    volatile sig_atomic_t n;
147    sigset_t oldset, newset;
148    int tot;
149
150    if (sig_count == 0) return;
151    sigemptyset(&newset);
152    sigaddset(&newset, SIGPIPE);
153    sigaddset(&newset, SIGALRM);
154    sigaddset(&newset, SIGCHLD);
155    sigaddset(&newset, SIGUSR1);
156    sigaddset(&newset, SIGUSR2);
157    sigaddset(&newset, SIGHUP);
158    sigaddset(&newset, SIGQUIT);
159    sigaddset(&newset, SIGINT);
160    sigaddset(&newset, SIGTERM);
161 #ifdef SIGPWR
162    sigaddset(&newset, SIGPWR);
163 #endif
164    sigprocmask(SIG_BLOCK, &newset, &oldset);
165    if (sigchld_count > MAXSIGQ)
166      WRN("%i SIGCHLD in queue. max queue size %i. losing "
167          "siginfo for extra signals.", sigchld_count, MAXSIGQ);
168    tot = sigchld_count + sigusr1_count + sigusr2_count +
169      sighup_count + sigquit_count + sigint_count + sigterm_count
170 #ifdef SIGPWR
171      + sigpwr_count
172 #endif
173      ;
174    
175    if (sig_count != tot)
176      {
177         ERR("sig_count (%i) != actual totals (%i) ", sig_count, tot);
178         sig_count = tot;
179      }
180    
181    for (n = 0; n < sigchld_count; n++)
182      {
183         pid_t pid;
184         int status;
185
186         while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
187           {
188              Ecore_Exe_Event_Del *e;
189
190              /* FIXME: If this process is set respawn, respawn with a suitable backoff
191               * period for those that need too much respawning.
192               */
193              e = _ecore_exe_event_del_new();
194              if (e)
195                {
196                   if (WIFEXITED(status))
197                     {
198                        e->exit_code = WEXITSTATUS(status);
199                        e->exited = 1;
200                     }
201                   else if (WIFSIGNALED(status))
202                     {
203                        e->exit_signal = WTERMSIG(status);
204                        e->signalled = 1;
205                     }
206                   e->pid = pid;
207                   e->exe = _ecore_exe_find(pid);
208
209                   if ((n < MAXSIGQ) && (sigchld_info[n].si_signo))
210                     e->data = sigchld_info[n];  /* No need to clone this. */
211
212                   if ((e->exe) && (ecore_exe_flags_get(e->exe) & (ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR)))
213                     {
214      /* We want to report the Last Words of the exe, so delay this event.
215       * This is twice as relevant for stderr.
216       * There are three possibilities here -
217       *  1 There are no Last Words.
218       *  2 There are Last Words, they are not ready to be read.
219       *  3 There are Last Words, they are ready to be read.
220       *
221       * For 1 we don't want to delay, for 3 we want to delay.
222       * 2 is the problem.  If we check for data now and there
223       * is none, then there is no way to differentiate 1 and 2.
224       * If we don't delay, we may loose data, but if we do delay,
225       * there may not be data and the exit event never gets sent.
226       *
227       * Any way you look at it, there has to be some time passed
228       * before the exit event gets sent.  So the strategy here is
229       * to setup a timer event that will send the exit event after
230       * an arbitrary, but brief, time.
231       *
232       * This is probably paranoid, for the less paraniod, we could
233       * check to see for Last Words, and only delay if there are any.
234       * This has it's own set of problems.
235       */
236                          Ecore_Timer *doomsday_clock;
237
238                          doomsday_clock = _ecore_exe_doomsday_clock_get(e->exe);
239                          IF_FN_DEL(ecore_timer_del, doomsday_clock);
240                          _ecore_unlock();
241                          doomsday_clock = ecore_timer_add
242                              (0.1, _ecore_signal_exe_exit_delay, e);
243                          _ecore_lock();
244                          _ecore_exe_doomsday_clock_set(e->exe, doomsday_clock);
245                     }
246                   else
247                     {
248                        _ecore_event_add(ECORE_EXE_EVENT_DEL, e,
249                                         _ecore_exe_event_del_free, NULL);
250                     }
251                }
252           }
253         sig_count--;
254      }
255    sigchld_count = 0;
256
257    if (sigusr1_count > MAXSIGQ)
258      WRN("%i SIGUSR1 in queue. max queue size %i. losing "
259          "siginfo for extra signals.", sigusr1_count, MAXSIGQ);
260    for (n = 0; n < sigusr1_count; n++)
261      {
262         Ecore_Event_Signal_User *e;
263
264         e = _ecore_event_signal_user_new();
265         if (e)
266           {
267              e->number = 1;
268
269              if ((n < MAXSIGQ) && (sigusr1_info[n].si_signo))
270                e->data = sigusr1_info[n];
271
272              _ecore_event_add(ECORE_EVENT_SIGNAL_USER, e,
273                               _ecore_signal_generic_free, NULL);
274           }
275         sig_count--;
276      }
277    sigusr1_count = 0;
278
279    if (sigusr2_count > MAXSIGQ)
280      WRN("%i SIGUSR2 in queue. max queue size %i. losing "
281          "siginfo for extra signals.", sigusr2_count, MAXSIGQ);
282    for (n = 0; n < sigusr2_count; n++)
283      {
284         Ecore_Event_Signal_User *e;
285
286         e = _ecore_event_signal_user_new();
287         if (e)
288           {
289              e->number = 2;
290
291              if ((n < MAXSIGQ) && (sigusr2_info[n].si_signo))
292                e->data = sigusr2_info[n];
293
294              _ecore_event_add(ECORE_EVENT_SIGNAL_USER, e,
295                               _ecore_signal_generic_free, NULL);
296           }
297         sig_count--;
298      }
299    sigusr2_count = 0;
300
301    if (sighup_count > MAXSIGQ)
302      WRN("%i SIGHUP in queue. max queue size %i. losing "
303          "siginfo for extra signals.", sighup_count, MAXSIGQ);
304    for (n = 0; n < sighup_count; n++)
305      {
306         Ecore_Event_Signal_Hup *e;
307
308         e = _ecore_event_signal_hup_new();
309         if (e)
310           {
311              if ((n < MAXSIGQ) && (sighup_info[n].si_signo))
312                e->data = sighup_info[n];
313
314              _ecore_event_add(ECORE_EVENT_SIGNAL_HUP, e,
315                               _ecore_signal_generic_free, NULL);
316           }
317         sig_count--;
318      }
319    sighup_count = 0;
320
321    if (sigquit_count > MAXSIGQ)
322      WRN("%i SIGQUIT in queue. max queue size %i. losing "
323          "siginfo for extra signals.", sigquit_count, MAXSIGQ);
324    for (n = 0; n < sigquit_count; n++)
325      {
326         Ecore_Event_Signal_Exit *e;
327
328         e = _ecore_event_signal_exit_new();
329         if (e)
330           {
331              e->quit = 1;
332
333              if ((n < MAXSIGQ) && (sigquit_info[n].si_signo))
334                e->data = sigquit_info[n];
335
336              _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
337                               _ecore_signal_generic_free, NULL);
338           }
339         sig_count--;
340      }
341    sigquit_count = 0;
342
343    if (sigint_count > MAXSIGQ)
344      WRN("%i SIGINT in queue. max queue size %i. losing "
345          "siginfo for extra signals.", sigint_count, MAXSIGQ);
346    for (n = 0; n < sigint_count; n++)
347      {
348         Ecore_Event_Signal_Exit *e;
349
350         e = _ecore_event_signal_exit_new();
351         if (e)
352           {
353              e->interrupt = 1;
354
355              if ((n < MAXSIGQ) && (sigint_info[n].si_signo))
356                e->data = sigint_info[n];
357
358              _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
359                               _ecore_signal_generic_free, NULL);
360           }
361         sig_count--;
362      }
363    sigint_count = 0;
364
365    if (sigterm_count > MAXSIGQ)
366      WRN("%i SIGTERM in queue. max queue size %i. losing "
367          "siginfo for extra signals.", sigterm_count, MAXSIGQ);
368    for (n = 0; n < sigterm_count; n++)
369      {
370         Ecore_Event_Signal_Exit *e;
371
372         e = _ecore_event_signal_exit_new();
373         if (e)
374           {
375              e->terminate = 1;
376
377              if ((n < MAXSIGQ) && (sigterm_info[n].si_signo))
378                e->data = sigterm_info[n];
379
380              _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
381                               _ecore_signal_generic_free, NULL);
382           }
383         sig_count--;
384      }
385    sigterm_count = 0;
386
387 #ifdef SIGPWR
388    if (sigpwr_count > MAXSIGQ)
389      WRN("%i SIGPWR in queue. max queue size %i. losing "
390          "siginfo for extra signals.", sigpwr_count, MAXSIGQ);
391    for (n = 0; n < sigpwr_count; n++)
392      {
393         Ecore_Event_Signal_Power *e;
394
395         e = _ecore_event_signal_power_new();
396         if (e)
397           {
398              if ((n < MAXSIGQ) && (sigpwr_info[n].si_signo))
399                e->data = sigpwr_info[n];
400
401              _ecore_event_add(ECORE_EVENT_SIGNAL_POWER, e,
402                               _ecore_signal_generic_free, NULL);
403           }
404         sig_count--;
405      }
406    sigpwr_count = 0;
407 #endif
408    sig_count = 0;
409    
410    sigprocmask(SIG_SETMASK, &oldset, NULL);
411 }
412
413 static void
414 _ecore_signal_callback_set(int            sig,
415                            Signal_Handler func)
416 {
417    struct sigaction sa;
418
419    sa.sa_sigaction = func;
420    sa.sa_flags = SA_RESTART | SA_SIGINFO;
421    sigemptyset(&sa.sa_mask);
422    sigaction(sig, &sa, NULL);
423 }
424
425 static void
426 _ecore_signal_callback_ignore(int        sig __UNUSED__,
427                               siginfo_t *si __UNUSED__,
428                               void      *foo __UNUSED__)
429 {
430 }
431
432 static void
433 _ecore_signal_callback_sigchld(int        sig __UNUSED__,
434                                siginfo_t *si,
435                                void      *foo __UNUSED__)
436 {
437    volatile sig_atomic_t n;
438    n = sigchld_count;
439    if (n < MAXSIGQ)
440      {
441         if (si)
442           sigchld_info[n] = *si;
443         else
444           sigchld_info[n].si_signo = 0;
445      }
446
447    sigchld_count++;
448    sig_count++;
449 }
450
451 static void
452 _ecore_signal_callback_sigusr1(int        sig __UNUSED__,
453                                siginfo_t *si,
454                                void      *foo __UNUSED__)
455 {
456    volatile sig_atomic_t n;
457    n = sigusr1_count;
458    if (n < MAXSIGQ)
459      {
460         if (si)
461           sigusr1_info[n] = *si;
462         else
463           sigusr1_info[n].si_signo = 0;
464      }
465    sigusr1_count++;
466    sig_count++;
467 }
468
469 static void
470 _ecore_signal_callback_sigusr2(int        sig __UNUSED__,
471                                siginfo_t *si,
472                                void      *foo __UNUSED__)
473 {
474    volatile sig_atomic_t n;
475    n = sigusr2_count;
476    if (n < MAXSIGQ)
477      {
478         if (si)
479           sigusr2_info[n] = *si;
480         else
481           sigusr2_info[n].si_signo = 0;
482      }
483    sigusr2_count++;
484    sig_count++;
485 }
486
487 static void
488 _ecore_signal_callback_sighup(int        sig __UNUSED__,
489                               siginfo_t *si,
490                               void      *foo __UNUSED__)
491 {
492    volatile sig_atomic_t n;
493    n = sighup_count;
494    if (n < MAXSIGQ)
495      {
496         if (si)
497           sighup_info[n] = *si;
498         else
499           sighup_info[n].si_signo = 0;
500      }
501    sighup_count++;
502    sig_count++;
503 }
504
505 static void
506 _ecore_signal_callback_sigquit(int        sig __UNUSED__,
507                                siginfo_t *si,
508                                void      *foo __UNUSED__)
509 {
510    volatile sig_atomic_t n;
511    n = sigquit_count;
512    if (n < MAXSIGQ)
513      {
514         if (si)
515           sigquit_info[n] = *si;
516         else
517           sigquit_info[n].si_signo = 0;
518      }
519    sigquit_count++;
520    sig_count++;
521 }
522
523 static void
524 _ecore_signal_callback_sigint(int        sig __UNUSED__,
525                               siginfo_t *si,
526                               void      *foo __UNUSED__)
527 {
528    volatile sig_atomic_t n;
529    n = sigint_count;
530    if (n < MAXSIGQ)
531      {
532         if (si)
533           sigint_info[n] = *si;
534         else
535           sigint_info[n].si_signo = 0;
536      }
537    sigint_count++;
538    sig_count++;
539 }
540
541 static void
542 _ecore_signal_callback_sigterm(int        sig __UNUSED__,
543                                siginfo_t *si,
544                                void      *foo __UNUSED__)
545 {
546    volatile sig_atomic_t n;
547    n = sigterm_count;
548    if (n < MAXSIGQ)
549      {
550         if (si)
551           sigterm_info[n] = *si;
552         else
553           sigterm_info[n].si_signo = 0;
554      }
555    sigterm_count++;
556    sig_count++;
557 }
558
559 #ifdef SIGPWR
560 static void
561 _ecore_signal_callback_sigpwr(int        sig __UNUSED__,
562                               siginfo_t *si,
563                               void      *foo __UNUSED__)
564 {
565    volatile sig_atomic_t n;
566    n = sigpwr_count;
567    if (n < MAXSIGQ)
568      {
569         if (si)
570           sigpwr_info[n] = *si;
571         else
572           sigpwr_info[n].si_signo = 0;
573      }
574    sigpwr_count++;
575    sig_count++;
576 }
577
578 #endif
579
580 static Eina_Bool
581 _ecore_signal_exe_exit_delay(void *data)
582 {
583    Ecore_Exe_Event_Del *e;
584
585    e = data;
586    if (e)
587      {
588         _ecore_exe_doomsday_clock_set(e->exe, NULL);
589         _ecore_event_add(ECORE_EXE_EVENT_DEL, e,
590                          _ecore_exe_event_del_free, NULL);
591      }
592    return ECORE_CALLBACK_CANCEL;
593 }
594