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