?? 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 structurestypedef 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 structuresCyg_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 setsigset_t sig_pending;// Array controlling signal statesstatic signal_state sigstate[sizeof(sigset_t)*8];// Array of available signal_info objects for queueing signalsstatic signal_info siginfo[SIGQUEUE_MAX];// List of free signal_info objectsstatic signal_info *siginfo_next = NULL;//==========================================================================// Variables used to support alarm()// Forward def of action functionstatic void sigalrm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data );// Kernel alarm objectstatic Cyg_Alarm sigalrm_alarm( Cyg_Clock::real_time_clock, sigalrm_action, 0 ) CYGBLD_POSIX_INIT;// Set true when alarm is armedvolatile cyg_bool sigalrm_armed = false;// Set true when alarm has fired and is waiting to be deliveredvolatile 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 signalcyg_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 + -