/* * $Id$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Currently 32 signals numbered 1-32 are defined */ #define SIGNAL_EMPTY_MASK 0x00000000 #define SIGNAL_ALL_MASK 0xffffffff #define signo_to_mask( _sig ) (1 << ((_sig) - 1)) #define is_valid_signo( _sig ) \ ((_sig) >= 1 && (_sig) <= 32 ) /*** PROCESS WIDE STUFF ****/ sigset_t _POSIX_signals_Pending; void _POSIX_signals_Abormal_termination_handler( int signo ) { exit( 1 ); } #define _POSIX_signals_Stop_handler NULL #define _POSIX_signals_Continue_handler NULL #define SIGACTION_TERMINATE \ { 0, SIGNAL_ALL_MASK, {_POSIX_signals_Abormal_termination_handler} } #define SIGACTION_IGNORE \ { 0, SIGNAL_ALL_MASK, {SIG_IGN} } #define SIGACTION_STOP \ { 0, SIGNAL_ALL_MASK, {_POSIX_signals_Stop_handler} } #define SIGACTION_CONTINUE \ { 0, SIGNAL_ALL_MASK, {_POSIX_signals_Continue_handler} } #define SIG_ARRAY_MAX (SIGRTMAX + 1) struct sigaction _POSIX_signals_Default_vectors[ SIG_ARRAY_MAX ] = { /* NO SIGNAL 0 */ SIGACTION_IGNORE, /* SIGHUP 1 */ SIGACTION_TERMINATE, /* SIGINT 2 */ SIGACTION_TERMINATE, /* SIGQUIT 3 */ SIGACTION_TERMINATE, /* SIGILL 4 */ SIGACTION_TERMINATE, /* SIGTRAP 5 */ SIGACTION_TERMINATE, /* SIGIOT 6 */ SIGACTION_TERMINATE, /* SIGABRT 6 SIGACTION_TERMINATE, -- alias for SIGIOT */ /* SIGEMT 7 */ SIGACTION_TERMINATE, /* SIGFPE 8 */ SIGACTION_TERMINATE, /* SIGKILL 9 */ SIGACTION_TERMINATE, /* SIGBUS 10 */ SIGACTION_TERMINATE, /* SIGSEGV 11 */ SIGACTION_TERMINATE, /* SIGSYS 12 */ SIGACTION_TERMINATE, /* SIGPIPE 13 */ SIGACTION_TERMINATE, /* SIGALRM 14 */ SIGACTION_TERMINATE, /* SIGTERM 15 */ SIGACTION_TERMINATE, /* SIGUSR1 16 */ SIGACTION_TERMINATE, /* SIGUSR2 17 */ SIGACTION_TERMINATE, /* SIGRTMIN 18 */ SIGACTION_IGNORE, /* SIGRT 19 */ SIGACTION_IGNORE, /* SIGRT 20 */ SIGACTION_IGNORE, /* SIGRT 21 */ SIGACTION_IGNORE, /* SIGRT 22 */ SIGACTION_IGNORE, /* SIGRT 23 */ SIGACTION_IGNORE, /* SIGRT 24 */ SIGACTION_IGNORE, /* SIGRT 25 */ SIGACTION_IGNORE, /* SIGRT 26 */ SIGACTION_IGNORE, /* SIGRT 27 */ SIGACTION_IGNORE, /* SIGRT 28 */ SIGACTION_IGNORE, /* SIGRT 29 */ SIGACTION_IGNORE, /* SIGRT 30 */ SIGACTION_IGNORE, /* SIGRT 31 */ SIGACTION_IGNORE, /* SIGRTMAX 32 */ SIGACTION_IGNORE }; struct sigaction _POSIX_signals_Vectors[ SIG_ARRAY_MAX ]; Watchdog_Control _POSIX_signals_Alarm_timer; Thread_queue_Control _POSIX_signals_Wait_queue; Chain_Control _POSIX_signals_Inactive_siginfo; Chain_Control _POSIX_signals_Siginfo[ SIG_ARRAY_MAX ]; /*PAGE * * 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 */ boolean _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 *) the_thread->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 TRUE; } /* * This should only be reached via pthread_kill(). */ return FALSE; } 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 ); } } } return FALSE; } /*PAGE * * _POSIX_signals_Set_process_signals */ void _POSIX_signals_Set_process_signals( sigset_t mask ) { ISR_Level level; _ISR_Disable( level ); if ( !_POSIX_signals_Pending ) _Thread_Do_post_task_switch_extension++; _POSIX_signals_Pending |= mask; _ISR_Enable( level ); } /*PAGE * * _POSIX_signals_Clear_process_signals */ void _POSIX_signals_Clear_process_signals( sigset_t mask ) { ISR_Level level; _ISR_Disable( level ); _POSIX_signals_Pending &= ~mask; if ( !_POSIX_signals_Pending ) _Thread_Do_post_task_switch_extension--; _ISR_Enable( level ); } /*PAGE * * _POSIX_signals_Clear_signals */ boolean _POSIX_signals_Clear_signals( POSIX_API_Control *api, int signo, siginfo_t *info, boolean is_global, boolean check_blocked ) { sigset_t mask; sigset_t signals_blocked; ISR_Level level; boolean do_callout; POSIX_signals_Siginfo_node *psiginfo; mask = signo_to_mask( signo ); do_callout = FALSE; /* set blocked signals based on if checking for them, SIGNAL_ALL_MASK * insures that no signals are blocked and all are checked. */ if ( check_blocked ) signals_blocked = ~api->signals_blocked; else signals_blocked = SIGNAL_ALL_MASK; /* 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 & signals_blocked) ) { if ( _POSIX_signals_Vectors[ signo ].sa_flags == SA_SIGINFO ) { psiginfo = (POSIX_signals_Siginfo_node *) _Chain_Get_unprotected( &_POSIX_signals_Siginfo[ signo ] ); if ( _Chain_Is_empty( &_POSIX_signals_Siginfo[ signo ] ) ) _POSIX_signals_Clear_process_signals( mask ); if ( psiginfo ) { *info = psiginfo->Info; _Chain_Append_unprotected( &_POSIX_signals_Inactive_siginfo, &psiginfo->Node ); } else do_callout = FALSE; } else _POSIX_signals_Clear_process_signals( mask ); do_callout = TRUE; } } else { if ( mask & (api->signals_pending & signals_blocked) ) { api->signals_pending &= ~mask; do_callout = TRUE; } } _ISR_Enable( level ); return do_callout; } /*PAGE * * _POSIX_signals_Check_signal */ boolean _POSIX_signals_Check_signal( POSIX_API_Control *api, int signo, boolean is_global ) { siginfo_t siginfo_struct; sigset_t saved_signals_blocked; if ( ! _POSIX_signals_Clear_signals( api, signo, &siginfo_struct, is_global, TRUE ) ) return FALSE; /* * Since we made a union of these, only one test is necessary but this is * safer. */ assert( _POSIX_signals_Vectors[ signo ].sa_handler || _POSIX_signals_Vectors[ signo ].sa_sigaction ); /* * Just to prevent sending a signal which is currently being ignored. */ if ( _POSIX_signals_Vectors[ signo ].sa_handler == SIG_IGN ) return FALSE; /* * Block the signals requested in sa_mask */ saved_signals_blocked = api->signals_blocked; api->signals_blocked |= _POSIX_signals_Vectors[ signo ].sa_mask; switch ( _POSIX_signals_Vectors[ signo ].sa_flags ) { case SA_SIGINFO: assert( is_global ); (*_POSIX_signals_Vectors[ signo ].sa_sigaction)( signo, &siginfo_struct, NULL /* context is undefined per 1003.1b-1993, p. 66 */ ); break; default: (*_POSIX_signals_Vectors[ signo ].sa_handler)( signo ); break; } /* * Restore the previous set of blocked signals */ api->signals_blocked = saved_signals_blocked; return TRUE; } void _POSIX_signals_Post_switch_extension( Thread_Control *the_thread ) { POSIX_API_Control *api; int signo; ISR_Level level; api = the_thread->API_Extensions[ THREAD_API_POSIX ]; /* * If we invoke any user code, there is the possibility that * a new signal has been posted that we should process so we * restart the loop if a signal handler was invoked. * * The first thing done is to check there are any signals to be * processed at all. No point in doing this loop otherwise. */ restart: _ISR_Disable( level ); if ( !(~api->signals_blocked & (api->signals_pending | _POSIX_signals_Pending)) ) { _ISR_Enable( level ); return; } _ISR_Enable( level ); for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) { if ( _POSIX_signals_Check_signal( api, signo, FALSE ) ) goto restart; if ( _POSIX_signals_Check_signal( api, signo, TRUE ) ) goto restart; } /* XXX - add __SIGFIRSTNOTRT or something like that to newlib siginfo.h */ for ( signo = SIGHUP ; signo <= __SIGLASTNOTRT ; signo++ ) { if ( _POSIX_signals_Check_signal( api, signo, FALSE ) ) goto restart; if ( _POSIX_signals_Check_signal( api, signo, TRUE ) ) goto restart; } } /*PAGE * * _POSIX_signals_Alarm_TSR */ void _POSIX_signals_Alarm_TSR( Objects_Id id, void *argument ) { int status; status = kill( getpid(), SIGALRM ); /* XXX can't print from an ISR, should this be fatal? */ assert( !status ); } /*PAGE * * _POSIX_signals_Manager_Initialization */ void _POSIX_signals_Manager_Initialization( int maximum_queued_signals ) { unsigned32 signo; /* * Insure we have the same number of vectors and default vector entries */ assert( sizeof(_POSIX_signals_Vectors) == sizeof(_POSIX_signals_Default_vectors) ); memcpy( _POSIX_signals_Vectors, _POSIX_signals_Default_vectors, sizeof( _POSIX_signals_Vectors ) ); /* * Initialize the set of pending signals for the entire process */ sigemptyset( &_POSIX_signals_Pending ); /* * Initialize the timer used to implement alarm(). */ _Watchdog_Initialize( &_POSIX_signals_Alarm_timer, _POSIX_signals_Alarm_TSR, 0, 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 */ /* * Allocate the siginfo pools. */ for ( signo=1 ; signo<= SIGRTMAX ; signo++ ) _Chain_Initialize_empty( &_POSIX_signals_Siginfo[ signo ] ); _Chain_Initialize( &_POSIX_signals_Inactive_siginfo, _Workspace_Allocate_or_fatal_error( maximum_queued_signals * sizeof( POSIX_signals_Siginfo_node ) ), maximum_queued_signals, sizeof( POSIX_signals_Siginfo_node ) ); } /* * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 */ int sigemptyset( sigset_t *set ) { if ( !set ) set_errno_and_return_minus_one( EINVAL ); *set = 0; return 0; } /* * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 */ int sigfillset( sigset_t *set ) { if ( !set ) set_errno_and_return_minus_one( EINVAL ); *set = SIGNAL_ALL_MASK; return 0; } /* * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 */ int sigaddset( sigset_t *set, int signo ) { if ( !set ) set_errno_and_return_minus_one( EINVAL ); if ( !signo ) return 0; if ( !is_valid_signo(signo) ) set_errno_and_return_minus_one( EINVAL ); *set |= signo_to_mask(signo); return 0; } /* * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 */ int sigdelset( sigset_t *set, int signo ) { if ( !set ) set_errno_and_return_minus_one( EINVAL ); if ( !signo ) return 0; if ( !is_valid_signo(signo) ) set_errno_and_return_minus_one( EINVAL ); *set &= ~signo_to_mask(signo); return 0; } /* * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 */ int sigismember( const sigset_t *set, int signo ) { if ( !set ) set_errno_and_return_minus_one( EINVAL ); if ( !signo ) return 0; if ( !is_valid_signo(signo) ) set_errno_and_return_minus_one( EINVAL ); if ( *set & signo_to_mask(signo) ) return 1; return 0; } /* * 3.3.4 Examine and Change Signal Action, P1003.1b-1993, p. 70 */ int sigaction( int sig, const struct sigaction *act, struct sigaction *oact ) { ISR_Level level; if ( oact ) *oact = _POSIX_signals_Vectors[ sig ]; if ( !sig ) return 0; if ( !is_valid_signo(sig) ) set_errno_and_return_minus_one( EINVAL ); /* * Some signals cannot be ignored (P1003.1b-1993, pp. 70-72 and references. * * NOTE: Solaris documentation claims to "silently enforce" this which * contradicts the POSIX specification. */ if ( sig == SIGKILL ) set_errno_and_return_minus_one( EINVAL ); /* * Evaluate the new action structure and set the global signal vector * appropriately. */ if ( act ) { /* * Unless the user is installing the default signal actions, then * we can just copy the provided sigaction structure into the vectors. */ _ISR_Disable( level ); if ( act->sa_handler == SIG_DFL ) { _POSIX_signals_Vectors[ sig ] = _POSIX_signals_Default_vectors[ sig ]; } else { _POSIX_signals_Clear_process_signals( signo_to_mask(sig) ); _POSIX_signals_Vectors[ sig ] = *act; } _ISR_Enable( level ); } /* * No need to evaluate or dispatch because: * * + If we were ignoring the signal before, none could be pending * now (signals not posted when SIG_IGN). * + If we are now ignoring a signal that was previously pending, * we clear the pending signal indicator. */ return 0; } /* * 3.3.5 Examine and Change Blocked Signals, P1003.1b-1993, p. 73 * * NOTE: P1003.1c/D10, p. 37 adds pthread_sigmask(). * */ int sigprocmask( int how, const sigset_t *set, sigset_t *oset ) { /* * P1003.1c/Draft 10, p. 38 maps sigprocmask to pthread_sigmask. */ return pthread_sigmask( how, set, oset ); } /* * 3.3.5 Examine and Change Blocked Signals, P1003.1b-1993, p. 73 * * NOTE: P1003.1c/D10, p. 37 adds pthread_sigmask(). */ int pthread_sigmask( int how, const sigset_t *set, sigset_t *oset ) { POSIX_API_Control *api; if ( !set && !oset ) set_errno_and_return_minus_one( EINVAL ); api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; if ( oset ) *oset = api->signals_blocked; if ( !set ) return 0; switch ( how ) { case SIG_BLOCK: api->signals_blocked |= *set; break; case SIG_UNBLOCK: api->signals_blocked &= ~*set; break; case SIG_SETMASK: api->signals_blocked = *set; break; default: set_errno_and_return_minus_one( EINVAL ); } /* XXX are there critical section problems here? */ /* XXX evaluate the new set */ if ( ~api->signals_blocked & (api->signals_pending | _POSIX_signals_Pending) ) { _Thread_Executing->do_post_task_switch_extension = TRUE; _Thread_Dispatch(); } return 0; } /* * 3.3.6 Examine Pending Signals, P1003.1b-1993, p. 75 */ int sigpending( sigset_t *set ) { POSIX_API_Control *api; if ( !set ) set_errno_and_return_minus_one( EINVAL ); api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; *set = api->signals_pending | _POSIX_signals_Pending; return 0; } /* * 3.3.7 Wait for a Signal, P1003.1b-1993, p. 75 */ int sigsuspend( const sigset_t *sigmask ) { sigset_t saved_signals_blocked; sigset_t all_signals; int status; POSIX_API_Control *api; api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; status = sigprocmask( SIG_BLOCK, sigmask, &saved_signals_blocked ); (void) sigfillset( &all_signals ); status = sigtimedwait( &all_signals, NULL, NULL ); (void) sigprocmask( SIG_SETMASK, &saved_signals_blocked, NULL ); return status; } /* * 3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76 * * NOTE: P1003.1c/D10, p. 39 adds sigwait(). */ int sigwaitinfo( const sigset_t *set, siginfo_t *info ) { return sigtimedwait( set, info, NULL ); } /* * 3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76 * * 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; } /* XXX - add __SIGFIRSTNOTRT or something like that to newlib siginfo.h */ for ( signo = SIGHUP ; 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 ) { Thread_Control *the_thread; POSIX_API_Control *api; Watchdog_Interval interval; siginfo_t signal_information; siginfo_t *the_info; int signo; the_info = ( info ) ? info : &signal_information; the_thread = _Thread_Executing; api = the_thread->API_Extensions[ THREAD_API_POSIX ]; /* * What if they are already pending? */ /* API signals pending? */ if ( *set & api->signals_pending ) { /* XXX real info later */ the_info->si_signo = _POSIX_signals_Get_highest( api->signals_pending ); _POSIX_signals_Clear_signals( api, the_info->si_signo, the_info, FALSE, FALSE ); the_info->si_code = SI_USER; the_info->si_value.sival_int = 0; return the_info->si_signo; } /* Process pending signals? */ if ( *set & _POSIX_signals_Pending) { signo = _POSIX_signals_Get_highest( _POSIX_signals_Pending ); _POSIX_signals_Clear_signals( api, signo, the_info, TRUE, FALSE ); if ( !info ) { the_info->si_signo = signo; the_info->si_code = SI_USER; the_info->si_value.sival_int = 0; } } 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->si_signo = -1; _Thread_Disable_dispatch(); the_thread->Wait.queue = &_POSIX_signals_Wait_queue; 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; } /* * 3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76 * * NOTE: P1003.1c/D10, p. 39 adds sigwait(). */ int sigwait( const sigset_t *set, int *sig ) { int status; status = sigtimedwait( set, NULL, NULL ); if ( status != -1 ) { if ( sig ) *sig = status; return 0; } return errno; } /*PAGE * * 3.3.2 Send a Signal to a Process, P1003.1b-1993, p. 68 * * NOTE: Behavior of kill() depends on _POSIX_SAVED_IDS. */ #define _POSIX_signals_Is_interested( _api, _mask ) \ ( ~(_api)->signals_blocked & (_mask) ) int killinfo( pid_t pid, int sig, const union sigval *value ) { sigset_t mask; POSIX_API_Control *api; unsigned32 the_class; unsigned32 index; unsigned32 maximum; Objects_Information *the_info; Objects_Control **object_table; Thread_Control *the_thread; Thread_Control *interested_thread; Priority_Control interested_priority; Chain_Control *the_chain; Chain_Node *the_node; siginfo_t siginfo_struct; siginfo_t *siginfo; POSIX_signals_Siginfo_node *psiginfo; /* * Only supported for the "calling process" (i.e. this node). */ if( pid != getpid() ) set_errno_and_return_minus_one( ESRCH ); /* * Validate the signal passed if not 0. */ if ( sig && !is_valid_signo(sig) ) set_errno_and_return_minus_one( EINVAL ); /* * If the signal is being ignored, then we are out of here. */ if ( !sig || _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN ) return 0; /* * P1003.1c/Draft 10, p. 33 says that certain signals should always * be directed to the executing thread such as those caused by hardware * faults. */ switch ( sig ) { case SIGFPE: case SIGILL: case SIGSEGV: return pthread_kill( pthread_self(), sig ); default: break; } mask = signo_to_mask( sig ); /* * Build up a siginfo structure */ siginfo = &siginfo_struct; siginfo->si_signo = sig; siginfo->si_code = SI_USER; if ( !value ) { siginfo->si_value.sival_int = 0; } else { siginfo->si_value = *value; } _Thread_Disable_dispatch(); /* * Is the currently executing thread interested? If so then it will * get it an execute it as soon as the dispatcher executes. */ the_thread = _Thread_Executing; api = the_thread->API_Extensions[ THREAD_API_POSIX ]; if ( _POSIX_signals_Is_interested( api, mask ) ) { goto process_it; } /* * Is an interested thread waiting for this signal (sigwait())? */ /* 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 * thread is selected. In the event of a tie, then the following * additional criteria is used: * * + ready thread over blocked * + blocked on call interruptible by signal (can return EINTR) * + blocked on call not interruptible by signal * * This looks at every thread in the system regardless of the creating API. * * NOTES: * * + rtems internal threads do not receive signals. */ interested_thread = NULL; interested_priority = PRIORITY_MAXIMUM + 1; for ( the_class = OBJECTS_CLASSES_FIRST_THREAD_CLASS; the_class <= OBJECTS_CLASSES_LAST_THREAD_CLASS; the_class++ ) { if ( the_class == OBJECTS_INTERNAL_THREADS ) continue; the_info = _Objects_Information_table[ the_class ]; if ( !the_info ) /* manager not installed */ continue; maximum = the_info->maximum; object_table = the_info->local_table; assert( object_table ); /* always at least 1 entry */ for ( index = 1 ; index <= maximum ; index++ ) { the_thread = (Thread_Control *) object_table[ index ]; if ( !the_thread ) continue; /* * If this thread is of lower priority than the interested thread, * go on to the next thread. */ if ( the_thread->current_priority > interested_priority ) continue; /* * If this thread is not interested, then go on to the next thread. */ api = the_thread->API_Extensions[ THREAD_API_POSIX ]; if ( !api || !_POSIX_signals_Is_interested( api, mask ) ) continue; /* * Now we know the thread under connsideration is interested. * If the thread under consideration is of higher priority, then * it becomes the interested thread. */ if ( the_thread->current_priority < interested_priority ) { interested_thread = the_thread; interested_priority = the_thread->current_priority; continue; } /* * Now the thread and the interested thread have the same priority. * If the interested thread is ready, then we don't need to send it * to a blocked thread. */ if ( _States_Is_ready( interested_thread->current_state ) ) continue; /* * 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 ) ) { interested_thread = the_thread; interested_priority = the_thread->current_priority; continue; } /* * Now we know both threads are blocked. * If the interested thread is interruptible, then just use it. */ /* XXX need a new states macro */ if ( interested_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) continue; /* * 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. */ /* XXX need a new states macro */ if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) { interested_thread = the_thread; interested_priority = the_thread->current_priority; } } } if ( interested_thread ) { the_thread = interested_thread; goto process_it; } /* * OK so no threads were interested right now. It will be left on the * global pending until a thread receives it. The global set of threads * can change interest in this signal in one of the following ways: * * + a thread is created with the signal unblocked, * + pthread_sigmask() unblocks the signal, * + sigprocmask() unblocks the signal, OR * + sigaction() which changes the handler to SIG_IGN. */ the_thread = NULL; goto post_process_signal; /* * We found a thread which was interested, so now we mark that this * thread needs to do the post context switch extension so it can * evaluate the signals pending. */ process_it: the_thread->do_post_task_switch_extension = TRUE; /* * Returns TRUE if the signal was synchronously given to a thread * blocked waiting for the signal. */ if ( _POSIX_signals_Unblock_thread( the_thread, sig, siginfo ) ) { _Thread_Enable_dispatch(); return 0; } post_process_signal: /* * We may have woken up a thread but we definitely need to post the * signal to the process wide information set. */ _POSIX_signals_Set_process_signals( mask ); if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO ) { psiginfo = (POSIX_signals_Siginfo_node *) _Chain_Get( &_POSIX_signals_Inactive_siginfo ); if ( !psiginfo ) set_errno_and_return_minus_one( EAGAIN ); psiginfo->Info = *siginfo; _Chain_Append( &_POSIX_signals_Siginfo[ sig ], &psiginfo->Node ); } _Thread_Enable_dispatch(); return 0; } /*PAGE * * 3.3.2 Send a Signal to a Process, P1003.1b-1993, p. 68 * * NOTE: Behavior of kill() depends on _POSIX_SAVED_IDS. */ int kill( pid_t pid, int sig ) { return killinfo( pid, sig, NULL ); } /* * 3.3.9 Queue a Signal to a Process, P1003.1b-1993, p. 78 */ int sigqueue( pid_t pid, int signo, const union sigval value ) { return killinfo( pid, signo, &value ); } /* * 3.3.10 Send a Signal to a Thread, P1003.1c/D10, p. 43 */ int pthread_kill( pthread_t thread, int sig ) { POSIX_API_Control *api; Thread_Control *the_thread; Objects_Locations location; if ( sig && !is_valid_signo(sig) ) set_errno_and_return_minus_one( EINVAL ); if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO ) set_errno_and_return_minus_one( ENOSYS ); /* * RTEMS does not support sending a siginfo signal to a specific thread. */ the_thread = _POSIX_Threads_Get( thread, &location ); switch ( location ) { case OBJECTS_ERROR: case OBJECTS_REMOTE: set_errno_and_return_minus_one( ESRCH ); case OBJECTS_LOCAL: /* * If sig == 0 then just validate arguments */ api = the_thread->API_Extensions[ THREAD_API_POSIX ]; if ( sig ) { if ( _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN ) { _Thread_Enable_dispatch(); return 0; } /* XXX critical section */ api->signals_pending |= signo_to_mask( sig ); (void) _POSIX_signals_Unblock_thread( the_thread, sig, NULL ); the_thread->do_post_task_switch_extension = TRUE; if ( _ISR_Is_in_progress() && _Thread_Is_executing( the_thread ) ) _ISR_Signals_to_thread_executing = TRUE; } _Thread_Enable_dispatch(); return 0; } return POSIX_BOTTOM_REACHED(); } /* * 3.4.1 Schedule Alarm, P1003.1b-1993, p. 79 */ Watchdog_Control _POSIX_signals_Alarm_timer; unsigned int alarm( unsigned int seconds ) { unsigned int remaining = 0; Watchdog_Control *the_timer; the_timer = &_POSIX_signals_Alarm_timer; switch ( _Watchdog_Remove( the_timer ) ) { case WATCHDOG_INACTIVE: case WATCHDOG_BEING_INSERTED: break; case WATCHDOG_ACTIVE: case WATCHDOG_REMOVE_IT: remaining = the_timer->initial - (the_timer->stop_time - the_timer->start_time); break; } _Watchdog_Insert_seconds( the_timer, seconds ); return remaining; } /* * 3.4.2 Suspend Process Execution, P1003.1b-1993, p. 81 */ int pause( void ) { sigset_t all_signals; int status; (void) sigfillset( &all_signals ); status = sigtimedwait( &all_signals, NULL, NULL ); return status; }