URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [compat/] [posix/] [v2_0/] [src/] [signal.cxx] - Rev 757
Go to most recent revision | Compare with Previous | Blame | View Log
//========================================================================== // // 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 { // This is a standard signal delivery. CYG_CHECK_FUNC_PTR( ss->sa.sa_handler, "Bad sa_handler signal handler" ); ss->sa.sa_handler( signo ); } // Relock the mutex signal_mutex.lock(); // Restore original signal mask self->sigmask = oldmask; // return that we have handled a signal res = true; } } if( !locked ) signal_mutex.unlock(); return res; } // ------------------------------------------------------------------------- // Utility routine to signal any threads waiting in sigwait*(). void cyg_posix_signal_sigwait() { signal_sigwait.broadcast(); } // ------------------------------------------------------------------------- // Action routine called from kernel alarm to deliver the SIGALRM signal. // We cannot call any signal delivery functions directly here, so we simply // set a flag and schedule an ASR to be called. static void sigalrm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data ) { sigset_t mask; sigalrm_armed = false; sigalrm_pending = true; sigemptyset( &mask ); sigaddset( &mask, SIGALRM ); // Wake up any threads in sigsuspend() and sigwait() in case they // are waiting for an alarm, and would have SIGALRM masked signal_sigwait.broadcast(); cyg_posix_pthread_release_thread( &mask ); } // ------------------------------------------------------------------------- // Check for SIGALRMs. This is called from the ASR and sigtimedwait() // as alarms need to be handled as a special case. static __inline__ void check_sigalarm(void) { // If there is a pending SIGALRM, generate it if( sigalrm_pending ) { sigalrm_pending = false; struct sigevent sev; sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGALRM; sev.sigev_value.sival_int = 0; // generate the signal cyg_sigqueue( &sev, SI_USER ); } } // ------------------------------------------------------------------------- // signal ASR function. This is called from the general POSIX ASR to // deal with any signal related issues. externC void cyg_posix_signal_asr(pthread_info *self) { check_sigalarm(); // Now call cyg_deliver_signals() to see if we can // handle any signals now. cyg_deliver_signals(); } //========================================================================== // Per-thread initialization and destruction externC void cyg_posix_thread_siginit( pthread_info *thread, pthread_info *parentthread ) { // Clear out signal masks sigemptyset( &thread->sigpending ); // but threads inherit signal masks if ( NULL == parentthread ) sigemptyset( &thread->sigmask ); else thread->sigmask = parentthread->sigmask; cyg_pthread_exception_init( thread ); } externC void cyg_posix_thread_sigdestroy( pthread_info *thread ) { cyg_pthread_exception_destroy( thread ); } //========================================================================== // Functions to generate signals // ------------------------------------------------------------------------- // Deliver sig to a process. // eCos only supports the value 0 for pid. externC int kill (pid_t pid, int sig) { SIGNAL_ENTRY(); if( !SIGNAL_VALID(sig) ) SIGNAL_RETURN(EINVAL); if( pid != 0 ) SIGNAL_RETURN(ESRCH); struct sigevent sev; sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = sig; sev.sigev_value.sival_int = 0; cyg_sigqueue( &sev, SI_USER ); cyg_deliver_signals(); SIGNAL_RETURN(0); } // ------------------------------------------------------------------------- externC int pthread_kill (pthread_t threadid, int sig) { SIGNAL_ENTRY(); if( !SIGNAL_VALID(sig) ) SIGNAL_RETURN(EINVAL); struct sigevent sev; pthread_info *thread = pthread_info_id(threadid); if( thread == NULL ) SIGNAL_RETURN(ESRCH); sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = sig; sev.sigev_value.sival_int = 0; cyg_sigqueue( &sev, SI_USER, thread ); cyg_deliver_signals(); SIGNAL_RETURN(0); } //========================================================================== // Functions to catch signals // ------------------------------------------------------------------------- // Install signal handler for sig. externC int sigaction (int sig, const struct sigaction *act, struct sigaction *oact) { SIGNAL_ENTRY(); if( !SIGNAL_VALID(sig) ) SIGNAL_RETURN(EINVAL); signal_state *ss = &sigstate[sig]; signal_mutex.lock(); if( oact != NULL ) *oact = ss->sa; ss->sa = *act; if( ss->sa.sa_handler == SIG_IGN ) { // Setting the handler to SIG_IGN causes any pending // signals to be discarded and any queued values to also // be removed. pthread_info *self = pthread_self_info(); sigset_t sigbit = 1<<sig; if( (sig_pending | self->sigpending) & sigbit ) { // This signal is pending, clear it sig_pending &= ~sigbit; self->sigpending &= ~sigbit; // Clean out any queued signal_info objects while( ss->pending != NULL ) { signal_info *si = ss->pending->next; // 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; } } } cyg_deliver_signals(); signal_mutex.unlock(); SIGNAL_RETURN(0); } // ------------------------------------------------------------------------- // Queue signal to process with value. externC int sigqueue (pid_t pid, int sig, const union sigval value) { SIGNAL_ENTRY(); if( !SIGNAL_VALID(sig) ) SIGNAL_RETURN(EINVAL); struct sigevent sev; sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = sig; sev.sigev_value = value; cyg_sigqueue( &sev, SI_QUEUE ); cyg_deliver_signals(); SIGNAL_RETURN(0); } //========================================================================== // Functions to deal with current blocked and pending masks // ------------------------------------------------------------------------- // Set process blocked signal mask // Map this onto pthread_sigmask(). externC int sigprocmask (int how, const sigset_t *set, sigset_t *oset) { return pthread_sigmask( how, set, oset); } // ------------------------------------------------------------------------- // Set calling thread's blocked signal mask externC int pthread_sigmask (int how, const sigset_t *set, sigset_t *oset) { int err = 0; SIGNAL_ENTRY(); pthread_info *self = pthread_self_info(); // Save old set if( oset != NULL ) *oset = self->sigmask; if( set != NULL ) { switch( how ) { case SIG_BLOCK: self->sigmask |= *set; break; case SIG_UNBLOCK: self->sigmask &= ~*set; break; case SIG_SETMASK: self->sigmask = *set; break; default: err = EINVAL; break; } } // Deliver any newly unblocked signals cyg_deliver_signals(); SIGNAL_RETURN(err); } // ------------------------------------------------------------------------- // Exported routine to set calling thread's blocked signal mask // // Optionally set and return the current thread's signal mask. This is // exported to other packages so that they can manipulate the signal // mask without necessarily having them delivered (as calling // pthread_sigmask() would). Signals can be delivered by calling // cyg_posix_deliver_signals(). externC void cyg_pthread_sigmask_set (const sigset_t *set, sigset_t *oset) { pthread_info *self = pthread_self_info(); if( self != NULL ) { if( oset != NULL ) *oset = self->sigmask; if( set != NULL ) self->sigmask = *set; } } // ------------------------------------------------------------------------- // Exported routine to test for any pending signals. // // This routine tests for any pending undelivered, unmasked // signals. If there are any it returns true. This is exported to // other packages, such as FILEIO, so that they can detect whether to // abort a current API call with an EINTR result. externC cyg_bool cyg_posix_sigpending(void) { pthread_info *self = pthread_self_info(); if( self == NULL ) return false; return ( ((sig_pending | self->sigpending) & ~self->sigmask) != 0 ); } // ------------------------------------------------------------------------- // Exported routine to deliver selected signals // // This routine optionally sets the given mask and then tries to // deliver any pending signals that have been unmasked. This is // exported to other packages so that they can cause signals to be // delivered at controlled points during execution. externC void cyg_posix_deliver_signals( const sigset_t *mask ) { sigset_t oldmask; pthread_info *self = pthread_self_info(); if( self != NULL ) { if( mask != NULL ) { oldmask = self->sigmask; self->sigmask = *mask; } else oldmask = 0; // silence warning cyg_deliver_signals(); if( mask != NULL ) self->sigmask = oldmask; } } // ------------------------------------------------------------------------- // Get set of pending signals for this process externC int sigpending (sigset_t *set) { SIGNAL_ENTRY(); if( set == NULL ) SIGNAL_RETURN(EINVAL); pthread_info *self = pthread_self_info(); *set = self->sigpending | sig_pending; SIGNAL_RETURN(0); } //========================================================================== // Wait for or accept signals // ------------------------------------------------------------------------- // Block signals in set and wait for a signal externC int sigsuspend (const sigset_t *set) { SIGNAL_ENTRY(); pthread_info *self = pthread_self_info(); signal_mutex.lock(); // Save the old mask and set the current mask to // the one supplied. sigset_t old = self->sigmask; self->sigmask = *set; // Loop until a signal gets delivered while( !cyg_deliver_signals() ) signal_sigwait.wait(); self->sigmask = old; signal_mutex.unlock(); SIGNAL_RETURN(EINTR); } // ------------------------------------------------------------------------- // Wait for a signal in set to arrive // Implement this as a variant on sigtimedwait(). externC int sigwait (const sigset_t *set, int *sig) { SIGNAL_ENTRY(); siginfo_t info; int ret = sigtimedwait( set, &info, NULL ); if( ret == -1 ) SIGNAL_RETURN(errno); *sig = ret; SIGNAL_RETURN(0); } // ------------------------------------------------------------------------- // Do the same as sigwait() except return a siginfo_t object too. // Implement this as a variant on sigtimedwait(). externC int sigwaitinfo (const sigset_t *set, siginfo_t *info) { SIGNAL_ENTRY(); int ret = sigtimedwait( set, info, NULL ); SIGNAL_RETURN_VALUE(ret); } // ------------------------------------------------------------------------- // Wait either for a signal in the given set to become pending, or // for the timeout to expire. If timeout is NULL, wait for ever. externC int sigtimedwait (const sigset_t *set, siginfo_t *info, const struct timespec *timeout) { SIGNAL_ENTRY(); // check for cancellation first. pthread_testcancel(); int err = 0; cyg_tick_count ticks; if( timeout == NULL ) ticks = 0; else ticks = cyg_timespec_to_ticks( timeout ) + Cyg_Clock::real_time_clock->current_value(); pthread_info *self = pthread_self_info(); signal_mutex.lock(); sigset_t todo; // Wait for a signal in the set to become pending while( (todo = (*set & (sig_pending | self->sigpending))) == 0 ) { // If timeout is not NULL, do a timed wait on the // sigwait condition variable. If it is NULL - wait // until we are woken. if( timeout ) { if( ticks == 0 || !signal_sigwait.wait(ticks) ) { // If the timeout is actually zero, or we have waited and // timed out, then we must quit with an error. err = EAGAIN; break; } } else { if ( !signal_sigwait.wait() ) { // check we weren't woken up forcibly (e.g. to be cancelled) // if so, pretend it's an error err = EAGAIN; break; } } // Special case check for SIGALRM since the fact SIGALRM is masked // would have prevented it being set pending in the alarm handler. check_sigalarm(); cyg_posix_timer_asr(self); } if( err == 0 ) { // There is a signal in the set that is pending: deliver // it. todo contains a mask of all the signals that could be // delivered now, but we only want to deliver one of them. int signo = 0; // Select the lowest numbered signal from the todo mask HAL_LSBIT_INDEX( signo, todo ); signal_state *ss = &sigstate[signo]; sigset_t sigbit = 1L<<signo; if( (ss->sa.sa_flags & SA_SIGINFO) && (ss->pending != NULL) ) { // If the SA_SIGINFO bit is set, then there // will be a signal_info object queued on the // pending field. signal_info *si = ss->pending->next; *info = 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; si->next = siginfo_next; siginfo_next = si; } else { // Not a queued signal, or there is no signal_info object // on the pending queue: fill in info structure with // default values. info->si_signo = signo; info->si_code = SI_USER; info->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. 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; } // all done } signal_mutex.unlock(); pthread_testcancel(); if (err) SIGNAL_RETURN(err); else SIGNAL_RETURN_VALUE( info->si_signo ); } //========================================================================== // alarm, pause and sleep // ------------------------------------------------------------------------- // Generate SIGALRM after some number of seconds externC unsigned int alarm( unsigned int seconds ) { int res = 0; struct timespec tv; cyg_tick_count trigger, interval; SIGNAL_ENTRY(); signal_mutex.lock(); if( sigalrm_armed ) { sigalrm_alarm.disable(); sigalrm_alarm.get_times( &trigger, &interval ); // Convert trigger time back to interval trigger -= Cyg_Clock::real_time_clock->current_value(); cyg_ticks_to_timespec( trigger, &tv ); res = tv.tv_sec; sigalrm_armed = false; } if( seconds != 0 ) { // Here we know that the sigalrm_alarm is unarmed, set it up // to trigger in the required number of seconds. tv.tv_sec = seconds; tv.tv_nsec = 0; trigger = cyg_timespec_to_ticks( &tv ); // Convert trigger interval to absolute time trigger += Cyg_Clock::real_time_clock->current_value(); sigalrm_alarm.initialize( trigger, 0 ); sigalrm_armed = true; } signal_mutex.unlock(); CYG_REPORT_RETVAL(res); return res; } // ------------------------------------------------------------------------- // Wait for a signal to be delivered. externC int pause( void ) { SIGNAL_ENTRY(); signal_mutex.lock(); // Check for any pending signals that can be delivered and // if there are none, wait for a signal to be generated if( !cyg_deliver_signals() ) signal_sigwait.wait(); // Now check again for some signals to deliver cyg_deliver_signals(); signal_mutex.unlock(); SIGNAL_RETURN(EINTR); } //========================================================================== // Signal sets // ------------------------------------------------------------------------- // Clear all signals from set. externC int sigemptyset (sigset_t *set) { SIGNAL_ENTRY(); *set = 0; SIGNAL_RETURN(0); } // ------------------------------------------------------------------------- // Set all signals in set. externC int sigfillset (sigset_t *set) { SIGNAL_ENTRY(); *set = ~0; SIGNAL_RETURN(0); } // ------------------------------------------------------------------------- // Add signo to set. externC int sigaddset (sigset_t *set, int signo) { SIGNAL_ENTRY(); int err = 0; if( !SIGNAL_VALID(signo) ) err = EINVAL; else *set |= 1<<signo; SIGNAL_RETURN(err); } // ------------------------------------------------------------------------- // Remove signo from set. externC int sigdelset (sigset_t *set, int signo) { SIGNAL_ENTRY(); int err = 0; if( !SIGNAL_VALID(signo) ) err = EINVAL; else *set &= ~(1<<signo); SIGNAL_RETURN(err); } // ------------------------------------------------------------------------- // Test whether signo is in set externC int sigismember (const sigset_t *set, int signo) { SIGNAL_ENTRY(); int ret = 0; if( !SIGNAL_VALID(signo) ) SIGNAL_RETURN(EINVAL); if( *set & (1<<signo) ) ret = 1; CYG_REPORT_RETVAL( ret ); return ret; } //========================================================================== // ISO C compatibility functions // ------------------------------------------------------------------------- // Installs a new signal handler for the specified signal, and returns // the old handler externC sa_sighandler_t signal(int sig, sa_sighandler_t handler) { SIGNAL_ENTRY(); int err; sa_sighandler_t ret; struct sigaction new_action; struct sigaction old_action; sigemptyset( &new_action.sa_mask ); new_action.sa_flags = 0; new_action.sa_handler = handler; err = sigaction( sig, &new_action, &old_action ); if( err < 0 ) ret = SIG_ERR; else ret = old_action.sa_handler; CYG_REPORT_RETVAL( ret ); return ret; } // ------------------------------------------------------------------------- // raise() - ISO C 7.7.2 // // // Raises the signal, which will cause the current signal handler for // that signal to be called externC int raise(int sig) { return kill( 0, sig ); } // ------------------------------------------------------------------------- // siglongjmp() // Restores signal mask and longjumps. __externC void siglongjmp( sigjmp_buf env, int val ) { CYG_REPORT_FUNCNAME( "siglongjmp" ); CYG_REPORT_FUNCARG2( "&env=%08x, val=%d", &env, val ); // ISO C says that if we are passed val == 0, then we change it to 1 if( val == 0 ) val = 1; if( env[0].__savemask ) pthread_sigmask( SIG_SETMASK, &env[0].__sigsavemask, NULL ); HAL_REORDER_BARRIER(); // prevent any chance of optimisation re-ordering hal_longjmp( env[0].__jmp_buf, val ); HAL_REORDER_BARRIER(); // prevent any chance of optimisation re-ordering #ifdef CYGDBG_USE_ASSERTS CYG_ASSERT( 0, "siglongjmp should not have reached this point!" ); #else for (;;) CYG_EMPTY_STATEMENT; #endif } #endif // ifdef CYGPKG_POSIX_SIGNALS // ------------------------------------------------------------------------- // EOF signal.cxx
Go to most recent revision | Compare with Previous | Blame | View Log