IDirectFBSurface: Fix FlipStereo() in secure fusion mode.
[core/DirectFB.git] / lib / direct / signals.c
1 /*
2    (c) Copyright 2001-2008  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4
5    All rights reserved.
6
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or (at your option) any later version.
17
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the
25    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26    Boston, MA 02111-1307, USA.
27 */
28
29 #include <config.h>
30
31 #include <pthread.h>
32
33 #include <signal.h>
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <unistd.h>
38
39 #include <direct/clock.h>
40 #include <direct/conf.h>
41 #include <direct/debug.h>
42 #include <direct/list.h>
43 #include <direct/mem.h>
44 #include <direct/messages.h>
45 #include <direct/signals.h>
46 #include <direct/system.h>
47 #include <direct/trace.h>
48 #include <direct/util.h>
49
50 D_DEBUG_DOMAIN( Direct_Signals, "Direct/Signals", "Signal handling" );
51
52
53 struct __D_DirectSignalHandler {
54      DirectLink               link;
55
56      int                      magic;
57
58      int                      num;
59      DirectSignalHandlerFunc  func;
60      void                    *ctx;
61 };
62
63 /**************************************************************************************************/
64
65 typedef struct {
66      int              signum;
67      struct sigaction old_action;
68 } SigHandled;
69
70 static int sigs_to_handle[] = { /*SIGALRM,*/ SIGHUP, SIGINT, /*SIGPIPE,*/ /*SIGPOLL,*/
71                                 SIGTERM, /*SIGUSR1, SIGUSR2,*/ /*SIGVTALRM,*/
72                                 /*SIGSTKFLT,*/ SIGABRT, SIGFPE, SIGILL, SIGQUIT,
73                                 SIGSEGV, SIGTRAP, /*SIGSYS, SIGEMT,*/ SIGBUS,
74                                 SIGXCPU, SIGXFSZ };
75
76 #define NUM_SIGS_TO_HANDLE ((int)D_ARRAY_SIZE( sigs_to_handle ))
77
78 static SigHandled sigs_handled[NUM_SIGS_TO_HANDLE];
79
80 static DirectLink      *handlers = NULL;
81 static pthread_mutex_t  handlers_lock;
82
83 /**************************************************************************************************/
84
85 static void install_handlers();
86 static void remove_handlers();
87
88 /**************************************************************************************************/
89
90 DirectResult
91 direct_signals_initialize()
92 {
93      D_DEBUG_AT( Direct_Signals, "Initializing...\n" );
94
95      direct_util_recursive_pthread_mutex_init( &handlers_lock );
96
97      install_handlers();
98
99      return DR_OK;
100 }
101
102 DirectResult
103 direct_signals_shutdown()
104 {
105      D_DEBUG_AT( Direct_Signals, "Shutting down...\n" );
106
107      remove_handlers();
108
109      pthread_mutex_destroy( &handlers_lock );
110
111      return DR_OK;
112 }
113
114 void
115 direct_signals_block_all()
116 {
117      sigset_t signals;
118
119      D_DEBUG_AT( Direct_Signals, "Blocking all signals from now on!\n" );
120
121      sigfillset( &signals );
122
123      if (pthread_sigmask( SIG_BLOCK, &signals, NULL ))
124           D_PERROR( "Direct/Signals: Setting signal mask failed!\n" );
125 }
126
127 DirectResult
128 direct_signal_handler_add( int                       num,
129                            DirectSignalHandlerFunc   func,
130                            void                     *ctx,
131                            DirectSignalHandler     **ret_handler )
132 {
133      DirectSignalHandler *handler;
134
135      D_ASSERT( func != NULL );
136      D_ASSERT( ret_handler != NULL );
137
138      D_DEBUG_AT( Direct_Signals,
139                  "Adding handler %p for signal %d with context %p...\n", func, num, ctx );
140
141      handler = D_CALLOC( 1, sizeof(DirectSignalHandler) );
142      if (!handler) {
143           D_WARN( "out of memory" );
144           return DR_NOLOCALMEMORY;
145      }
146
147      handler->num  = num;
148      handler->func = func;
149      handler->ctx  = ctx;
150
151      D_MAGIC_SET( handler, DirectSignalHandler );
152
153      pthread_mutex_lock( &handlers_lock );
154      direct_list_append( &handlers, &handler->link );
155      pthread_mutex_unlock( &handlers_lock );
156
157      *ret_handler = handler;
158
159      return DR_OK;
160 }
161
162 DirectResult
163 direct_signal_handler_remove( DirectSignalHandler *handler )
164 {
165      D_MAGIC_ASSERT( handler, DirectSignalHandler );
166
167      D_DEBUG_AT( Direct_Signals, "Removing handler %p for signal %d with context %p...\n",
168                  handler->func, handler->num, handler->ctx );
169
170      pthread_mutex_lock( &handlers_lock );
171      direct_list_remove( &handlers, &handler->link );
172      pthread_mutex_unlock( &handlers_lock );
173
174      D_MAGIC_CLEAR( handler );
175
176      D_FREE( handler );
177
178      return DR_OK;
179 }
180
181 /**************************************************************************************************/
182
183 static bool
184 show_segv( const siginfo_t *info )
185 {
186      switch (info->si_code) {
187 #ifdef SEGV_MAPERR
188           case SEGV_MAPERR:
189                direct_log_printf( NULL, " (at %p, invalid address) <--\n", info->si_addr );
190                return true;
191 #endif
192 #ifdef SEGV_ACCERR
193           case SEGV_ACCERR:
194                direct_log_printf( NULL, " (at %p, invalid permissions) <--\n", info->si_addr );
195                return true;
196 #endif
197      }
198      return false;
199 }
200
201 static bool
202 show_bus( const siginfo_t *info )
203 {
204      switch (info->si_code) {
205 #ifdef BUG_ADRALN
206           case BUS_ADRALN:
207                direct_log_printf( NULL, " (at %p, invalid address alignment) <--\n", info->si_addr );
208                return true;
209 #endif
210 #ifdef BUS_ADRERR
211           case BUS_ADRERR:
212                direct_log_printf( NULL, " (at %p, non-existent physical address) <--\n", info->si_addr );
213                return true;
214 #endif
215 #ifdef BUS_OBJERR
216           case BUS_OBJERR:
217                direct_log_printf( NULL, " (at %p, object specific hardware error) <--\n", info->si_addr );
218                return true;
219 #endif
220      }
221
222      return false;
223 }
224
225 static bool
226 show_ill( const siginfo_t *info )
227 {
228      switch (info->si_code) {
229 #ifdef ILL_ILLOPC
230           case ILL_ILLOPC:
231                direct_log_printf( NULL, " (at %p, illegal opcode) <--\n", info->si_addr );
232                return true;
233 #endif
234 #ifdef ILL_ILLOPN
235           case ILL_ILLOPN:
236                direct_log_printf( NULL, " (at %p, illegal operand) <--\n", info->si_addr );
237                return true;
238 #endif
239 #ifdef ILL_ILLADR
240           case ILL_ILLADR:
241                direct_log_printf( NULL, " (at %p, illegal addressing mode) <--\n", info->si_addr );
242                return true;
243 #endif
244 #ifdef ILL_ILLTRP
245           case ILL_ILLTRP:
246                direct_log_printf( NULL, " (at %p, illegal trap) <--\n", info->si_addr );
247                return true;
248 #endif
249 #ifdef ILL_PRVOPC
250           case ILL_PRVOPC:
251                direct_log_printf( NULL, " (at %p, privileged opcode) <--\n", info->si_addr );
252                return true;
253 #endif
254 #ifdef ILL_PRVREG
255           case ILL_PRVREG:
256                direct_log_printf( NULL, " (at %p, privileged register) <--\n", info->si_addr );
257                return true;
258 #endif
259 #ifdef ILL_COPROC
260           case ILL_COPROC:
261                direct_log_printf( NULL, " (at %p, coprocessor error) <--\n", info->si_addr );
262                return true;
263 #endif
264 #ifdef ILL_BADSTK
265           case ILL_BADSTK:
266                direct_log_printf( NULL, " (at %p, internal stack error) <--\n", info->si_addr );
267                return true;
268 #endif
269      }
270
271      return false;
272 }
273
274 static bool
275 show_fpe( const siginfo_t *info )
276 {
277      switch (info->si_code) {
278 #ifdef FPE_INTDIV
279           case FPE_INTDIV:
280                direct_log_printf( NULL, " (at %p, integer divide by zero) <--\n", info->si_addr );
281                return true;
282 #endif
283 #ifdef FPE_FLTDIV
284           case FPE_FLTDIV:
285                direct_log_printf( NULL, " (at %p, floating point divide by zero) <--\n", info->si_addr );
286                return true;
287 #endif
288      }
289
290      direct_log_printf( NULL, " (at %p) <--\n", info->si_addr );
291
292      return true;
293 }
294
295 static bool
296 show_any( const siginfo_t *info )
297 {
298      switch (info->si_code) {
299 #ifdef SI_USER
300           case SI_USER:
301                direct_log_printf( NULL, " (sent by pid %d, uid %d) <--\n", info->si_pid, info->si_uid );
302                return true;
303 #endif
304 #ifdef SI_KERNEL
305           case SI_KERNEL:
306                direct_log_printf( NULL, " (sent by the kernel) <--\n" );
307                return true;
308 #endif
309      }
310      return false;
311 }
312
313 static void
314 #ifdef SA_SIGINFO
315 signal_handler( int num, siginfo_t *info, void *foo )
316 #else
317 signal_handler( int num )
318 #endif
319 {
320      DirectLink *l, *n;
321      void       *addr   = NULL;
322      int         pid    = direct_gettid();
323      long long   millis = direct_clock_get_millis();
324
325      fflush(stdout);
326      fflush(stderr);
327
328      direct_log_printf( NULL, "(!) [%5d: %4lld.%03lld] --> Caught signal %d",
329                         pid, millis/1000, millis%1000, num );
330
331 #ifdef SA_SIGINFO
332      if (info && info > (siginfo_t*) 0x100) {
333           bool shown = false;
334
335           if (info->si_code > 0 && info->si_code < 0x80) {
336                addr = info->si_addr;
337
338                switch (num) {
339                     case SIGSEGV:
340                          shown = show_segv( info );
341                          break;
342
343                     case SIGBUS:
344                          shown = show_bus( info );
345                          break;
346
347                     case SIGILL:
348                          shown = show_ill( info );
349                          break;
350
351                     case SIGFPE:
352                          shown = show_fpe( info );
353                          break;
354
355                     default:
356                          direct_log_printf( NULL, " <--\n" );
357                          addr  = NULL;
358                          shown = true;
359                          break;
360                }
361           }
362           else
363                shown = show_any( info );
364
365           if (!shown)
366                direct_log_printf( NULL, " (unknown origin) <--\n" );
367      }
368      else
369 #endif
370           direct_log_printf( NULL, ", no siginfo available <--\n" );
371
372      direct_trace_print_stacks();
373
374      /* Loop through all handlers. */
375      pthread_mutex_lock( &handlers_lock );
376
377      direct_list_foreach_safe (l, n, handlers) {
378           DirectSignalHandler *handler = (DirectSignalHandler*) l;
379
380           if (handler->num != num && handler->num != DIRECT_SIGNAL_ANY)
381                continue;
382
383           switch (handler->func( num, addr, handler->ctx )) {
384                case DSHR_OK:
385                     break;
386
387                case DSHR_REMOVE:
388                     direct_list_remove( &handlers, &handler->link );
389                     D_MAGIC_CLEAR( handler );
390                     D_FREE( handler );
391                     break;
392
393                case DSHR_RESUME:
394                     millis = direct_clock_get_millis();
395
396                     direct_log_printf( NULL, "(!) [%5d: %4lld.%03lld]      -> cured!\n",
397                                        pid, millis / 1000, millis % 1000 );
398                     pthread_mutex_unlock( &handlers_lock );
399                     return;
400
401                default:
402                     D_BUG( "unknown result" );
403                     break;
404           }
405      }
406
407      pthread_mutex_unlock( &handlers_lock );
408
409      remove_handlers();
410
411      raise( num );
412      
413      abort();
414
415      exit( -num );
416 }
417
418 /**************************************************************************************************/
419
420 static void
421 install_handlers()
422 {
423      int i;
424
425      for (i=0; i<NUM_SIGS_TO_HANDLE; i++) {
426           sigs_handled[i].signum = -1;
427
428           if (direct_config->sighandler && !sigismember( &direct_config->dont_catch,
429                                                          sigs_to_handle[i] ))
430           {
431                struct sigaction action;
432                int              signum = sigs_to_handle[i];
433
434 #ifdef SA_SIGINFO
435                action.sa_sigaction = signal_handler;
436                action.sa_flags     = SA_SIGINFO;
437 #else
438                action.sa_handler   = signal_handler;
439                action.sa_flags     = 0;
440 #endif
441
442                if (signum != SIGSEGV)
443                     action.sa_flags |= SA_NODEFER;
444
445                sigemptyset( &action.sa_mask );
446
447                if (sigaction( signum, &action, &sigs_handled[i].old_action )) {
448                     D_PERROR( "Direct/Signals: "
449                               "Unable to install signal handler for signal %d!\n", signum );
450                     continue;
451                }
452
453                sigs_handled[i].signum = signum;
454           }
455      }
456 }
457
458 static void
459 remove_handlers()
460 {
461      int i;
462
463      for (i=0; i<NUM_SIGS_TO_HANDLE; i++) {
464           if (sigs_handled[i].signum != -1) {
465                int signum = sigs_handled[i].signum;
466
467                if (sigaction( signum, &sigs_handled[i].old_action, NULL )) {
468                     D_PERROR( "Direct/Signals: "
469                               "Unable to restore previous handler for signal %d!\n", signum );
470                }
471
472                sigs_handled[i].signum = -1;
473           }
474      }
475 }
476