📄 signal.cxx
字号:
//==========================================================================
//
// signal.cxx
//
// POSIX signal functions implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Nick Garnett
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos 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 General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-27
// Purpose: POSIX signal functions implementation
// Description: This file contains the implementation of the POSIX signal
// functions.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <pkgconf/posix.h>
#ifdef CYGPKG_POSIX_SIGNALS
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/isoinfra.h>
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
#include "pprivate.h" // POSIX private header
#include <signal.h> // our header
#include <setjmp.h>
#include <unistd.h> // _exit
#include <cyg/kernel/clock.hxx>
#include <cyg/kernel/thread.hxx>
#include <cyg/kernel/clock.inl>
#include <cyg/kernel/thread.inl>
// -------------------------------------------------------------------------
// Internal definitions
// Handle entry to a signal package function.
#define SIGNAL_ENTRY() CYG_REPORT_FUNCTYPE( "returning %d" );
// Do a signal package defined return. This requires the error code
// to be placed in errno, and if it is non-zero, -1 returned as the
// result of the function. This also gives us a place to put any
// generic tidyup handling needed for things like signal delivery and
// cancellation.
#define SIGNAL_RETURN(err) \CYG_MACRO_START \ int __retval = 0; \ if( err != 0 ) __retval = -1, errno = err; \ CYG_REPORT_RETVAL( __retval ); \ return __retval; \CYG_MACRO_END
// Similarly for functions that have valid non-zero returns
#define SIGNAL_RETURN_VALUE(val) \CYG_MACRO_START \ CYG_REPORT_RETVAL( val ); \ return val; \CYG_MACRO_END
// Range check on a signal value.
#define SIGNAL_VALID(_sig_) (((_sig_) > 0) && ((_sig_) < ((int)sizeof(sigset_t)*8)))
//==========================================================================
// Signal management structures
typedef struct signal_info
{
struct signal_info *next; // link in list of pending signals
siginfo_t si; // siginfo to pass to handler
} signal_info;
typedef struct
{
struct sigaction sa; // Sigaction defining what to do
signal_info *pending; // List of pending signals - this is
// a circular list with pending pointing
// to the tail element (or NULL if empty).
} signal_state;
//==========================================================================
// Signal management variables
// Lock used to protect signal management structures
Cyg_Mutex signal_mutex CYGBLD_POSIX_INIT;
// Condition variable for all threads in sigsuspend() and sigwait()
// to wait on.
Cyg_Condition_Variable signal_sigwait( signal_mutex ) CYGBLD_POSIX_INIT;
// Global pending signal set
sigset_t sig_pending;
// Array controlling signal states
static signal_state sigstate[sizeof(sigset_t)*8];
// Array of available signal_info objects for queueing signals
static signal_info siginfo[SIGQUEUE_MAX];
// List of free signal_info objects
static signal_info *siginfo_next = NULL;
//==========================================================================
// Variables used to support alarm()
// Forward def of action function
static void sigalrm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data );
// Kernel alarm object
static Cyg_Alarm sigalrm_alarm( Cyg_Clock::real_time_clock, sigalrm_action, 0 ) CYGBLD_POSIX_INIT;
// Set true when alarm is armed
volatile cyg_bool sigalrm_armed = false;
// Set true when alarm has fired and is waiting to be delivered
volatile cyg_bool sigalrm_pending = false;
//==========================================================================
// Implementation functions.
// These are where the real work of the signal mechanism gets done.
externC void cyg_posix_signal_start()
{
// Chain all free signal_info objects together
for( int i = 0; i < SIGQUEUE_MAX; i++ )
{
siginfo[i].next = siginfo_next;
siginfo_next = &siginfo[i];
}
// initialize all signal actions to SIG_DFL
for ( unsigned int i=0; i<(sizeof(sigstate)/sizeof(signal_state)); i++ )
{
sigstate[i].sa.sa_handler = SIG_DFL;
}
// Clear the pending signal set
sigemptyset( &sig_pending );
}
// -------------------------------------------------------------------------
// Generate a signal
cyg_bool cyg_sigqueue( const struct sigevent *sev, int code,
pthread_info *thread )
{
if( sev->sigev_notify == SIGEV_NONE )
{
// Do nothing
return true;
}
if( sev->sigev_notify == SIGEV_THREAD )
{
// create a thread to run the notification
// function.
// FIXME: implement SIGEV_THREAD
return true;
}
// Otherwise we must have a SIGEV_SIGNAL notification
// Find out whether the current thread already has the mutex
// locked. This is a distinct possibility if this function is
// called from the ASR while exiting the signal_sigwait condvar in
// pause() and sigtimedwait().
pthread_info *self = pthread_self_info();
cyg_bool locked = (self != NULL) && (signal_mutex.get_owner() == self->thread);
// Lock the mutex only if we do not already own it
if( !locked ) signal_mutex.lock();
int signo = sev->sigev_signo;
signal_state *ss = &sigstate[signo];
if( ss->sa.sa_flags & SA_SIGINFO )
{
// We have a queuable signal, allocate a signal_info
// object and add it to the queue.
if( siginfo_next == NULL )
{
if( !locked ) signal_mutex.unlock();
return false;
}
signal_info *si = siginfo_next;
siginfo_next = si->next;
si->si.si_signo = signo;
si->si.si_code = code;
si->si.si_value = sev->sigev_value;
if( ss->pending == NULL )
{
si->next = si;
}
else
{
si->next = ss->pending->next;
ss->pending->next = si;
}
ss->pending = si;
}
// else A non-queuable signal, just set it pending
if( thread != NULL )
{
sigaddset( &thread->sigpending, signo );
// just wake the thread up now if it's blocked somewhere
if ((thread->sigpending & ~thread->sigmask) != 0)
{
thread->thread->set_asr_pending();
thread->thread->release();
}
}
else
{
sigaddset( &sig_pending, signo );
// Wake up any threads in sigsuspend() and sigwait().
if (!signal_sigwait.get_queue()->empty())
{
signal_sigwait.broadcast();
}
else
{
cyg_posix_pthread_release_thread( &sig_pending );
}
}
if( !locked ) signal_mutex.unlock();
return true;
}
// -------------------------------------------------------------------------
// Deliver any pending unblocked signals to the current thread
// Returns true if a signal handler was called.
cyg_bool cyg_deliver_signals()
{
cyg_bool res = false;
pthread_info *self = pthread_self_info();
// If there is no pthread_info pointer for this thread then
// it is not a POSIX thread and cannot have signals delivered
// to it.
if( self == NULL ) return false;
// If there are no pending signals our work is done
if( sig_pending == 0 && self->sigpending == 0 )
return false;
// If there are no unmasked pending signals our
// work is also done
if( ((sig_pending | self->sigpending) & ~self->sigmask) == 0 )
return false;
// As with cyg_sigqueue(), this function can get called from an
// ASR where the signal_mutex is already locked. Check here to
// avoid relocking...
cyg_bool locked = signal_mutex.get_owner() == self->thread;
if( !locked ) signal_mutex.lock();
sigset_t todo;
// Since a signal handler may raise another signal, or unmask an existing
// signal, we loop here while there are no more unblocked signals pending.
while( (todo = ((sig_pending | self->sigpending) & ~self->sigmask)) != 0 )
{
// Here todo is a mask of the signals available for delivery
int signo = 0;
// This prioritizes low numbered signals
HAL_LSBIT_INDEX( signo, todo );
signal_state *ss = &sigstate[signo];
sigset_t sigbit = 1L<<signo;
if( ss->sa.sa_handler != SIG_IGN )
{
sigset_t oldmask = self->sigmask;
siginfo_t lsi;
if(ss->pending != NULL)
{
// There is a queued signal. Dequeue it and copy the
// siginfo object to a local copy.
signal_info *si = ss->pending->next;
// Make a local copy of the siginfo object
lsi = si->si;
// Remove the head signal_info object from the
// circular list.
if( ss->pending == si )
ss->pending = NULL;
else
ss->pending->next = si->next;
// Return it to the free list
si->next = siginfo_next;
siginfo_next = si;
}
else
{
// There are no signals queued. Set up the local siginfo_t
// object with default values.
lsi.si_signo = signo;
lsi.si_code = SI_USER;
lsi.si_value.sival_int = 0;
}
// Clear the bit from the pending masks. If the pending
// queue is not empty, leave the bits set, otherwise clear
// them. Do this now so that if the signal handler longjumps
// out, the signal subsystem is clean.
if( ss->pending == NULL )
{
// Clear the bit in both masks regardless of which
// one it actually came from. This is cheaper than
// trying to find out.
sig_pending &= ~sigbit;
self->sigpending &= ~sigbit;
}
// Add the mask set and the signal itself to the
// mask while we call the signal handler
self->sigmask = oldmask | ss->sa.sa_mask | sigbit;
// Unlock now so that a longjmp out of the handler
// does the right thing. We do this even if we did not
// lock the mutex since it will only recently have been
// relocked and thus all data is still consistent.
signal_mutex.unlock();
if( ss->sa.sa_flags & SA_SIGINFO )
{
// A sigaction delivery
CYG_CHECK_FUNC_PTR( ss->sa.sa_sigaction,
"Bad sa_sigaction signal handler" );
ss->sa.sa_sigaction( signo, &lsi, NULL );
}
else if ( ss->sa.sa_handler == SIG_DFL )
{
CYG_TRACE2( true,
"Unhandled POSIX signal: sig=%d, mask=%08x",
signo, oldmask );
// FIXME: should do something better here
#if CYGINT_ISO_EXIT
_exit( -signo );
#endif
CYG_FAIL("Unhandled POSIX signal");
}
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -