/*
* This file is part of the XForms library package.
*
* XForms 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.1, or
* (at your option) any later version.
*
* XForms 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 XForms. If not, see .
*/
/**
* \file signal.c
*
* This file is part of the XForms library package.
* Copyright (c) 1996-2002 T.C. Zhao
* All rights reserved.
*
* Simple minded quick&dirty signal handling.
*
* Only permit a specific signal to have one handler
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "include/forms.h"
#include "flinternal.h"
#include
#include
void ( * fli_handle_signal )( void ) = NULL; /* also needed in handling.c */
/***************************************
***************************************/
static void
handle_signal( void )
{
FLI_SIGNAL_REC *rec = fli_context->signal_rec;
for ( ; rec; rec = rec->next )
while ( rec->caught )
{
rec->caught--;
rec->callback( rec->signum, rec->data );
}
}
#ifndef FL_WIN32
#define IsDangerous( s ) ( ( s ) == SIGBUS \
|| ( s ) == SIGSEGV \
|| ( s ) == SIGILL \
|| ( s ) == SIGFPE )
#else
#define IsDangerous( s ) 0
#endif
static int sig_direct;
/***************************************
***************************************/
static RETSIGTYPE
default_signal_handler( int sig )
{
fl_signal_caught( sig );
/* if the signal is one of those that can cause infinite loops, handle it
and then exit */
if ( IsDangerous( sig ) )
{
handle_signal( );
fprintf( stderr, "Can't continue upon receiving signal %d\n", sig );
exit( sig );
}
#ifndef RETSIGTYPE_IS_VOID
return 0;
#endif
}
/***************************************
***************************************/
void
fl_add_signal_callback( int s,
FL_SIGNAL_HANDLER cb,
void * data )
{
FLI_SIGNAL_REC *sig_rec,
*rec = fli_context->signal_rec;
if ( ! fli_handle_signal )
fli_handle_signal = handle_signal;
while ( rec && rec->signum != s )
rec = rec->next;
if ( rec )
{
rec->callback = cb;
rec->data = data;
}
else
{
sig_rec = fl_malloc( sizeof *sig_rec );
sig_rec->next = NULL;
sig_rec->data = data;
sig_rec->callback = cb;
sig_rec->signum = s;
sig_rec->caught = 0;
if ( ! sig_direct )
{
#if defined HAVE_SIGACTION
struct sigaction sact;
sact.sa_handler = default_signal_handler;
sigemptyset( &sact.sa_mask );
sact.sa_flags = 0;
if ( sigaction( s, &sact, &sig_rec->old_sigact ) < 0 )
#else
errno = 0;
sig_rec->ocallback = signal( s, default_signal_handler );
if ( sig_rec->ocallback == ( FLI_OSSIG_HANDLER ) - 1L || errno )
#endif
{
M_err( "fl_add_signal_callback", "Can't add handler for "
"signal %d", s );
fl_free( sig_rec );
return;
}
}
if ( fli_context->signal_rec )
sig_rec->next = fli_context->signal_rec;
fli_context->signal_rec = sig_rec;
}
}
/***************************************
***************************************/
void
fl_remove_signal_callback( int s )
{
FLI_SIGNAL_REC *last,
*rec = fli_context->signal_rec;
for ( last = rec; rec && rec->signum != s; last = rec, rec = rec->next )
/* empty */ ;
if ( ! rec )
{
M_err( "fl_remove_signal_callback", "No handler exists for signal %d",
s );
return;
}
if ( rec == fli_context->signal_rec )
fli_context->signal_rec = rec->next;
else
last->next = rec->next;
if ( ! sig_direct )
{
#if defined HAVE_SIGACTION
sigaction( s, &rec->old_sigact, NULL );
#else
signal( s, rec->ocallback );
#endif
}
fli_safe_free( rec );
}
/***************************************
***************************************/
void
fl_signal_caught( int s )
{
FLI_SIGNAL_REC *rec = fli_context->signal_rec;
while ( rec && rec->signum != s )
rec = rec->next;
if ( ! rec )
{
M_err( "fl_signal_caught", "Caught bogus signal %d", s );
return;
}
rec->caught++;
#if ! defined HAVE_SIGACTION
if ( ! sig_direct && ! IsDangerous( s ) )
signal( s, default_signal_handler );
#endif
}
/***************************************
***************************************/
void
fl_app_signal_direct( int y )
{
if ( ! fli_handle_signal )
fli_handle_signal = handle_signal;
sig_direct = y;
}
/***************************************
***************************************/
void
fli_remove_all_signal_callbacks( void )
{
while ( fli_context->signal_rec )
fl_remove_signal_callback( fli_context->signal_rec->signum );
}
/*
* Local variables:
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/