summaryrefslogtreecommitdiff
path: root/Source/DirectFB/lib/direct/signals.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/lib/direct/signals.c')
-rwxr-xr-xSource/DirectFB/lib/direct/signals.c480
1 files changed, 480 insertions, 0 deletions
diff --git a/Source/DirectFB/lib/direct/signals.c b/Source/DirectFB/lib/direct/signals.c
new file mode 100755
index 0000000..5b0310a
--- /dev/null
+++ b/Source/DirectFB/lib/direct/signals.c
@@ -0,0 +1,480 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+
+#include <pthread.h>
+
+#include <signal.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <direct/clock.h>
+#include <direct/conf.h>
+#include <direct/debug.h>
+#include <direct/list.h>
+#include <direct/mem.h>
+#include <direct/messages.h>
+#include <direct/signals.h>
+#include <direct/system.h>
+#include <direct/trace.h>
+#include <direct/util.h>
+
+D_DEBUG_DOMAIN( Direct_Signals, "Direct/Signals", "Signal handling" );
+
+
+struct __D_DirectSignalHandler {
+ DirectLink link;
+
+ int magic;
+
+ int num;
+ DirectSignalHandlerFunc func;
+ void *ctx;
+};
+
+/**************************************************************************************************/
+
+typedef struct {
+ int signum;
+ struct sigaction old_action;
+} SigHandled;
+
+static int sigs_to_handle[] = { /*SIGALRM,*/ SIGHUP, SIGINT, /*SIGPIPE,*/ /*SIGPOLL,*/
+ SIGTERM, /*SIGUSR1, SIGUSR2,*/ /*SIGVTALRM,*/
+ /*SIGSTKFLT,*/ SIGABRT, SIGFPE, SIGILL, SIGQUIT,
+ SIGSEGV, SIGTRAP, /*SIGSYS, SIGEMT,*/ SIGBUS,
+ SIGXCPU, SIGXFSZ };
+
+#define NUM_SIGS_TO_HANDLE ((int)D_ARRAY_SIZE( sigs_to_handle ))
+
+static SigHandled sigs_handled[NUM_SIGS_TO_HANDLE];
+
+static DirectLink *handlers = NULL;
+static pthread_mutex_t handlers_lock;
+
+/**************************************************************************************************/
+
+static void install_handlers( void );
+static void remove_handlers( void );
+
+/**************************************************************************************************/
+
+DirectResult
+direct_signals_initialize( void )
+{
+ D_DEBUG_AT( Direct_Signals, "Initializing...\n" );
+
+ direct_util_recursive_pthread_mutex_init( &handlers_lock );
+
+ install_handlers();
+
+ return DR_OK;
+}
+
+DirectResult
+direct_signals_shutdown( void )
+{
+ D_DEBUG_AT( Direct_Signals, "Shutting down...\n" );
+
+ remove_handlers();
+
+ pthread_mutex_destroy( &handlers_lock );
+
+ return DR_OK;
+}
+
+void
+direct_signals_block_all( void )
+{
+ sigset_t signals;
+
+ D_DEBUG_AT( Direct_Signals, "Blocking all signals from now on!\n" );
+
+ sigfillset( &signals );
+
+ if (pthread_sigmask( SIG_BLOCK, &signals, NULL ))
+ D_PERROR( "Direct/Signals: Setting signal mask failed!\n" );
+}
+
+DirectResult
+direct_signal_handler_add( int num,
+ DirectSignalHandlerFunc func,
+ void *ctx,
+ DirectSignalHandler **ret_handler )
+{
+ DirectSignalHandler *handler;
+
+ D_ASSERT( func != NULL );
+ D_ASSERT( ret_handler != NULL );
+
+ D_DEBUG_AT( Direct_Signals,
+ "Adding handler %p for signal %d with context %p...\n", func, num, ctx );
+
+ handler = D_CALLOC( 1, sizeof(DirectSignalHandler) );
+ if (!handler) {
+ D_WARN( "out of memory" );
+ return DR_NOLOCALMEMORY;
+ }
+
+ handler->num = num;
+ handler->func = func;
+ handler->ctx = ctx;
+
+ D_MAGIC_SET( handler, DirectSignalHandler );
+
+ pthread_mutex_lock( &handlers_lock );
+ direct_list_append( &handlers, &handler->link );
+ pthread_mutex_unlock( &handlers_lock );
+
+ *ret_handler = handler;
+
+ return DR_OK;
+}
+
+DirectResult
+direct_signal_handler_remove( DirectSignalHandler *handler )
+{
+ D_MAGIC_ASSERT( handler, DirectSignalHandler );
+
+ D_DEBUG_AT( Direct_Signals, "Removing handler %p for signal %d with context %p...\n",
+ handler->func, handler->num, handler->ctx );
+
+ pthread_mutex_lock( &handlers_lock );
+ direct_list_remove( &handlers, &handler->link );
+ pthread_mutex_unlock( &handlers_lock );
+
+ D_MAGIC_CLEAR( handler );
+
+ D_FREE( handler );
+
+ return DR_OK;
+}
+
+/**************************************************************************************************/
+
+static bool
+show_segv( const siginfo_t *info )
+{
+ switch (info->si_code) {
+#ifdef SEGV_MAPERR
+ case SEGV_MAPERR:
+ direct_log_printf( NULL, " (at %p, invalid address) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef SEGV_ACCERR
+ case SEGV_ACCERR:
+ direct_log_printf( NULL, " (at %p, invalid permissions) <--\n", info->si_addr );
+ return true;
+#endif
+ }
+ return false;
+}
+
+static bool
+show_bus( const siginfo_t *info )
+{
+ switch (info->si_code) {
+#ifdef BUG_ADRALN
+ case BUS_ADRALN:
+ direct_log_printf( NULL, " (at %p, invalid address alignment) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef BUS_ADRERR
+ case BUS_ADRERR:
+ direct_log_printf( NULL, " (at %p, non-existent physical address) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef BUS_OBJERR
+ case BUS_OBJERR:
+ direct_log_printf( NULL, " (at %p, object specific hardware error) <--\n", info->si_addr );
+ return true;
+#endif
+ }
+
+ return false;
+}
+
+static bool
+show_ill( const siginfo_t *info )
+{
+ switch (info->si_code) {
+#ifdef ILL_ILLOPC
+ case ILL_ILLOPC:
+ direct_log_printf( NULL, " (at %p, illegal opcode) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef ILL_ILLOPN
+ case ILL_ILLOPN:
+ direct_log_printf( NULL, " (at %p, illegal operand) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef ILL_ILLADR
+ case ILL_ILLADR:
+ direct_log_printf( NULL, " (at %p, illegal addressing mode) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef ILL_ILLTRP
+ case ILL_ILLTRP:
+ direct_log_printf( NULL, " (at %p, illegal trap) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef ILL_PRVOPC
+ case ILL_PRVOPC:
+ direct_log_printf( NULL, " (at %p, privileged opcode) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef ILL_PRVREG
+ case ILL_PRVREG:
+ direct_log_printf( NULL, " (at %p, privileged register) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef ILL_COPROC
+ case ILL_COPROC:
+ direct_log_printf( NULL, " (at %p, coprocessor error) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef ILL_BADSTK
+ case ILL_BADSTK:
+ direct_log_printf( NULL, " (at %p, internal stack error) <--\n", info->si_addr );
+ return true;
+#endif
+ }
+
+ return false;
+}
+
+static bool
+show_fpe( const siginfo_t *info )
+{
+ switch (info->si_code) {
+#ifdef FPE_INTDIV
+ case FPE_INTDIV:
+ direct_log_printf( NULL, " (at %p, integer divide by zero) <--\n", info->si_addr );
+ return true;
+#endif
+#ifdef FPE_FLTDIV
+ case FPE_FLTDIV:
+ direct_log_printf( NULL, " (at %p, floating point divide by zero) <--\n", info->si_addr );
+ return true;
+#endif
+ }
+
+ direct_log_printf( NULL, " (at %p) <--\n", info->si_addr );
+
+ return true;
+}
+
+static bool
+show_any( const siginfo_t *info )
+{
+ switch (info->si_code) {
+#ifdef SI_USER
+ case SI_USER:
+ direct_log_printf( NULL, " (sent by pid %d, uid %d) <--\n", info->si_pid, info->si_uid );
+ return true;
+#endif
+#ifdef SI_KERNEL
+ case SI_KERNEL:
+ direct_log_printf( NULL, " (sent by the kernel) <--\n" );
+ return true;
+#endif
+ }
+ return false;
+}
+
+static void
+#ifdef SA_SIGINFO
+signal_handler( int num, siginfo_t *info, void *foo )
+#else
+signal_handler( int num )
+#endif
+{
+ DirectLink *l, *n;
+ void *addr = NULL;
+ int pid = direct_gettid();
+ long long millis = direct_clock_get_millis();
+
+ fflush(stdout);
+ fflush(stderr);
+
+ direct_log_printf( NULL, "(!) [%5d: %4lld.%03lld] --> Caught signal %d",
+ pid, millis/1000, millis%1000, num );
+
+#ifdef SA_SIGINFO
+ if (info && info > (siginfo_t*) 0x100) {
+ bool shown = false;
+
+ if (info->si_code > 0 && info->si_code < 0x80) {
+ addr = info->si_addr;
+
+ switch (num) {
+ case SIGSEGV:
+ shown = show_segv( info );
+ break;
+
+ case SIGBUS:
+ shown = show_bus( info );
+ break;
+
+ case SIGILL:
+ shown = show_ill( info );
+ break;
+
+ case SIGFPE:
+ shown = show_fpe( info );
+ break;
+
+ default:
+ direct_log_printf( NULL, " <--\n" );
+ addr = NULL;
+ shown = true;
+ break;
+ }
+ }
+ else
+ shown = show_any( info );
+
+ if (!shown)
+ direct_log_printf( NULL, " (unknown origin) <--\n" );
+ }
+ else
+#endif
+ direct_log_printf( NULL, ", no siginfo available <--\n" );
+
+ direct_trace_print_stacks();
+
+ /* Loop through all handlers. */
+ pthread_mutex_lock( &handlers_lock );
+
+ direct_list_foreach_safe (l, n, handlers) {
+ DirectSignalHandler *handler = (DirectSignalHandler*) l;
+
+ if (handler->num != num && handler->num != DIRECT_SIGNAL_ANY)
+ continue;
+
+ switch (handler->func( num, addr, handler->ctx )) {
+ case DSHR_OK:
+ break;
+
+ case DSHR_REMOVE:
+ direct_list_remove( &handlers, &handler->link );
+ D_MAGIC_CLEAR( handler );
+ D_FREE( handler );
+ break;
+
+ case DSHR_RESUME:
+ millis = direct_clock_get_millis();
+
+ direct_log_printf( NULL, "(!) [%5d: %4lld.%03lld] -> cured!\n",
+ pid, millis / 1000, millis % 1000 );
+ pthread_mutex_unlock( &handlers_lock );
+ return;
+
+ default:
+ D_BUG( "unknown result" );
+ break;
+ }
+ }
+
+ pthread_mutex_unlock( &handlers_lock );
+
+
+// sleep(100);
+
+
+ remove_handlers();
+
+ raise( num );
+
+ abort();
+
+ exit( -num );
+}
+
+/**************************************************************************************************/
+
+static void
+install_handlers( void )
+{
+ int i;
+
+ for (i=0; i<NUM_SIGS_TO_HANDLE; i++) {
+ sigs_handled[i].signum = -1;
+
+ if (direct_config->sighandler && !sigismember( &direct_config->dont_catch,
+ sigs_to_handle[i] ))
+ {
+ struct sigaction action;
+ int signum = sigs_to_handle[i];
+
+#ifdef SA_SIGINFO
+ action.sa_sigaction = signal_handler;
+ action.sa_flags = SA_SIGINFO;
+#else
+ action.sa_handler = signal_handler;
+ action.sa_flags = 0;
+#endif
+
+ if (signum != SIGSEGV)
+ action.sa_flags |= SA_NODEFER;
+
+ sigemptyset( &action.sa_mask );
+
+ if (sigaction( signum, &action, &sigs_handled[i].old_action )) {
+ D_PERROR( "Direct/Signals: "
+ "Unable to install signal handler for signal %d!\n", signum );
+ continue;
+ }
+
+ sigs_handled[i].signum = signum;
+ }
+ }
+}
+
+static void
+remove_handlers( void )
+{
+ int i;
+
+ for (i=0; i<NUM_SIGS_TO_HANDLE; i++) {
+ if (sigs_handled[i].signum != -1) {
+ int signum = sigs_handled[i].signum;
+
+ if (sigaction( signum, &sigs_handled[i].old_action, NULL )) {
+ D_PERROR( "Direct/Signals: "
+ "Unable to restore previous handler for signal %d!\n", signum );
+ }
+
+ sigs_handled[i].signum = -1;
+ }
+ }
+}
+