diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index 8f58ca62b9..c39aeba2a2 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,9 @@ +2010-07-27 Vinu Rajashekhar + + PR 1630/cpukit + * posix/src/psignalchecksignal.c, posix/src/sigtimedwait.c: + sigtimedwait() was not completely following the POSIX specification. + 2010-07-26 Joel Sherrill * score/src/threadget.c: Conditionalize a check that can only occur diff --git a/cpukit/posix/src/psignalchecksignal.c b/cpukit/posix/src/psignalchecksignal.c index 1ed3bacdf7..8bba7a4226 100644 --- a/cpukit/posix/src/psignalchecksignal.c +++ b/cpukit/posix/src/psignalchecksignal.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,7 @@ bool _POSIX_signals_Check_signal( { siginfo_t siginfo_struct; sigset_t saved_signals_blocked; + Thread_Wait_information stored_thread_wait_information; if ( ! _POSIX_signals_Clear_signals( api, signo, &siginfo_struct, is_global, true ) ) @@ -72,6 +74,14 @@ bool _POSIX_signals_Check_signal( saved_signals_blocked = api->signals_blocked; api->signals_blocked |= _POSIX_signals_Vectors[ signo ].sa_mask; + /* + * We have to save the blocking information of the current wait queue + * because the signal handler may subsequently go on and put the thread + * on a wait queue, for its own purposes. + */ + memcpy( &stored_thread_wait_information, &_Thread_Executing->Wait, + sizeof( Thread_Wait_information )); + /* * Here, the signal handler function executes */ @@ -88,6 +98,12 @@ bool _POSIX_signals_Check_signal( break; } + /* + * Restore the blocking information + */ + memcpy( &_Thread_Executing->Wait, &stored_thread_wait_information, + sizeof( Thread_Wait_information )); + /* * Restore the previous set of blocked signals */ diff --git a/cpukit/posix/src/sigtimedwait.c b/cpukit/posix/src/sigtimedwait.c index 70b632b6de..41ebf88677 100644 --- a/cpukit/posix/src/sigtimedwait.c +++ b/cpukit/posix/src/sigtimedwait.c @@ -26,7 +26,7 @@ #include #include -int _POSIX_signals_Get_highest( +int _POSIX_signals_Get_lowest( sigset_t set ) { @@ -115,7 +115,7 @@ int sigtimedwait( _ISR_Disable( level ); if ( *set & api->signals_pending ) { /* XXX real info later */ - the_info->si_signo = _POSIX_signals_Get_highest( api->signals_pending ); + the_info->si_signo = _POSIX_signals_Get_lowest( api->signals_pending ); _POSIX_signals_Clear_signals( api, the_info->si_signo, @@ -133,7 +133,7 @@ int sigtimedwait( /* Process pending signals? */ if ( *set & _POSIX_signals_Pending ) { - signo = _POSIX_signals_Get_highest( _POSIX_signals_Pending ); + signo = _POSIX_signals_Get_lowest( _POSIX_signals_Pending ); _POSIX_signals_Clear_signals( api, signo, the_info, true, false ); _ISR_Enable( level ); @@ -161,6 +161,17 @@ int sigtimedwait( */ _POSIX_signals_Clear_signals( api, the_info->si_signo, the_info, false, false ); - errno = _Thread_Executing->Wait.return_code; + + /* Set errno only if return code is not EINTR or + * if EINTR was caused by a signal being caught, which + * was not in our set. + */ + + if ( (_Thread_Executing->Wait.return_code != EINTR) + || !(*set & signo_to_mask( the_info->si_signo )) ) { + errno = _Thread_Executing->Wait.return_code; + return -1; + } + return the_info->si_signo; }