From c31058947491ca319c901040219be39e4f8155b6 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 19 Oct 2017 13:47:57 +0200 Subject: score: Move thread queue timeout handling Update #3117. Update #3182. --- cpukit/posix/include/rtems/posix/mqueueimpl.h | 25 +-- cpukit/posix/include/rtems/posix/muteximpl.h | 32 ++-- cpukit/posix/src/condwaitsupp.c | 126 +++++++------ cpukit/posix/src/mqueuereceive.c | 15 +- cpukit/posix/src/mqueuerecvsupp.c | 29 +-- cpukit/posix/src/mqueuesend.c | 4 +- cpukit/posix/src/mqueuesendsupp.c | 26 +-- cpukit/posix/src/mqueuetimedreceive.c | 36 +--- cpukit/posix/src/mqueuetimedsend.c | 36 +--- cpukit/posix/src/mutexlock.c | 13 +- cpukit/posix/src/mutexlocksupp.c | 20 +- cpukit/posix/src/mutextimedlock.c | 50 +---- cpukit/posix/src/mutextrylock.c | 24 +-- cpukit/posix/src/nanosleep.c | 255 +++++++++----------------- cpukit/posix/src/pbarrierwait.c | 1 - cpukit/posix/src/prwlockrdlock.c | 2 +- cpukit/posix/src/prwlocktimedrdlock.c | 47 +---- cpukit/posix/src/prwlocktimedwrlock.c | 47 +---- cpukit/posix/src/prwlockwrlock.c | 2 +- cpukit/posix/src/pthreadjoin.c | 1 - cpukit/posix/src/semtimedwait.c | 23 +-- cpukit/posix/src/sigtimedwait.c | 25 ++- 22 files changed, 280 insertions(+), 559 deletions(-) (limited to 'cpukit/posix') diff --git a/cpukit/posix/include/rtems/posix/mqueueimpl.h b/cpukit/posix/include/rtems/posix/mqueueimpl.h index 5888800ca1..6813a3ef88 100644 --- a/cpukit/posix/include/rtems/posix/mqueueimpl.h +++ b/cpukit/posix/include/rtems/posix/mqueueimpl.h @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -63,12 +64,12 @@ void _POSIX_Message_queue_Delete( * @note This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open time. */ ssize_t _POSIX_Message_queue_Receive_support( - mqd_t mqdes, - char *msg_ptr, - size_t msg_len, - unsigned int *msg_prio, - bool wait, - Watchdog_Interval timeout + mqd_t mqdes, + char *msg_ptr, + size_t msg_len, + unsigned int *msg_prio, + const struct timespec *abstime, + Thread_queue_Enqueue_callout enqueue_callout ); /** @@ -77,12 +78,12 @@ ssize_t _POSIX_Message_queue_Receive_support( * This routine posts a message to a specified message queue. */ int _POSIX_Message_queue_Send_support( - mqd_t mqdes, - const char *msg_ptr, - size_t msg_len, - unsigned int msg_prio, - bool wait, - Watchdog_Interval timeout + mqd_t mqdes, + const char *msg_ptr, + size_t msg_len, + unsigned int msg_prio, + const struct timespec *abstime, + Thread_queue_Enqueue_callout enqueue_callout ); RTEMS_INLINE_ROUTINE POSIX_Message_queue_Control * diff --git a/cpukit/posix/include/rtems/posix/muteximpl.h b/cpukit/posix/include/rtems/posix/muteximpl.h index f146e0d9db..435b43634d 100644 --- a/cpukit/posix/include/rtems/posix/muteximpl.h +++ b/cpukit/posix/include/rtems/posix/muteximpl.h @@ -132,7 +132,7 @@ Status_Control _POSIX_Mutex_Seize_slow( POSIX_Mutex_Control *the_mutex, const Thread_queue_Operations *operations, Thread_Control *executing, - bool wait, + const struct timespec *abstime, Thread_queue_Context *queue_context ); @@ -171,7 +171,7 @@ RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Seize( unsigned long flags, const Thread_queue_Operations *operations, Thread_Control *executing, - bool wait, + const struct timespec *abstime, Thread_queue_Context *queue_context ) { @@ -198,7 +198,7 @@ RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Seize( the_mutex, operations, executing, - wait, + abstime, queue_context ); } @@ -329,11 +329,11 @@ RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Ceiling_set_owner( } RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Ceiling_seize( - POSIX_Mutex_Control *the_mutex, - unsigned long flags, - Thread_Control *executing, - bool wait, - Thread_queue_Context *queue_context + POSIX_Mutex_Control *the_mutex, + unsigned long flags, + Thread_Control *executing, + const struct timespec *abstime, + Thread_queue_Context *queue_context ) { Thread_Control *owner; @@ -371,7 +371,7 @@ RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Ceiling_seize( the_mutex, POSIX_MUTEX_PRIORITY_CEILING_TQ_OPERATIONS, executing, - wait, + abstime, queue_context ); } @@ -444,16 +444,12 @@ RTEMS_INLINE_ROUTINE Status_Control _POSIX_Mutex_Ceiling_surrender( return STATUS_SUCCESSFUL; } -/** - * @brief POSIX Mutex Lock Support Method - * - * A support routine which implements guts of the blocking, non-blocking, and - * timed wait version of mutex lock. - */ +#define POSIX_MUTEX_ABSTIME_TRY_LOCK ((uintptr_t) 1) + int _POSIX_Mutex_Lock_support( - pthread_mutex_t *mutex, - bool blocking, - Watchdog_Interval timeout + pthread_mutex_t *mutex, + const struct timespec *abstime, + Thread_queue_Enqueue_callout enqueue_callout ); static inline POSIX_Mutex_Control *_POSIX_Mutex_Get( diff --git a/cpukit/posix/src/condwaitsupp.c b/cpukit/posix/src/condwaitsupp.c index ceaa6eb1af..32c1eab629 100644 --- a/cpukit/posix/src/condwaitsupp.c +++ b/cpukit/posix/src/condwaitsupp.c @@ -25,7 +25,7 @@ #include #include -static void _POSIX_Condition_variables_Enqueue_callout( +static void _POSIX_Condition_variables_Mutex_unlock( Thread_queue_Queue *queue, Thread_Control *the_thread, Thread_queue_Context *queue_context @@ -44,11 +44,52 @@ static void _POSIX_Condition_variables_Enqueue_callout( * case, so we follow their lead. */ _Assert( mutex_error == EINVAL || mutex_error == EPERM ); - _Thread_queue_Extract( the_thread ); - the_thread->Wait.return_code= STATUS_NOT_OWNER; + _Thread_Continue( the_thread, STATUS_NOT_OWNER ); } } +static void _POSIX_Condition_variables_Enqueue_no_timeout( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context +) +{ + _POSIX_Condition_variables_Mutex_unlock( queue, the_thread, queue_context ); +} + +static void _POSIX_Condition_variables_Enqueue_with_timeout_monotonic( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context +) +{ + _Thread_queue_Add_timeout_monotonic_timespec( + queue, + the_thread, + cpu_self, + queue_context + ); + _POSIX_Condition_variables_Mutex_unlock( queue, the_thread, queue_context ); +} + +static void _POSIX_Condition_variables_Enqueue_with_timeout_realtime( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context +) +{ + _Thread_queue_Add_timeout_realtime_timespec( + queue, + the_thread, + cpu_self, + queue_context + ); + _POSIX_Condition_variables_Mutex_unlock( queue, the_thread, queue_context ); +} + int _POSIX_Condition_variables_Wait_support( pthread_cond_t *cond, pthread_mutex_t *mutex, @@ -59,44 +100,32 @@ int _POSIX_Condition_variables_Wait_support( unsigned long flags; Thread_queue_Context queue_context; int error; - int mutex_error; Thread_Control *executing; - Watchdog_Interval timeout; - bool already_timedout; - TOD_Absolute_timeout_conversion_results status; the_cond = _POSIX_Condition_variables_Get( cond ); POSIX_CONDITION_VARIABLES_VALIDATE_OBJECT( the_cond, flags ); _Thread_queue_Context_initialize( &queue_context ); - already_timedout = false; if ( abstime != NULL ) { - /* - * POSIX requires that blocking calls with timeouts that take - * an absolute timeout must ignore issues with the absolute - * time provided if the operation would otherwise succeed. - * So we check the abstime provided, and hold on to whether it - * is valid or not. If it isn't correct and in the future, - * then we do a polling operation and convert the UNSATISFIED - * status into the appropriate error. - */ - status = _TOD_Absolute_timeout_to_ticks( - abstime, - _POSIX_Condition_variables_Get_clock( flags ), - &timeout - ); - if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID ) - return EINVAL; + _Thread_queue_Context_set_timeout_argument( &queue_context, abstime ); - if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST || - status == TOD_ABSOLUTE_TIMEOUT_IS_NOW ) { - already_timedout = true; + if ( _POSIX_Condition_variables_Get_clock( flags ) == CLOCK_MONOTONIC ) { + _Thread_queue_Context_set_enqueue_callout( + &queue_context, + _POSIX_Condition_variables_Enqueue_with_timeout_monotonic + ); } else { - _Thread_queue_Context_set_relative_timeout( &queue_context, timeout ); + _Thread_queue_Context_set_enqueue_callout( + &queue_context, + _POSIX_Condition_variables_Enqueue_with_timeout_realtime + ); } } else { - _Thread_queue_Context_set_no_timeout( &queue_context ); + _Thread_queue_Context_set_enqueue_callout( + &queue_context, + _POSIX_Condition_variables_Enqueue_no_timeout + ); } executing = _POSIX_Condition_variables_Acquire( the_cond, &queue_context ); @@ -111,32 +140,17 @@ int _POSIX_Condition_variables_Wait_support( the_cond->mutex = mutex; - if ( !already_timedout ) { - _Thread_queue_Context_set_thread_state( - &queue_context, - STATES_WAITING_FOR_CONDITION_VARIABLE - ); - _Thread_queue_Context_set_enqueue_callout( - &queue_context, - _POSIX_Condition_variables_Enqueue_callout - ); - _Thread_queue_Enqueue( - &the_cond->Queue.Queue, - POSIX_CONDITION_VARIABLES_TQ_OPERATIONS, - executing, - &queue_context - ); - error = _POSIX_Get_error_after_wait( executing ); - } else { - _POSIX_Condition_variables_Release( the_cond, &queue_context ); - - mutex_error = pthread_mutex_unlock( the_cond->mutex ); - if ( mutex_error != 0 ) { - error = EPERM; - } else { - error = ETIMEDOUT; - } - } + _Thread_queue_Context_set_thread_state( + &queue_context, + STATES_WAITING_FOR_CONDITION_VARIABLE + ); + _Thread_queue_Enqueue( + &the_cond->Queue.Queue, + POSIX_CONDITION_VARIABLES_TQ_OPERATIONS, + executing, + &queue_context + ); + error = _POSIX_Get_error_after_wait( executing ); /* * If the thread is interrupted, while in the thread queue, by @@ -155,6 +169,8 @@ int _POSIX_Condition_variables_Wait_support( */ if ( error != EPERM ) { + int mutex_error; + mutex_error = pthread_mutex_lock( mutex ); if ( mutex_error != 0 ) { _Assert( mutex_error == EINVAL ); diff --git a/cpukit/posix/src/mqueuereceive.c b/cpukit/posix/src/mqueuereceive.c index 465cd79cec..c160634dc5 100644 --- a/cpukit/posix/src/mqueuereceive.c +++ b/cpukit/posix/src/mqueuereceive.c @@ -18,17 +18,6 @@ #include "config.h" #endif -#include - -#include -#include -#include -#include -#include - -#include -#include -#include #include ssize_t mq_receive( @@ -43,7 +32,7 @@ ssize_t mq_receive( msg_ptr, msg_len, msg_prio, - true, - WATCHDOG_NO_TIMEOUT + NULL, + _Thread_queue_Enqueue_do_nothing_extra ); } diff --git a/cpukit/posix/src/mqueuerecvsupp.c b/cpukit/posix/src/mqueuerecvsupp.c index 416e7989fd..c6d1805214 100644 --- a/cpukit/posix/src/mqueuerecvsupp.c +++ b/cpukit/posix/src/mqueuerecvsupp.c @@ -36,18 +36,17 @@ THREAD_QUEUE_OBJECT_ASSERT( */ ssize_t _POSIX_Message_queue_Receive_support( - mqd_t mqdes, - char *msg_ptr, - size_t msg_len, - unsigned int *msg_prio, - bool wait, - Watchdog_Interval timeout + mqd_t mqdes, + char *msg_ptr, + size_t msg_len, + unsigned int *msg_prio, + const struct timespec *abstime, + Thread_queue_Enqueue_callout enqueue_callout ) { POSIX_Message_queue_Control *the_mq; Thread_queue_Context queue_context; size_t length_out; - bool do_wait; Thread_Control *executing; Status_Control status; @@ -67,22 +66,15 @@ ssize_t _POSIX_Message_queue_Receive_support( rtems_set_errno_and_return_minus_one( EMSGSIZE ); } + _Thread_queue_Context_set_enqueue_callout( &queue_context, enqueue_callout ); + _Thread_queue_Context_set_timeout_argument( &queue_context, abstime ); + /* * Now if something goes wrong, we return a "length" of -1 * to indicate an error. */ - length_out = -1; - /* - * A timed receive with a bad time will do a poll regardless. - */ - if ( wait ) { - do_wait = ( the_mq->oflag & O_NONBLOCK ) == 0; - } else { - do_wait = wait; - } - _CORE_message_queue_Acquire_critical( &the_mq->Message_queue, &queue_context @@ -97,13 +89,12 @@ ssize_t _POSIX_Message_queue_Receive_support( * Now perform the actual message receive */ executing = _Thread_Executing; - _Thread_queue_Context_set_relative_timeout( &queue_context, timeout ); status = _CORE_message_queue_Seize( &the_mq->Message_queue, executing, msg_ptr, &length_out, - do_wait, + ( the_mq->oflag & O_NONBLOCK ) == 0, &queue_context ); diff --git a/cpukit/posix/src/mqueuesend.c b/cpukit/posix/src/mqueuesend.c index 6cf67cd3bb..4843ae073d 100644 --- a/cpukit/posix/src/mqueuesend.c +++ b/cpukit/posix/src/mqueuesend.c @@ -61,7 +61,7 @@ int mq_send( msg_ptr, msg_len, msg_prio, - true, - WATCHDOG_NO_TIMEOUT + NULL, + _Thread_queue_Enqueue_do_nothing_extra ); } diff --git a/cpukit/posix/src/mqueuesendsupp.c b/cpukit/posix/src/mqueuesendsupp.c index c975a95505..a238991af5 100644 --- a/cpukit/posix/src/mqueuesendsupp.c +++ b/cpukit/posix/src/mqueuesendsupp.c @@ -35,18 +35,17 @@ #include int _POSIX_Message_queue_Send_support( - mqd_t mqdes, - const char *msg_ptr, - size_t msg_len, - unsigned int msg_prio, - bool wait, - Watchdog_Interval timeout + mqd_t mqdes, + const char *msg_ptr, + size_t msg_len, + unsigned int msg_prio, + const struct timespec *abstime, + Thread_queue_Enqueue_callout enqueue_callout ) { POSIX_Message_queue_Control *the_mq; Thread_queue_Context queue_context; Status_Control status; - bool do_wait; Thread_Control *executing; /* @@ -69,14 +68,8 @@ int _POSIX_Message_queue_Send_support( rtems_set_errno_and_return_minus_one( EBADF ); } - /* - * A timed receive with a bad time will do a poll regardless. - */ - if ( wait ) { - do_wait = ( the_mq->oflag & O_NONBLOCK ) == 0; - } else { - do_wait = wait; - } + _Thread_queue_Context_set_enqueue_callout( &queue_context, enqueue_callout ); + _Thread_queue_Context_set_timeout_argument( &queue_context, abstime ); _CORE_message_queue_Acquire_critical( &the_mq->Message_queue, @@ -92,14 +85,13 @@ int _POSIX_Message_queue_Send_support( * Now perform the actual message receive */ executing = _Thread_Executing; - _Thread_queue_Context_set_relative_timeout( &queue_context, timeout ); status = _CORE_message_queue_Submit( &the_mq->Message_queue, executing, msg_ptr, msg_len, _POSIX_Message_queue_Priority_to_core( msg_prio ), - do_wait, + ( the_mq->oflag & O_NONBLOCK ) == 0, &queue_context ); return _POSIX_Zero_or_minus_one_plus_errno( status ); diff --git a/cpukit/posix/src/mqueuetimedreceive.c b/cpukit/posix/src/mqueuetimedreceive.c index f9b2730baa..fe9fc75053 100644 --- a/cpukit/posix/src/mqueuetimedreceive.c +++ b/cpukit/posix/src/mqueuetimedreceive.c @@ -32,17 +32,6 @@ #include "config.h" #endif -#include - -#include -#include -#include -#include -#include - -#include -#include -#include #include /* @@ -59,33 +48,12 @@ ssize_t mq_timedreceive( const struct timespec *__restrict abstime ) { - Watchdog_Interval ticks; - bool do_wait = true; - TOD_Absolute_timeout_conversion_results status; - - /* - * POSIX requires that blocking calls with timeouts that take - * an absolute timeout must ignore issues with the absolute - * time provided if the operation would otherwise succeed. - * So we check the abstime provided, and hold on to whether it - * is valid or not. If it isn't correct and in the future, - * then we do a polling operation and convert the UNSATISFIED - * status into the appropriate error. - * - * If the status is TOD_ABSOLUTE_TIMEOUT_INVALID, - * TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST, or TOD_ABSOLUTE_TIMEOUT_IS_NOW, - * then we should not wait. - */ - status = _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ); - if ( status != TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE ) - do_wait = false; - return _POSIX_Message_queue_Receive_support( mqdes, msg_ptr, msg_len, msg_prio, - do_wait, - ticks + abstime, + _Thread_queue_Add_timeout_realtime_timespec ); } diff --git a/cpukit/posix/src/mqueuetimedsend.c b/cpukit/posix/src/mqueuetimedsend.c index 3920a3fcc1..5596517c78 100644 --- a/cpukit/posix/src/mqueuetimedsend.c +++ b/cpukit/posix/src/mqueuetimedsend.c @@ -18,17 +18,6 @@ #include "config.h" #endif -#include - -#include -#include -#include -#include -#include - -#include -#include -#include #include int mq_timedsend( @@ -39,33 +28,12 @@ int mq_timedsend( const struct timespec *abstime ) { - Watchdog_Interval ticks; - bool do_wait = true; - TOD_Absolute_timeout_conversion_results status; - - /* - * POSIX requires that blocking calls with timeouts that take - * an absolute timeout must ignore issues with the absolute - * time provided if the operation would otherwise succeed. - * So we check the abstime provided, and hold on to whether it - * is valid or not. If it isn't correct and in the future, - * then we do a polling operation and convert the UNSATISFIED - * status into the appropriate error. - * - * If the status is TOD_ABSOLUTE_TIMEOUT_INVALID, - * TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST, or TOD_ABSOLUTE_TIMEOUT_IS_NOW, - * then we should not wait. - */ - status = _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ); - if ( status != TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE ) - do_wait = false; - return _POSIX_Message_queue_Send_support( mqdes, msg_ptr, msg_len, msg_prio, - do_wait, - ticks + abstime, + _Thread_queue_Add_timeout_realtime_timespec ); } diff --git a/cpukit/posix/src/mutexlock.c b/cpukit/posix/src/mutexlock.c index d4cf4b74bd..35722fe96f 100644 --- a/cpukit/posix/src/mutexlock.c +++ b/cpukit/posix/src/mutexlock.c @@ -18,14 +18,7 @@ #include "config.h" #endif -#include -#include - -#include -#include -#include #include -#include /* * 11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93 @@ -37,5 +30,9 @@ int pthread_mutex_lock( pthread_mutex_t *mutex ) { - return _POSIX_Mutex_Lock_support( mutex, true, WATCHDOG_NO_TIMEOUT ); + return _POSIX_Mutex_Lock_support( + mutex, + NULL, + _Thread_queue_Enqueue_do_nothing_extra + ); } diff --git a/cpukit/posix/src/mutexlocksupp.c b/cpukit/posix/src/mutexlocksupp.c index 4b0f366629..4530a6bea2 100644 --- a/cpukit/posix/src/mutexlocksupp.c +++ b/cpukit/posix/src/mutexlocksupp.c @@ -25,16 +25,15 @@ Status_Control _POSIX_Mutex_Seize_slow( POSIX_Mutex_Control *the_mutex, const Thread_queue_Operations *operations, Thread_Control *executing, - bool wait, + const struct timespec *abstime, Thread_queue_Context *queue_context ) { - if ( wait ) { + if ( (uintptr_t) abstime != POSIX_MUTEX_ABSTIME_TRY_LOCK ) { _Thread_queue_Context_set_thread_state( queue_context, STATES_WAITING_FOR_MUTEX ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( queue_context ); _Thread_queue_Context_set_deadlock_callout( queue_context, _Thread_queue_Deadlock_status @@ -53,9 +52,9 @@ Status_Control _POSIX_Mutex_Seize_slow( } int _POSIX_Mutex_Lock_support( - pthread_mutex_t *mutex, - bool wait, - Watchdog_Interval timeout + pthread_mutex_t *mutex, + const struct timespec *abstime, + Thread_queue_Enqueue_callout enqueue_callout ) { POSIX_Mutex_Control *the_mutex; @@ -68,7 +67,8 @@ int _POSIX_Mutex_Lock_support( POSIX_MUTEX_VALIDATE_OBJECT( the_mutex, flags ); executing = _POSIX_Mutex_Acquire( the_mutex, &queue_context ); - _Thread_queue_Context_set_relative_timeout( &queue_context, timeout ); + _Thread_queue_Context_set_enqueue_callout( &queue_context, enqueue_callout); + _Thread_queue_Context_set_timeout_argument( &queue_context, abstime ); switch ( _POSIX_Mutex_Get_protocol( flags ) ) { case POSIX_MUTEX_PRIORITY_CEILING: @@ -76,7 +76,7 @@ int _POSIX_Mutex_Lock_support( the_mutex, flags, executing, - wait, + abstime, &queue_context ); break; @@ -86,7 +86,7 @@ int _POSIX_Mutex_Lock_support( flags, POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS, executing, - wait, + abstime, &queue_context ); break; @@ -99,7 +99,7 @@ int _POSIX_Mutex_Lock_support( flags, POSIX_MUTEX_PRIORITY_INHERIT_TQ_OPERATIONS, executing, - wait, + abstime, &queue_context ); break; diff --git a/cpukit/posix/src/mutextimedlock.c b/cpukit/posix/src/mutextimedlock.c index cfc1827ae8..075417a3dd 100644 --- a/cpukit/posix/src/mutextimedlock.c +++ b/cpukit/posix/src/mutextimedlock.c @@ -18,14 +18,7 @@ #include "config.h" #endif -#include -#include - -#include -#include -#include #include -#include /** * 11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93 @@ -37,42 +30,9 @@ int pthread_mutex_timedlock( const struct timespec *abstime ) { - Watchdog_Interval ticks; - bool do_wait = true; - TOD_Absolute_timeout_conversion_results status; - int lock_status; - - /* - * POSIX requires that blocking calls with timeouts that take - * an absolute timeout must ignore issues with the absolute - * time provided if the operation would otherwise succeed. - * So we check the abstime provided, and hold on to whether it - * is valid or not. If it isn't correct and in the future, - * then we do a polling operation and convert the UNSATISFIED - * status into the appropriate error. - * - * If the status is TOD_ABSOLUTE_TIMEOUT_INVALID, - * TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST, or TOD_ABSOLUTE_TIMEOUT_IS_NOW, - * then we should not wait. - */ - status = _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ); - if ( status != TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE ) - do_wait = false; - - lock_status = _POSIX_Mutex_Lock_support( mutex, do_wait, ticks ); - /* - * This service only gives us the option to block. We used a polling - * attempt to lock if the abstime was not in the future. If we did - * not obtain the mutex, then not look at the status immediately, - * make sure the right reason is returned. - */ - if ( !do_wait && (lock_status == EBUSY) ) { - if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID ) - return EINVAL; - if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST || - status == TOD_ABSOLUTE_TIMEOUT_IS_NOW ) - return ETIMEDOUT; - } - - return lock_status; + return _POSIX_Mutex_Lock_support( + mutex, + abstime, + _Thread_queue_Add_timeout_realtime_timespec + ); } diff --git a/cpukit/posix/src/mutextrylock.c b/cpukit/posix/src/mutextrylock.c index d029ae5de6..895f38fa44 100644 --- a/cpukit/posix/src/mutextrylock.c +++ b/cpukit/posix/src/mutextrylock.c @@ -18,14 +18,7 @@ #include "config.h" #endif -#include -#include - -#include -#include -#include #include -#include /** * 11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93 @@ -36,8 +29,17 @@ int pthread_mutex_trylock( pthread_mutex_t *mutex ) { - int r = _POSIX_Mutex_Lock_support( mutex, false, WATCHDOG_NO_TIMEOUT ); - if ( r == EDEADLK ) - r = EBUSY; - return r; + int eno; + + eno = _POSIX_Mutex_Lock_support( + mutex, + (const struct timespec *) POSIX_MUTEX_ABSTIME_TRY_LOCK, + NULL + ); + + if ( eno == EDEADLK ) { + eno = EBUSY; + } + + return eno; } diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c index e8a7fe14c1..f65c91bc17 100644 --- a/cpukit/posix/src/nanosleep.c +++ b/cpukit/posix/src/nanosleep.c @@ -21,100 +21,18 @@ #endif #include -#include -#include #include #include #include +#include #include +#include +#include static Thread_queue_Control _Nanosleep_Pseudo_queue = THREAD_QUEUE_INITIALIZER( "Nanosleep" ); -static inline int nanosleep_helper( - clockid_t clock_id, - uint64_t ticks, - struct timespec *timeout, - struct timespec *rmtp, - Watchdog_Discipline discipline -) -{ - Thread_queue_Context queue_context; - struct timespec stop; - int err; - - err = 0; - - _Thread_queue_Context_initialize( &queue_context ); - _Thread_queue_Context_set_thread_state( - &queue_context, - STATES_WAITING_FOR_TIME | STATES_INTERRUPTIBLE_BY_SIGNAL - ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); - - if ( discipline == WATCHDOG_ABSOLUTE ) { - _Thread_queue_Context_set_absolute_timeout( &queue_context, ticks ); - } else { - _Thread_queue_Context_set_relative_timeout( &queue_context, ticks ); - } - - /* - * Block for the desired amount of time - */ - _Thread_queue_Acquire( &_Nanosleep_Pseudo_queue, &queue_context ); - _Thread_queue_Enqueue( - &_Nanosleep_Pseudo_queue.Queue, - &_Thread_queue_Operations_FIFO, - _Thread_Executing, - &queue_context - ); - - clock_gettime( clock_id, &stop ); - /* - * If the user wants the time remaining, do the conversion. - */ - if ( _Timespec_Less_than( &stop, timeout ) ) { - /* - * If there is time remaining, then we were interrupted by a signal. - */ - err = EINTR; - if ( rmtp != NULL ) { - _Timespec_Subtract( &stop, timeout, rmtp ); - } - } else if ( rmtp != NULL ) { - /* no time remaining */ - _Timespec_Set_to_zero( rmtp ); - } - - return err; -} - -/* - * A nanosleep for zero time is implemented as a yield. - * This behavior is also beyond the POSIX specification but is - * consistent with the RTEMS API and yields desirable behavior. - */ -static inline int nanosleep_yield( struct timespec *rmtp ) -{ - /* - * It is critical to obtain the executing thread after thread dispatching is - * disabled on SMP configurations. - */ - Thread_Control *executing; - Per_CPU_Control *cpu_self; - - executing = _Thread_Get_executing(); - cpu_self = _Thread_Dispatch_disable(); - _Thread_Yield( executing ); - _Thread_Dispatch_direct( cpu_self ); - if ( rmtp ) { - rmtp->tv_sec = 0; - rmtp->tv_nsec = 0; - } - return 0; -} - /* * 14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269 */ @@ -123,43 +41,15 @@ int nanosleep( struct timespec *rmtp ) { - int err; - struct timespec now; - uint64_t ticks; - Watchdog_Interval relative_interval; - - /* - * Return EINVAL if the delay interval is negative. - * - * NOTE: This behavior is beyond the POSIX specification. - * FSU and GNU/Linux pthreads shares this behavior. - */ - if ( !_Timespec_Is_valid( rqtp ) ) { - rtems_set_errno_and_return_minus_one( EINVAL ); - } + int eno; - relative_interval = _Timespec_To_ticks( rqtp ); - if ( relative_interval == 0 ) - return nanosleep_yield( rmtp ); - - /* CLOCK_REALTIME can be adjusted during the timeout, - * so convert to an absolute timeout value and put the - * thread on the WATCHDOG_ABSOLUTE threadq. */ - err = clock_gettime( CLOCK_REALTIME, &now ); - if ( err != 0 ) - return -1; - _Timespec_Add_to( &now, rqtp ); - ticks = _Watchdog_Realtime_from_timespec( &now ); - err = nanosleep_helper( CLOCK_REALTIME, - ticks, - &now, - rmtp, - WATCHDOG_ABSOLUTE - ); - if ( err != 0 ) { - rtems_set_errno_and_return_minus_one( err ); + eno = clock_nanosleep( CLOCK_REALTIME, 0, rqtp, rmtp ); + + if ( eno != 0 ) { + rtems_set_errno_and_return_minus_one( eno ); } - return 0; + + return eno; } /* @@ -172,59 +62,82 @@ int clock_nanosleep( struct timespec *rmtp ) { - int err = 0; - struct timespec timeout; - uint64_t ticks; - Watchdog_Interval relative_interval; - TOD_Absolute_timeout_conversion_results status; - - if ( !_Timespec_Is_valid( rqtp ) ) - return EINVAL; - - /* get relative ticks of the requested timeout */ - if ( flags & TIMER_ABSTIME ) { - /* See if absolute time already passed */ - status = _TOD_Absolute_timeout_to_ticks(rqtp, clock_id, &relative_interval); - if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID ) - return EINVAL; - if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST ) - return 0; - if ( status == TOD_ABSOLUTE_TIMEOUT_IS_NOW ) - return nanosleep_yield( NULL ); - rmtp = NULL; /* Do not touch rmtp when using absolute time */ - timeout.tv_sec = 0; - timeout.tv_nsec = 0; + Thread_queue_Context queue_context; + struct timespec spare_end; + const struct timespec *end; + Thread_Control *executing; + int eno; + + if ( clock_id != CLOCK_REALTIME && clock_id != CLOCK_MONOTONIC ) { + return ENOTSUP; + } + + _Thread_queue_Context_initialize( &queue_context ); + _Thread_queue_Context_set_thread_state( + &queue_context, + STATES_WAITING_FOR_TIME | STATES_INTERRUPTIBLE_BY_SIGNAL + ); + + if ( ( flags & TIMER_ABSTIME ) != 0 ) { + end = rqtp; + + if ( clock_id == CLOCK_REALTIME ) { + _Thread_queue_Context_set_enqueue_timeout_realtime_timespec( + &queue_context, + end + ); + } else { + _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec( + &queue_context, + end + ); + } } else { - /* prepare to convert relative ticks to absolute timeout */ - err = clock_gettime( clock_id, &timeout ); - if ( err != 0 ) + if ( !_Watchdog_Is_valid_interval_timespec( rqtp ) ) { return EINVAL; - relative_interval = _Timespec_To_ticks( rqtp ); - } - if ( relative_interval == 0 ) - return nanosleep_yield( rmtp ); - - _Timespec_Add_to( &timeout, rqtp ); - if ( clock_id == CLOCK_REALTIME ) { - ticks = _Watchdog_Realtime_from_timespec( &timeout ); - err = nanosleep_helper( - clock_id, - ticks, - &timeout, - rmtp, - WATCHDOG_ABSOLUTE - ); - } else if ( clock_id == CLOCK_MONOTONIC ) { - /* use the WATCHDOG_RELATIVE to ignore changes in wall time */ - err = nanosleep_helper( - clock_id, - relative_interval, - &timeout, - rmtp, - WATCHDOG_RELATIVE + } + + _TOD_Get_zero_based_uptime_as_timespec( &spare_end ); + + /* In case this overflows, then the enqueue callout will reject it */ + _Timespec_Add_to( &spare_end, rqtp ); + + end = &spare_end; + _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec( + &queue_context, + end ); - } else { - err = ENOTSUP; } - return err; + + _Thread_queue_Acquire( &_Nanosleep_Pseudo_queue, &queue_context ); + executing = _Thread_Executing; + _Thread_queue_Enqueue( + &_Nanosleep_Pseudo_queue.Queue, + &_Thread_queue_Operations_FIFO, + executing, + &queue_context + ); + eno = _POSIX_Get_error_after_wait( executing ); + + if ( eno == ETIMEDOUT ) { + eno = 0; + } + + if ( rmtp != NULL && ( flags & TIMER_ABSTIME ) == 0 ) { + if ( eno == EINTR ) { + struct timespec actual_end; + + _TOD_Get_zero_based_uptime_as_timespec( &actual_end ); + + if ( _Timespec_Less_than( &actual_end, end ) ) { + _Timespec_Subtract( &actual_end, end, rmtp ); + } else { + _Timespec_Set_to_zero( rmtp ); + } + } else { + _Timespec_Set_to_zero( rmtp ); + } + } + + return eno; } diff --git a/cpukit/posix/src/pbarrierwait.c b/cpukit/posix/src/pbarrierwait.c index b9785216b4..75d9437774 100644 --- a/cpukit/posix/src/pbarrierwait.c +++ b/cpukit/posix/src/pbarrierwait.c @@ -54,7 +54,6 @@ int pthread_barrier_wait( pthread_barrier_t *_barrier ) STATES_WAITING_FOR_BARRIER ); _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); - _Thread_queue_Context_set_no_timeout( &queue_context ); _Thread_queue_Enqueue( &barrier->Queue.Queue, POSIX_BARRIER_TQ_OPERATIONS, diff --git a/cpukit/posix/src/prwlockrdlock.c b/cpukit/posix/src/prwlockrdlock.c index 4019c1fcb2..38c2981076 100644 --- a/cpukit/posix/src/prwlockrdlock.c +++ b/cpukit/posix/src/prwlockrdlock.c @@ -33,7 +33,7 @@ int pthread_rwlock_rdlock( POSIX_RWLOCK_VALIDATE_OBJECT( the_rwlock ); _Thread_queue_Context_initialize( &queue_context ); - _Thread_queue_Context_set_no_timeout( &queue_context ); + _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); status = _CORE_RWLock_Seize_for_reading( &the_rwlock->RWLock, true, /* we are willing to wait forever */ diff --git a/cpukit/posix/src/prwlocktimedrdlock.c b/cpukit/posix/src/prwlocktimedrdlock.c index a9ac13348d..47c76d9136 100644 --- a/cpukit/posix/src/prwlocktimedrdlock.c +++ b/cpukit/posix/src/prwlocktimedrdlock.c @@ -20,59 +20,28 @@ #include #include -#include int pthread_rwlock_timedrdlock( pthread_rwlock_t *rwlock, const struct timespec *abstime ) { - POSIX_RWLock_Control *the_rwlock; - Thread_queue_Context queue_context; - Watchdog_Interval ticks; - bool do_wait; - TOD_Absolute_timeout_conversion_results timeout_status; - Status_Control status; - - /* - * POSIX requires that blocking calls with timeouts that take - * an absolute timeout must ignore issues with the absolute - * time provided if the operation would otherwise succeed. - * So we check the abstime provided, and hold on to whether it - * is valid or not. If it isn't correct and in the future, - * then we do a polling operation and convert the STATUS_UNAVAILABLE - * status into the appropriate error. - * - * If the timeout status is TOD_ABSOLUTE_TIMEOUT_INVALID, - * TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST, or TOD_ABSOLUTE_TIMEOUT_IS_NOW, - * then we should not wait. - */ - timeout_status = _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ); - do_wait = ( timeout_status == TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE ); + POSIX_RWLock_Control *the_rwlock; + Thread_queue_Context queue_context; + Status_Control status; the_rwlock = _POSIX_RWLock_Get( rwlock ); POSIX_RWLOCK_VALIDATE_OBJECT( the_rwlock ); _Thread_queue_Context_initialize( &queue_context ); - _Thread_queue_Context_set_relative_timeout( &queue_context, ticks ); + _Thread_queue_Context_set_enqueue_timeout_realtime_timespec( + &queue_context, + abstime + ); status = _CORE_RWLock_Seize_for_reading( &the_rwlock->RWLock, - do_wait, + true, &queue_context ); - - if ( !do_wait && status == STATUS_UNAVAILABLE ) { - if ( timeout_status == TOD_ABSOLUTE_TIMEOUT_INVALID ) { - return EINVAL; - } - - if ( - timeout_status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST - || timeout_status == TOD_ABSOLUTE_TIMEOUT_IS_NOW - ) { - return ETIMEDOUT; - } - } - return _POSIX_Get_error( status ); } diff --git a/cpukit/posix/src/prwlocktimedwrlock.c b/cpukit/posix/src/prwlocktimedwrlock.c index 1f1e654d53..a48f0e665c 100644 --- a/cpukit/posix/src/prwlocktimedwrlock.c +++ b/cpukit/posix/src/prwlocktimedwrlock.c @@ -22,59 +22,28 @@ #include #include -#include int pthread_rwlock_timedwrlock( pthread_rwlock_t *rwlock, const struct timespec *abstime ) { - POSIX_RWLock_Control *the_rwlock; - Thread_queue_Context queue_context; - Watchdog_Interval ticks; - bool do_wait; - TOD_Absolute_timeout_conversion_results timeout_status; - Status_Control status; - - /* - * POSIX requires that blocking calls with timeouts that take - * an absolute timeout must ignore issues with the absolute - * time provided if the operation would otherwise succeed. - * So we check the abstime provided, and hold on to whether it - * is valid or not. If it isn't correct and in the future, - * then we do a polling operation and convert the STATUS_UNAVAILABLE - * status into the appropriate error. - * - * If the timeout status is TOD_ABSOLUTE_TIMEOUT_INVALID, - * TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST, or TOD_ABSOLUTE_TIMEOUT_IS_NOW, - * then we should not wait. - */ - timeout_status = _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ); - do_wait = ( timeout_status == TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE ); + POSIX_RWLock_Control *the_rwlock; + Thread_queue_Context queue_context; + Status_Control status; the_rwlock = _POSIX_RWLock_Get( rwlock ); POSIX_RWLOCK_VALIDATE_OBJECT( the_rwlock ); _Thread_queue_Context_initialize( &queue_context ); - _Thread_queue_Context_set_relative_timeout( &queue_context, ticks ); + _Thread_queue_Context_set_enqueue_timeout_realtime_timespec( + &queue_context, + abstime + ); status = _CORE_RWLock_Seize_for_writing( &the_rwlock->RWLock, - do_wait, + true, &queue_context ); - - if ( !do_wait && status == STATUS_UNAVAILABLE ) { - if ( timeout_status == TOD_ABSOLUTE_TIMEOUT_INVALID ) { - return EINVAL; - } - - if ( - timeout_status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST - || timeout_status == TOD_ABSOLUTE_TIMEOUT_IS_NOW - ) { - return ETIMEDOUT; - } - } - return _POSIX_Get_error( status ); } diff --git a/cpukit/posix/src/prwlockwrlock.c b/cpukit/posix/src/prwlockwrlock.c index df4d2685aa..eae10ba375 100644 --- a/cpukit/posix/src/prwlockwrlock.c +++ b/cpukit/posix/src/prwlockwrlock.c @@ -35,7 +35,7 @@ int pthread_rwlock_wrlock( POSIX_RWLOCK_VALIDATE_OBJECT( the_rwlock ); _Thread_queue_Context_initialize( &queue_context ); - _Thread_queue_Context_set_no_timeout( &queue_context ); + _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); status = _CORE_RWLock_Seize_for_writing( &the_rwlock->RWLock, true, /* do not timeout -- wait forever */ diff --git a/cpukit/posix/src/pthreadjoin.c b/cpukit/posix/src/pthreadjoin.c index b6981fd9b3..ce4bf0d049 100644 --- a/cpukit/posix/src/pthreadjoin.c +++ b/cpukit/posix/src/pthreadjoin.c @@ -40,7 +40,6 @@ static int _POSIX_Threads_Join( pthread_t thread, void **value_ptr ) _Thread_queue_Context_initialize( &queue_context ); _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); - _Thread_queue_Context_set_no_timeout( &queue_context ); the_thread = _Thread_Get( thread, &queue_context.Lock_context.Lock_context ); if ( the_thread == NULL ) { diff --git a/cpukit/posix/src/semtimedwait.c b/cpukit/posix/src/semtimedwait.c index 90e6866341..9e7bb466dd 100644 --- a/cpukit/posix/src/semtimedwait.c +++ b/cpukit/posix/src/semtimedwait.c @@ -51,29 +51,16 @@ int sem_timedwait( _Sem_Queue_release( sem, level, &queue_context ); return 0; } else { - Watchdog_Interval ticks; - Status_Control status; - - switch ( _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ) ) { - case TOD_ABSOLUTE_TIMEOUT_INVALID: - _Sem_Queue_release( sem, level, &queue_context ); - rtems_set_errno_and_return_minus_one( EINVAL ); - break; - case TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST: - case TOD_ABSOLUTE_TIMEOUT_IS_NOW: - _Sem_Queue_release( sem, level, &queue_context ); - rtems_set_errno_and_return_minus_one( ETIMEDOUT ); - break; - default: - break; - } + Status_Control status; _Thread_queue_Context_set_thread_state( &queue_context, STATES_WAITING_FOR_SEMAPHORE ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); - _Thread_queue_Context_set_relative_timeout( &queue_context, ticks ); + _Thread_queue_Context_set_enqueue_timeout_realtime_timespec( + &queue_context, + abstime + ); _Thread_queue_Context_set_ISR_level( &queue_context, level ); _Thread_queue_Enqueue( &sem->Queue.Queue, diff --git a/cpukit/posix/src/sigtimedwait.c b/cpukit/posix/src/sigtimedwait.c index 70170bf2f7..a0e18adef0 100644 --- a/cpukit/posix/src/sigtimedwait.c +++ b/cpukit/posix/src/sigtimedwait.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include static int _POSIX_signals_Get_lowest( @@ -89,20 +91,24 @@ int sigtimedwait( * in the Open Group specification. */ - if ( timeout ) { - Watchdog_Interval interval; + if ( timeout != NULL ) { + struct timespec end; - if ( !_Timespec_Is_valid( timeout ) ) - rtems_set_errno_and_return_minus_one( EINVAL ); + if ( !_Watchdog_Is_valid_interval_timespec( timeout ) ) { + return EINVAL; + } - interval = _Timespec_To_ticks( timeout ); + _TOD_Get_zero_based_uptime_as_timespec( &end ); - if ( !interval ) - rtems_set_errno_and_return_minus_one( EINVAL ); + /* In case this overflows, then the enqueue callout will reject it */ + _Timespec_Add_to( &end, timeout ); - _Thread_queue_Context_set_relative_timeout( &queue_context, interval ); + _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec( + &queue_context, + &end + ); } else { - _Thread_queue_Context_set_no_timeout( &queue_context ); + _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); } /* @@ -160,7 +166,6 @@ int sigtimedwait( &queue_context, STATES_WAITING_FOR_SIGNAL | STATES_INTERRUPTIBLE_BY_SIGNAL ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); _Thread_queue_Enqueue( &_POSIX_signals_Wait_queue.Queue, POSIX_SIGNALS_TQ_OPERATIONS, -- cgit v1.2.3