summaryrefslogtreecommitdiffstats
path: root/cpukit/posix/src/psignal.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/posix/src/psignal.c')
-rw-r--r--cpukit/posix/src/psignal.c1347
1 files changed, 1347 insertions, 0 deletions
diff --git a/cpukit/posix/src/psignal.c b/cpukit/posix/src/psignal.c
new file mode 100644
index 0000000000..289c9f02d5
--- /dev/null
+++ b/cpukit/posix/src/psignal.c
@@ -0,0 +1,1347 @@
+/*
+ * $Id$
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include <rtems/system.h>
+#include <rtems/score/isr.h>
+#include <rtems/score/thread.h>
+#include <rtems/score/tqdata.h>
+#include <rtems/score/wkspace.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
+ */
+
+#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;
+
+typedef struct {
+ Chain_Node Node;
+ siginfo_t Info;
+} POSIX_signals_Siginfo_node;
+
+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;
+}