diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 1996-06-12 17:45:01 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 1996-06-12 17:45:01 +0000 |
commit | 2291b7165484739175f7d57981be3951e324cfce (patch) | |
tree | 87b7f121bc1851d77ec35958ad33143856a5cdcb /cpukit | |
parent | added comment to make sure we add unblock of thread (diff) | |
download | rtems-2291b7165484739175f7d57981be3951e324cfce.tar.bz2 |
initial implementation of blocking signal routines -- sigwait, sigwaitinfo,
sigtimedwait, sigsuspend, and pause.
Diffstat (limited to 'cpukit')
-rw-r--r-- | cpukit/posix/src/psignal.c | 261 |
1 files changed, 227 insertions, 34 deletions
diff --git a/cpukit/posix/src/psignal.c b/cpukit/posix/src/psignal.c index b1e9a9e586..a5a63f1d6b 100644 --- a/cpukit/posix/src/psignal.c +++ b/cpukit/posix/src/psignal.c @@ -10,9 +10,11 @@ #include <rtems/system.h> #include <rtems/score/isr.h> #include <rtems/score/thread.h> +#include <rtems/score/tqdata.h> #include <rtems/posix/seterr.h> #include <rtems/posix/threadsup.h> #include <rtems/posix/pthread.h> +#include <rtems/posix/time.h> /* * Currently 32 signals numbered 1-32 are defined @@ -88,6 +90,8 @@ struct sigaction _POSIX_signals_Vectors[ SIG_ARRAY_MAX ]; Watchdog_Control _POSIX_signals_Alarm_timer; +Thread_queue_Control _POSIX_signals_Wait_queue; + typedef struct { Chain_Node Node; siginfo_t Info; @@ -98,7 +102,78 @@ Chain_Control _POSIX_signals_Siginfo[ SIG_ARRAY_MAX ]; /*PAGE * - * XXX + * XXX - move these + */ + +#define _States_Is_interruptible_signal( _states ) \ + ( ((_states) & \ + (STATES_WAITING_FOR_SIGNAL|STATES_INTERRUPTIBLE_BY_SIGNAL)) == \ + (STATES_WAITING_FOR_SIGNAL|STATES_INTERRUPTIBLE_BY_SIGNAL)) + +/*PAGE + * + * _POSIX_signals_Unblock_thread + */ + +/* XXX this routine could probably be cleaned up */ +void _POSIX_signals_Unblock_thread( + Thread_Control *the_thread, + int signo, + siginfo_t *info +) +{ + POSIX_API_Control *api; + sigset_t mask; + siginfo_t *the_info = NULL; + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + mask = signo_to_mask( signo ); + + /* + * Is the thread is specifically waiting for a signal? + */ + + if ( _States_Is_interruptible_signal( the_thread->current_state ) ) { + + if ( (the_thread->Wait.option & mask) || (~api->signals_blocked & mask) ) { + the_thread->Wait.return_code = EINTR; + + the_info = (siginfo_t *) _Thread_Executing->Wait.return_argument; + + if ( !info ) { + the_info->si_signo = signo; + the_info->si_code = SI_USER; + the_info->si_value.sival_int = 0; + } else { + *the_info = *info; + } + + _Thread_queue_Extract_with_proxy( the_thread ); + } + return; + } + + if ( ~api->signals_blocked & mask ) { + the_thread->do_post_task_switch_extension = TRUE; + + if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) { + the_thread->Wait.return_code = EINTR; + if ( _States_Is_waiting_on_thread_queue(the_thread->current_state) ) + _Thread_queue_Extract_with_proxy( the_thread ); + else if ( _States_Is_delaying(the_thread->current_state)){ + if ( _Watchdog_Is_active( &the_thread->Timer ) ) + (void) _Watchdog_Remove( &the_thread->Timer ); + _Thread_Unblock( the_thread ); + } + } + } + +} + +/*PAGE + * + * _POSIX_signals_Check_signal */ boolean _POSIX_signals_Check_signal( @@ -120,6 +195,7 @@ boolean _POSIX_signals_Check_signal( /* XXX this is not right for siginfo type signals yet */ /* XXX since they can't be cleared the same way */ + _ISR_Disable( level ); if ( is_global ) { if ( mask & (_POSIX_signals_Pending & ~api->signals_blocked ) ) { @@ -289,6 +365,20 @@ void _POSIX_signals_Manager_Initialization( void ) NULL ); + /* + * Initialize the queue we use to block for signals + */ + + _Thread_queue_Initialize( + &_POSIX_signals_Wait_queue, + OBJECTS_NO_CLASS, + THREAD_QUEUE_DISCIPLINE_PRIORITY, + STATES_WAITING_FOR_SIGNAL | STATES_INTERRUPTIBLE_BY_SIGNAL, + NULL, + EAGAIN + ); + + /* XXX status codes */ /* * XXX Allocate the siginfo pools. */ @@ -547,7 +637,22 @@ int sigsuspend( const sigset_t *sigmask ) { - return POSIX_NOT_IMPLEMENTED(); + sigset_t saved_signals_blocked; + sigset_t all_signals; + int status; + POSIX_API_Control *api; + + api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + saved_signals_blocked = api->signals_blocked; + + (void) sigfillset( &all_signals ); + + status = sigtimedwait( &all_signals, NULL, NULL ); + + api->signals_blocked = saved_signals_blocked; + + return status; } /* @@ -561,7 +666,7 @@ int sigwaitinfo( siginfo_t *info ) { - return POSIX_NOT_IMPLEMENTED(); + return sigtimedwait( set, info, NULL ); } /* @@ -570,13 +675,74 @@ int sigwaitinfo( * NOTE: P1003.1c/D10, p. 39 adds sigwait(). */ +int _POSIX_signals_Get_highest( + sigset_t set +) +{ + int signo; + + for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) { + if ( set & signo_to_mask( signo ) ) + return signo; + } + + for ( signo = SIGABRT ; signo <= __SIGLASTNOTRT ; signo++ ) { + if ( set & signo_to_mask( signo ) ) + return signo; + } + + return 0; +} + + int sigtimedwait( const sigset_t *set, siginfo_t *info, const struct timespec *timeout ) { - return POSIX_NOT_IMPLEMENTED(); + Thread_Control *the_thread; + POSIX_API_Control *api; + Watchdog_Interval interval; + siginfo_t signal_information; + siginfo_t *the_info; + + interval = 0; + if ( timeout ) { + + if (timeout->tv_nsec < 0 || timeout->tv_nsec >= TOD_NANOSECONDS_PER_SECOND) + set_errno_and_return_minus_one( EINVAL ); + + interval = _POSIX_Timespec_to_interval( timeout ); + } + + the_info = ( info ) ? info : &signal_information; + + the_thread = _Thread_Executing; + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + /* + * What if they are already pending? + */ + + if ( *set & api->signals_pending ) { + /* XXX real info later */ + the_info->si_signo = _POSIX_signals_Get_highest( api->signals_pending ); + the_info->si_code = SI_USER; + the_info->si_value.sival_int = 0; + } + + _Thread_Disable_dispatch(); + the_thread->Wait.return_code = EINTR; + the_thread->Wait.option = *set; + the_thread->Wait.return_argument = (void *) the_info; + _Thread_queue_Enter_critical_section( &_POSIX_signals_Wait_queue ); + _Thread_queue_Enqueue( &_POSIX_signals_Wait_queue, interval ); + _Thread_Enable_dispatch(); + + errno = _Thread_Executing->Wait.return_code; + return the_info->si_signo; } /* @@ -590,7 +756,17 @@ int sigwait( int *sig ) { - return POSIX_NOT_IMPLEMENTED(); + int status; + + status = sigtimedwait( set, NULL, NULL ); + + if ( status != -1 ) { + if ( sig ) + *sig = status; + return 0; + } + + return errno; } /* @@ -630,8 +806,9 @@ int kill( Thread_Control *the_thread; Thread_Control *interested_thread; Priority_Control interested_priority; - - + Chain_Control *the_chain; + Chain_Node *the_node; + /* * Only supported for the "calling process" (i.e. this node). */ @@ -681,7 +858,27 @@ int kill( * Is an interested thread waiting for this signal (sigwait())? */ - /* XXX wait for signal functions need to be done */ + /* XXX violation of visibility -- need to define thread queue support */ + + for( index=0 ; + index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ; + index++ ) { + + the_chain = &_POSIX_signals_Wait_queue.Queues.Priority[ index ]; + + for ( the_node = the_chain->first ; + !_Chain_Is_tail( the_chain, the_node ) ; + the_node = the_node->next ) { + + the_thread = (Thread_Control *)the_node; + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + if ((the_thread->Wait.option & mask) || (~api->signals_blocked & mask)) { + goto process_it; + } + + } + } /* * Is any other thread interested? The highest priority interested @@ -711,13 +908,13 @@ int kill( the_info = _Objects_Information_table[ the_class ]; - if ( !the_info ) + if ( !the_info ) /* manager not installed */ continue; maximum = the_info->maximum; object_table = the_info->local_table; - assert( object_table ); + assert( object_table ); /* always at least 1 entry */ object_table++; /* skip entry 0 */ @@ -742,7 +939,8 @@ int kill( continue; /* - * If this thread is of higher priority logically and interested, then + * Now we know the thread under connsideration is interested. + * If the thread under consideration is of higher priority, then * it becomes the interested thread. */ @@ -762,8 +960,9 @@ int kill( continue; /* - * The interested thread is blocked and the thread we are considering - * is not, so it becomes the interested thread. + * Now the interested thread is blocked. + * If the thread we are considering is not, the it becomes the + * interested thread. */ if ( _States_Is_ready( the_thread->current_state ) ) { @@ -773,6 +972,7 @@ int kill( } /* + * Now we know both threads are blocked. * If the interested thread is interruptible, then just use it. */ @@ -781,8 +981,8 @@ int kill( continue; /* - * Both the thread under consideration and the interested thread are - * blocked and the interested thread is not interruptible by a signal. + * Now both threads are blocked and the interested thread is not + * interruptible. * If the thread under consideration is interruptible by a signal, * then it becomes the interested thread. */ @@ -821,12 +1021,13 @@ int kill( */ process_it: - /* XXX what if the thread is blocked? -- need code from pthread_kill */ - /* XXX and it needs to be in a subroutine */ + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; the_thread->do_post_task_switch_extension = TRUE; + _POSIX_signals_Unblock_thread( the_thread, sig, NULL ); + _Thread_Enable_dispatch(); /* XXX take this out when a little more confident */ @@ -874,22 +1075,7 @@ int pthread_kill( api->signals_pending |= signo_to_mask( sig ); - if ( api->signals_pending & ~api->signals_blocked ) { - the_thread->do_post_task_switch_extension = TRUE; - - /* XXX unblock the task -- this is a kludge -- fix it */ - - if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) { - the_thread->Wait.return_code = EINTR; - if ( _States_Is_waiting_on_thread_queue(the_thread->current_state) ) - _Thread_queue_Extract_with_proxy( the_thread ); - else if ( _States_Is_delaying(the_thread->current_state)){ - if ( _Watchdog_Is_active( &the_thread->Timer ) ) - (void) _Watchdog_Remove( &the_thread->Timer ); - _Thread_Unblock( the_thread ); - } - } - } + _POSIX_signals_Unblock_thread( the_thread, sig, NULL ); } _Thread_Enable_dispatch(); return 0; @@ -936,5 +1122,12 @@ unsigned int alarm( int pause( void ) { - return POSIX_NOT_IMPLEMENTED(); + sigset_t all_signals; + int status; + + (void) sigfillset( &all_signals ); + + status = sigtimedwait( &all_signals, NULL, NULL ); + + return status; } |