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/libnetworking/rtems/rtems_glue.c | 2 +- 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 ++- cpukit/rtems/src/barrierwait.c | 2 +- cpukit/rtems/src/msgqreceive.c | 2 +- cpukit/rtems/src/regiongetsegment.c | 10 +- cpukit/rtems/src/semobtain.c | 6 +- cpukit/score/Makefile.am | 2 +- cpukit/score/include/rtems/score/coresemimpl.h | 1 - cpukit/score/include/rtems/score/threadq.h | 33 ++- cpukit/score/include/rtems/score/threadqimpl.h | 110 +++++++--- cpukit/score/include/rtems/score/todimpl.h | 40 ---- cpukit/score/include/rtems/score/watchdog.h | 31 +-- cpukit/score/include/rtems/score/watchdogimpl.h | 5 + cpukit/score/src/apimutexlock.c | 2 +- cpukit/score/src/condition.c | 88 ++++---- cpukit/score/src/corebarrierwait.c | 1 - cpukit/score/src/coremsgseize.c | 1 - cpukit/score/src/coremsgsubmit.c | 1 - cpukit/score/src/coremutexseize.c | 1 - cpukit/score/src/corerwlockobtainread.c | 1 - cpukit/score/src/corerwlockobtainwrite.c | 1 - cpukit/score/src/coretodabsolutetimeout.c | 82 -------- cpukit/score/src/futex.c | 1 - cpukit/score/src/mutex.c | 43 +--- cpukit/score/src/semaphore.c | 1 - cpukit/score/src/threadqenqueue.c | 54 ++--- cpukit/score/src/threadqtimeout.c | 154 ++++++++++++++ cpukit/score/src/threadrestart.c | 2 +- 49 files changed, 639 insertions(+), 877 deletions(-) delete mode 100644 cpukit/score/src/coretodabsolutetimeout.c create mode 100644 cpukit/score/src/threadqtimeout.c (limited to 'cpukit') diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c index 939b858dc7..785f841fba 100644 --- a/cpukit/libnetworking/rtems/rtems_glue.c +++ b/cpukit/libnetworking/rtems/rtems_glue.c @@ -376,7 +376,7 @@ rtems_bsdnet_semaphore_obtain (void) rtems_panic ("rtems-net: network sema obtain: network not initialised\n"); _Thread_queue_Context_initialize(&queue_context); _ISR_lock_ISR_disable(&queue_context.Lock_context.Lock_context); - _Thread_queue_Context_set_no_timeout( &queue_context ); + _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); status = _CORE_recursive_mutex_Seize ( &the_networkSemaphore->Core_control.Mutex.Recursive, CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS, 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, diff --git a/cpukit/rtems/src/barrierwait.c b/cpukit/rtems/src/barrierwait.c index c0931689c7..4811c218b8 100644 --- a/cpukit/rtems/src/barrierwait.c +++ b/cpukit/rtems/src/barrierwait.c @@ -38,7 +38,7 @@ rtems_status_code rtems_barrier_wait( return RTEMS_INVALID_ID; } - _Thread_queue_Context_set_relative_timeout( &queue_context, timeout ); + _Thread_queue_Context_set_enqueue_timeout_ticks( &queue_context, timeout ); status = _CORE_barrier_Seize( &the_barrier->Barrier, _Thread_Executing, diff --git a/cpukit/rtems/src/msgqreceive.c b/cpukit/rtems/src/msgqreceive.c index d509faf988..2304be735a 100644 --- a/cpukit/rtems/src/msgqreceive.c +++ b/cpukit/rtems/src/msgqreceive.c @@ -61,7 +61,7 @@ rtems_status_code rtems_message_queue_receive( ); executing = _Thread_Executing; - _Thread_queue_Context_set_relative_timeout( &queue_context, timeout ); + _Thread_queue_Context_set_enqueue_timeout_ticks( &queue_context, timeout ); status = _CORE_message_queue_Seize( &the_message_queue->message_queue, executing, diff --git a/cpukit/rtems/src/regiongetsegment.c b/cpukit/rtems/src/regiongetsegment.c index dfd476ccc0..02acefb004 100644 --- a/cpukit/rtems/src/regiongetsegment.c +++ b/cpukit/rtems/src/regiongetsegment.c @@ -27,11 +27,19 @@ static void _Region_Enqueue_callout( Thread_queue_Queue *queue, Thread_Control *the_thread, + Per_CPU_Control *cpu_self, Thread_queue_Context *queue_context ) { Region_Control *the_region; + _Thread_queue_Add_timeout_ticks( + queue, + the_thread, + cpu_self, + queue_context + ); + the_region = REGION_OF_THREAD_QUEUE_QUEUE( queue ); _Region_Unlock( the_region ); } @@ -91,11 +99,11 @@ rtems_status_code rtems_region_get_segment( &queue_context, STATES_WAITING_FOR_SEGMENT ); + _Thread_queue_Context_set_timeout_ticks( &queue_context, timeout ); _Thread_queue_Context_set_enqueue_callout( &queue_context, _Region_Enqueue_callout ); - _Thread_queue_Context_set_relative_timeout( &queue_context, timeout ); _Thread_queue_Enqueue( &the_region->Wait_queue.Queue, the_region->wait_operations, diff --git a/cpukit/rtems/src/semobtain.c b/cpukit/rtems/src/semobtain.c index b81612eaae..db0c3f2e0c 100644 --- a/cpukit/rtems/src/semobtain.c +++ b/cpukit/rtems/src/semobtain.c @@ -69,7 +69,11 @@ rtems_status_code rtems_semaphore_obtain( executing = _Thread_Executing; wait = !_Options_Is_no_wait( option_set ); - _Thread_queue_Context_set_relative_timeout( &queue_context, timeout ); + if ( wait ) { + _Thread_queue_Context_set_enqueue_timeout_ticks( &queue_context, timeout ); + } else { + _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); + } switch ( the_semaphore->variant ) { case SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY: diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index f0c927b294..7ff1f41684 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -305,6 +305,7 @@ libscore_a_SOURCES += src/threadq.c \ src/threadqextractwithproxy.c src/threadqfirst.c \ src/threadqflush.c libscore_a_SOURCES += src/threadqops.c +libscore_a_SOURCES += src/threadqtimeout.c ## TIMESPEC_C_FILES libscore_a_SOURCES += src/timespecaddto.c src/timespecfromticks.c \ @@ -316,7 +317,6 @@ libscore_a_SOURCES += src/timespecaddto.c src/timespecfromticks.c \ libscore_a_SOURCES += src/coretod.c src/coretodset.c \ src/coretodtickspersec.c \ src/coretodadjust.c -libscore_a_SOURCES += src/coretodabsolutetimeout.c ## WATCHDOG_C_FILES libscore_a_SOURCES += src/watchdoginsert.c diff --git a/cpukit/score/include/rtems/score/coresemimpl.h b/cpukit/score/include/rtems/score/coresemimpl.h index aa053d7acd..00f77e61dd 100644 --- a/cpukit/score/include/rtems/score/coresemimpl.h +++ b/cpukit/score/include/rtems/score/coresemimpl.h @@ -188,7 +188,6 @@ RTEMS_INLINE_ROUTINE Status_Control _CORE_semaphore_Seize( queue_context, STATES_WAITING_FOR_SEMAPHORE ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( queue_context ); _Thread_queue_Enqueue( &the_semaphore->Wait_queue.Queue, operations, diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h index c4742ba05c..3e618bf5af 100644 --- a/cpukit/score/include/rtems/score/threadq.h +++ b/cpukit/score/include/rtems/score/threadq.h @@ -57,14 +57,16 @@ typedef struct Thread_queue_Operations Thread_queue_Operations; * * @param[in] queue The actual thread queue. * @param[in] the_thread The thread to enqueue. + * @param[in] cpu_self The current processor. * @param[in] queue_context The thread queue context of the lock acquire. * * @see _Thread_queue_Context_set_enqueue_callout(). */ typedef void ( *Thread_queue_Enqueue_callout )( - Thread_queue_Queue *queue, - Thread_Control *the_thread, - Thread_queue_Context *queue_context + Thread_queue_Queue *queue, + Thread_Control *the_thread, + struct Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context ); /** @@ -202,22 +204,31 @@ struct Thread_queue_Context { * @brief The enqueue callout for _Thread_queue_Enqueue(). * * The callout is invoked after the release of the thread queue lock with - * thread dispatching disabled. Afterwards the thread is blocked. + * thread dispatching disabled. Afterwards the thread is blocked. This + * callout must be used to install the thread watchdog for timeout handling. * * @see _Thread_queue_Enqueue_do_nothing_extra(). + * _Thread_queue_Add_timeout_ticks(), and + * _Thread_queue_Add_timeout_realtime_timespec(). */ Thread_queue_Enqueue_callout enqueue_callout; - /** - * @brief The clock discipline for the interval timeout. - * Use WATCHDOG_NO_TIMEOUT to block indefinitely. - */ - Watchdog_Discipline timeout_discipline; - /** * @brief Interval to wait. + * + * May be used by the enqueue callout to register a timeout handler. */ - uint64_t timeout; + union { + /** + * @brief The timeout in ticks. + */ + Watchdog_Interval ticks; + + /** + * @brief The timeout argument, e.g. pointer to struct timespec. + */ + const void *arg; + } Timeout; #if defined(RTEMS_SMP) /** diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h index f74db96129..ecbd8fd42f 100644 --- a/cpukit/score/include/rtems/score/threadqimpl.h +++ b/cpukit/score/include/rtems/score/threadqimpl.h @@ -65,6 +65,28 @@ typedef struct { void _Thread_queue_Enqueue_do_nothing_extra( Thread_queue_Queue *queue, Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context +); + +void _Thread_queue_Add_timeout_ticks( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context +); + +void _Thread_queue_Add_timeout_monotonic_timespec( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context +); + +void _Thread_queue_Add_timeout_realtime_timespec( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, Thread_queue_Context *queue_context ); @@ -117,6 +139,40 @@ _Thread_queue_Context_set_thread_state( queue_context->thread_state = thread_state; } +/** + * @brief Sets the timeout ticks in the thread queue context. + * + * @param queue_context The thread queue context. + * @param ticks The timeout in ticks. + * + * @see _Thread_queue_Enqueue(). + */ +RTEMS_INLINE_ROUTINE void +_Thread_queue_Context_set_timeout_ticks( + Thread_queue_Context *queue_context, + Watchdog_Interval ticks +) +{ + queue_context->Timeout.ticks = ticks; +} + +/** + * @brief Sets the timeout argument in the thread queue context. + * + * @param queue_context The thread queue context. + * @param arg The timeout argument. + * + * @see _Thread_queue_Enqueue(). + */ +RTEMS_INLINE_ROUTINE void +_Thread_queue_Context_set_timeout_argument( + Thread_queue_Context *queue_context, + const void *arg +) +{ + queue_context->Timeout.arg = arg; +} + /** * @brief Sets the enqueue callout in the thread queue context. * @@ -150,55 +206,61 @@ _Thread_queue_Context_set_enqueue_do_nothing_extra( } /** - * @brief Sets an indefinite timeout interval in the thread queue context. + * @brief Sets the enqueue callout to add a relative monotonic timeout in + * ticks. * * @param queue_context The thread queue context. - * @param timeout The new timeout. + * @param ticks The timeout in ticks. * * @see _Thread_queue_Enqueue(). */ RTEMS_INLINE_ROUTINE void -_Thread_queue_Context_set_no_timeout( - Thread_queue_Context *queue_context +_Thread_queue_Context_set_enqueue_timeout_ticks( + Thread_queue_Context *queue_context, + Watchdog_Interval ticks ) { - queue_context->timeout_discipline = WATCHDOG_NO_TIMEOUT; + queue_context->Timeout.ticks = ticks; + queue_context->enqueue_callout = _Thread_queue_Add_timeout_ticks; } /** - * @brief Sets a relative timeout in the thread queue context. + * @brief Sets the enqueue callout to add an absolute monotonic timeout in + * timespec format. * * @param queue_context The thread queue context. - * @param discipline The clock discipline to use for the timeout. + * @param abstime The absolute monotonic timeout. * * @see _Thread_queue_Enqueue(). */ RTEMS_INLINE_ROUTINE void -_Thread_queue_Context_set_relative_timeout( - Thread_queue_Context *queue_context, - Watchdog_Interval timeout +_Thread_queue_Context_set_enqueue_timeout_monotonic_timespec( + Thread_queue_Context *queue_context, + const struct timespec *abstime ) { - queue_context->timeout_discipline = WATCHDOG_RELATIVE; - queue_context->timeout = timeout; + queue_context->Timeout.arg = abstime; + queue_context->enqueue_callout = + _Thread_queue_Add_timeout_monotonic_timespec; } /** - * @brief Sets an absolute timeout in the thread queue context. + * @brief Sets the enqueue callout to add an absolute realtime timeout in + * timespec format. * * @param queue_context The thread queue context. - * @param discipline The clock discipline to use for the timeout. + * @param abstime The absolute realtime timeout. * * @see _Thread_queue_Enqueue(). */ RTEMS_INLINE_ROUTINE void -_Thread_queue_Context_set_absolute_timeout( - Thread_queue_Context *queue_context, - uint64_t timeout +_Thread_queue_Context_set_enqueue_timeout_realtime_timespec( + Thread_queue_Context *queue_context, + const struct timespec *abstime ) { - queue_context->timeout_discipline = WATCHDOG_ABSOLUTE; - queue_context->timeout = timeout; + queue_context->Timeout.arg = abstime; + queue_context->enqueue_callout = _Thread_queue_Add_timeout_realtime_timespec; } /** @@ -615,11 +677,10 @@ Thread_Control *_Thread_queue_Do_dequeue( * - _Thread_queue_Context_set_thread_state(), * * - _Thread_queue_Context_set_enqueue_callout() or - * _Thread_queue_Context_set_enqueue_do_nothing_extra(), - * - * - _Thread_queue_Context_set_no_timeout() or - * _Thread_queue_Context_set_relative_timeout() or - * _Thread_queue_Context_set_absolute_timeout(), and + * _Thread_queue_Context_set_enqueue_do_nothing_extra() or + * _Thread_queue_Context_set_enqueue_timeout_ticks() or + * _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec() or + * _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(), * * - _Thread_queue_Context_set_deadlock_callout(). * @@ -652,7 +713,6 @@ Thread_Control *_Thread_queue_Do_dequeue( * STATES_WAITING_FOR_MUTEX * ); * _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); - * _Thread_queue_Context_set_no_timeout( &queue_context ); * _Thread_queue_Context_set_deadlock_callout( * queue_context, * _Thread_queue_Deadlock_fatal diff --git a/cpukit/score/include/rtems/score/todimpl.h b/cpukit/score/include/rtems/score/todimpl.h index de4dc93430..e3a1a8f58c 100644 --- a/cpukit/score/include/rtems/score/todimpl.h +++ b/cpukit/score/include/rtems/score/todimpl.h @@ -298,46 +298,6 @@ RTEMS_INLINE_ROUTINE bool _TOD_Is_set( void ) return _TOD.is_set; } -/** - * @brief Absolute timeout conversion results. - * - * This enumeration defines the possible results of converting - * an absolute time used for timeouts to POSIX blocking calls to - * a number of ticks for example. - */ -typedef enum { - /** The timeout is invalid. */ - TOD_ABSOLUTE_TIMEOUT_INVALID, - /** The timeout represents a time that is in the past. */ - TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST, - /** The timeout represents a time that is equal to the current time. */ - TOD_ABSOLUTE_TIMEOUT_IS_NOW, - /** The timeout represents a time that is in the future. */ - TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE, -} TOD_Absolute_timeout_conversion_results; - -/** - * @brief Convert absolute timeout to ticks. - * - * This method takes an absolute time being used as a timeout - * to a blocking directive, validates it and returns the number - * of corresponding clock ticks for use by the SuperCore. - * - * @param[in] abstime is a pointer to the timeout - * @param[in] clock is the time source to use for the timeout - * @param[out] ticks_out will contain the number of ticks - * - * @return This method returns the number of ticks in @a ticks_out - * and a status value indicating whether the absolute time - * is valid, in the past, equal to the current time or in - * the future as it should be. - */ -TOD_Absolute_timeout_conversion_results _TOD_Absolute_timeout_to_ticks( - const struct timespec *abstime, - clockid_t clock, - Watchdog_Interval *ticks_out -); - /**@}*/ #ifdef __cplusplus diff --git a/cpukit/score/include/rtems/score/watchdog.h b/cpukit/score/include/rtems/score/watchdog.h index a379bf7a23..dbb092bbef 100644 --- a/cpukit/score/include/rtems/score/watchdog.h +++ b/cpukit/score/include/rtems/score/watchdog.h @@ -53,36 +53,9 @@ typedef struct Watchdog_Control Watchdog_Control; typedef uint32_t Watchdog_Interval; /** - * @brief The clock discipline to use for the Watchdog timeout interval. + * @brief Special watchdog ticks value to indicate an infinite wait. */ -typedef enum { - - /** - * @brief Indefinite wait. - * - * This is to indicate there is no timeout and not to use a watchdog. It - * must be equal to 0, which is an illegal relative clock interval, so that - * it may be used as a Watchdog_Interval value with WATCHDOG_RELATIVE to - * express an indefinite wait. - */ - WATCHDOG_NO_TIMEOUT = 0, - - /** - * @brief Relative clock. - * - * The reference time point for the watchdog is current ticks value - * during insert. Time is measured in clock ticks. - */ - WATCHDOG_RELATIVE, - - /** - * @brief Absolute clock. - * - * The reference time point for this header is the POSIX Epoch. Time is - * measured in nanoseconds since POSIX Epoch. - */ - WATCHDOG_ABSOLUTE -} Watchdog_Discipline; +#define WATCHDOG_NO_TIMEOUT 0 /** * @brief Return type from a Watchdog Service Routine. diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h index 1fa67f3961..7866c0ce44 100644 --- a/cpukit/score/include/rtems/score/watchdogimpl.h +++ b/cpukit/score/include/rtems/score/watchdogimpl.h @@ -284,6 +284,11 @@ RTEMS_INLINE_ROUTINE void _Watchdog_Next_first( } } +/** + * @brief The maximum watchdog ticks value for the far future. + */ +#define WATCHDOG_MAXIMUM_TICKS UINT64_MAX + #define WATCHDOG_NANOSECONDS_PER_SECOND 1000000000 /** diff --git a/cpukit/score/src/apimutexlock.c b/cpukit/score/src/apimutexlock.c index 879562d9f0..312dcc2993 100644 --- a/cpukit/score/src/apimutexlock.c +++ b/cpukit/score/src/apimutexlock.c @@ -33,7 +33,7 @@ void _API_Mutex_Lock( API_Mutex_Control *the_mutex ) _Thread_queue_Context_initialize( &queue_context ); _ISR_lock_ISR_disable( &queue_context.Lock_context.Lock_context ); - _Thread_queue_Context_set_no_timeout( &queue_context ); + _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); _CORE_recursive_mutex_Seize( &the_mutex->Mutex, CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS, diff --git a/cpukit/score/src/condition.c b/cpukit/score/src/condition.c index bbbeb901db..9913d86d34 100644 --- a/cpukit/score/src/condition.c +++ b/cpukit/score/src/condition.c @@ -84,16 +84,38 @@ typedef struct { struct _Mutex_Control *mutex; } Condition_Enqueue_context; -static void _Condition_Enqueue_callout( +static void _Condition_Mutex_release( Thread_queue_Context *queue_context ) +{ + Condition_Enqueue_context *context; + + context = (Condition_Enqueue_context *) queue_context; + _Mutex_Release( context->mutex ); +} + +static void _Condition_Enqueue_no_timeout( Thread_queue_Queue *queue, Thread_Control *the_thread, + Per_CPU_Control *cpu_self, Thread_queue_Context *queue_context ) { - Condition_Enqueue_context *context; + _Condition_Mutex_release( queue_context ); +} - context = (Condition_Enqueue_context *) queue_context; - _Mutex_Release( context->mutex ); +static void _Condition_Enqueue_with_timeout( + 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 + ); + _Condition_Mutex_release( queue_context ); } static Thread_Control *_Condition_Do_wait( @@ -107,15 +129,12 @@ static Thread_Control *_Condition_Do_wait( context->mutex = _mutex; condition = _Condition_Get( _condition ); + _ISR_lock_ISR_disable( &context->Base.Lock_context.Lock_context ); executing = _Condition_Queue_acquire_critical( condition, &context->Base ); _Thread_queue_Context_set_thread_state( &context->Base, STATES_WAITING_FOR_CONDITION_VARIABLE ); - _Thread_queue_Context_set_enqueue_callout( - &context->Base, - _Condition_Enqueue_callout - ); _Thread_queue_Enqueue( &condition->Queue.Queue, CONDITION_TQ_OPERATIONS, @@ -134,8 +153,10 @@ void _Condition_Wait( Condition_Enqueue_context context; _Thread_queue_Context_initialize( &context.Base ); - _ISR_lock_ISR_disable( &context.Base.Lock_context.Lock_context ); - _Thread_queue_Context_set_no_timeout( &context.Base ); + _Thread_queue_Context_set_enqueue_callout( + &context.Base, + _Condition_Enqueue_no_timeout + ); _Condition_Do_wait( _condition, _mutex, &context ); _Mutex_Acquire( _mutex ); } @@ -149,24 +170,13 @@ int _Condition_Wait_timed( Condition_Enqueue_context context; Thread_Control *executing; int eno; - Watchdog_Interval ticks; _Thread_queue_Context_initialize( &context.Base ); - _ISR_lock_ISR_disable( &context.Base.Lock_context.Lock_context ); - - switch ( _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ) ) { - case TOD_ABSOLUTE_TIMEOUT_INVALID: - _ISR_lock_ISR_enable( &context.Base.Lock_context.Lock_context ); - return EINVAL; - case TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST: - case TOD_ABSOLUTE_TIMEOUT_IS_NOW: - _ISR_lock_ISR_enable( &context.Base.Lock_context.Lock_context ); - return ETIMEDOUT; - default: - break; - } - - _Thread_queue_Context_set_relative_timeout( &context.Base, ticks ); + _Thread_queue_Context_set_enqueue_callout( + &context.Base, + _Condition_Enqueue_with_timeout + ); + _Thread_queue_Context_set_timeout_argument( &context.Base, abstime ); executing = _Condition_Do_wait( _condition, _mutex, &context ); eno = STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) ); _Mutex_Acquire( _mutex ); @@ -195,8 +205,10 @@ void _Condition_Wait_recursive( unsigned int nest_level; _Thread_queue_Context_initialize( &context.Base ); - _ISR_lock_ISR_disable( &context.Base.Lock_context.Lock_context ); - _Thread_queue_Context_set_no_timeout( &context.Base ); + _Thread_queue_Context_set_enqueue_callout( + &context.Base, + _Condition_Enqueue_no_timeout + ); nest_level = _Condition_Unnest_mutex( _mutex ); _Condition_Do_wait( _condition, &_mutex->_Mutex, &context ); _Mutex_recursive_Acquire( _mutex ); @@ -213,23 +225,13 @@ int _Condition_Wait_recursive_timed( Thread_Control *executing; int eno; unsigned int nest_level; - Watchdog_Interval ticks; _Thread_queue_Context_initialize( &context.Base ); - _ISR_lock_ISR_disable( &context.Base.Lock_context.Lock_context ); - - switch ( _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ) ) { - case TOD_ABSOLUTE_TIMEOUT_INVALID: - _ISR_lock_ISR_enable( &context.Base.Lock_context.Lock_context ); - return EINVAL; - case TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST: - case TOD_ABSOLUTE_TIMEOUT_IS_NOW: - _ISR_lock_ISR_enable( &context.Base.Lock_context.Lock_context ); - return ETIMEDOUT; - default: - break; - } - _Thread_queue_Context_set_relative_timeout( &context.Base, ticks ); + _Thread_queue_Context_set_enqueue_callout( + &context.Base, + _Condition_Enqueue_with_timeout + ); + _Thread_queue_Context_set_timeout_argument( &context.Base, abstime ); nest_level = _Condition_Unnest_mutex( _mutex ); executing = _Condition_Do_wait( _condition, &_mutex->_Mutex, &context ); eno = STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) ); diff --git a/cpukit/score/src/corebarrierwait.c b/cpukit/score/src/corebarrierwait.c index 5093e02bc0..08acce9d86 100644 --- a/cpukit/score/src/corebarrierwait.c +++ b/cpukit/score/src/corebarrierwait.c @@ -48,7 +48,6 @@ Status_Control _CORE_barrier_Seize( queue_context, STATES_WAITING_FOR_BARRIER ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( queue_context ); _Thread_queue_Enqueue( &the_barrier->Wait_queue.Queue, CORE_BARRIER_TQ_OPERATIONS, diff --git a/cpukit/score/src/coremsgseize.c b/cpukit/score/src/coremsgseize.c index 5d0b95b9e5..e3d8842831 100644 --- a/cpukit/score/src/coremsgseize.c +++ b/cpukit/score/src/coremsgseize.c @@ -117,7 +117,6 @@ Status_Control _CORE_message_queue_Seize( queue_context, STATES_WAITING_FOR_MESSAGE ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( queue_context ); _Thread_queue_Enqueue( &the_message_queue->Wait_queue.Queue, the_message_queue->operations, diff --git a/cpukit/score/src/coremsgsubmit.c b/cpukit/score/src/coremsgsubmit.c index 6040f76eb3..49c90256cd 100644 --- a/cpukit/score/src/coremsgsubmit.c +++ b/cpukit/score/src/coremsgsubmit.c @@ -135,7 +135,6 @@ Status_Control _CORE_message_queue_Submit( queue_context, STATES_WAITING_FOR_MESSAGE ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( queue_context ); _Thread_queue_Enqueue( &the_message_queue->Wait_queue.Queue, the_message_queue->operations, diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c index 173c495d3c..e07458573d 100644 --- a/cpukit/score/src/coremutexseize.c +++ b/cpukit/score/src/coremutexseize.c @@ -36,7 +36,6 @@ Status_Control _CORE_mutex_Seize_slow( 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 diff --git a/cpukit/score/src/corerwlockobtainread.c b/cpukit/score/src/corerwlockobtainread.c index 88853ebfb3..6969486f28 100644 --- a/cpukit/score/src/corerwlockobtainread.c +++ b/cpukit/score/src/corerwlockobtainread.c @@ -77,7 +77,6 @@ Status_Control _CORE_RWLock_Seize_for_reading( queue_context, STATES_WAITING_FOR_RWLOCK ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( queue_context ); _Thread_queue_Enqueue( &the_rwlock->Queue.Queue, CORE_RWLOCK_TQ_OPERATIONS, diff --git a/cpukit/score/src/corerwlockobtainwrite.c b/cpukit/score/src/corerwlockobtainwrite.c index 6145fc3c4c..7b296169d9 100644 --- a/cpukit/score/src/corerwlockobtainwrite.c +++ b/cpukit/score/src/corerwlockobtainwrite.c @@ -71,7 +71,6 @@ Status_Control _CORE_RWLock_Seize_for_writing( queue_context, STATES_WAITING_FOR_RWLOCK ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( queue_context ); _Thread_queue_Enqueue( &the_rwlock->Queue.Queue, CORE_RWLOCK_TQ_OPERATIONS, diff --git a/cpukit/score/src/coretodabsolutetimeout.c b/cpukit/score/src/coretodabsolutetimeout.c deleted file mode 100644 index d67b7c33c7..0000000000 --- a/cpukit/score/src/coretodabsolutetimeout.c +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file - * - * @brief Convert Absolute Timeout to Ticks - * @ingroup ScoreTOD - */ - -/* - * COPYRIGHT (c) 1989-2008. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -/* - * The abstime is a walltime. We turn it into an interval. - */ -TOD_Absolute_timeout_conversion_results _TOD_Absolute_timeout_to_ticks( - const struct timespec *abstime, - clockid_t clock, - Watchdog_Interval *ticks_out -) -{ - struct timespec current_time; - struct timespec difference; - - /* - * Make sure there is always a value returned. - */ - *ticks_out = 0; - - /* - * Is the absolute time even valid? - */ - if ( !_Timespec_Is_valid(abstime) ) - return TOD_ABSOLUTE_TIMEOUT_INVALID; - - /* - * Is the absolute time in the past? - */ - if ( clock == CLOCK_REALTIME ) { - _TOD_Get( ¤t_time ); - } else { - _Assert( clock == CLOCK_MONOTONIC ); - _TOD_Get_zero_based_uptime_as_timespec( ¤t_time ); - } - - if ( _Timespec_Less_than( abstime, ¤t_time ) ) - return TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST; - - /* - * How long until the requested absolute time? - */ - _Timespec_Subtract( ¤t_time, abstime, &difference ); - - /* - * Internally the SuperCore uses ticks, so convert to them. - */ - *ticks_out = _Timespec_To_ticks( &difference ); - - /* - * If the difference was 0, then the future is now. It is so bright - * we better wear shades. - */ - if ( !*ticks_out ) - return TOD_ABSOLUTE_TIMEOUT_IS_NOW; - - /* - * This is the case we were expecting and it took this long to - * get here. - */ - return TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE; -} - diff --git a/cpukit/score/src/futex.c b/cpukit/score/src/futex.c index c5b4f197c3..6487882819 100644 --- a/cpukit/score/src/futex.c +++ b/cpukit/score/src/futex.c @@ -95,7 +95,6 @@ int _Futex_Wait( struct _Futex_Control *_futex, int *uaddr, int val ) STATES_WAITING_FOR_FUTEX ); _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); - _Thread_queue_Context_set_no_timeout( &queue_context ); _Thread_queue_Context_set_ISR_level( &queue_context, level ); _Thread_queue_Enqueue( &futex->Queue.Queue, diff --git a/cpukit/score/src/mutex.c b/cpukit/score/src/mutex.c index 1c793ad633..e2f5bb52fc 100644 --- a/cpukit/score/src/mutex.c +++ b/cpukit/score/src/mutex.c @@ -102,7 +102,6 @@ static void _Mutex_Acquire_slow( 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_fatal @@ -163,7 +162,7 @@ void _Mutex_Acquire( struct _Mutex_Control *_mutex ) _Thread_Resource_count_increment( executing ); _Mutex_Queue_release( mutex, level, &queue_context ); } else { - _Thread_queue_Context_set_no_timeout( &queue_context ); + _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); _Mutex_Acquire_slow( mutex, owner, executing, level, &queue_context ); } } @@ -193,21 +192,10 @@ int _Mutex_Acquire_timed( return 0; } else { - Watchdog_Interval ticks; - - switch ( _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ) ) { - case TOD_ABSOLUTE_TIMEOUT_INVALID: - _Mutex_Queue_release( mutex, level, &queue_context ); - return EINVAL; - case TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST: - case TOD_ABSOLUTE_TIMEOUT_IS_NOW: - _Mutex_Queue_release( mutex, level, &queue_context ); - return ETIMEDOUT; - default: - break; - } - - _Thread_queue_Context_set_relative_timeout( &queue_context, ticks ); + _Thread_queue_Context_set_enqueue_timeout_realtime_timespec( + &queue_context, + abstime + ); _Mutex_Acquire_slow( mutex, owner, executing, level, &queue_context ); return STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) ); @@ -290,7 +278,7 @@ void _Mutex_recursive_Acquire( struct _Mutex_recursive_Control *_mutex ) ++mutex->nest_level; _Mutex_Queue_release( &mutex->Mutex, level, &queue_context ); } else { - _Thread_queue_Context_set_no_timeout( &queue_context ); + _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); _Mutex_Acquire_slow( &mutex->Mutex, owner, executing, level, &queue_context ); } } @@ -325,21 +313,10 @@ int _Mutex_recursive_Acquire_timed( return 0; } else { - Watchdog_Interval ticks; - - switch ( _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ) ) { - case TOD_ABSOLUTE_TIMEOUT_INVALID: - _Mutex_Queue_release( &mutex->Mutex, level, &queue_context ); - return EINVAL; - case TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST: - case TOD_ABSOLUTE_TIMEOUT_IS_NOW: - _Mutex_Queue_release( &mutex->Mutex, level, &queue_context ); - return ETIMEDOUT; - default: - break; - } - - _Thread_queue_Context_set_relative_timeout( &queue_context, ticks ); + _Thread_queue_Context_set_enqueue_timeout_realtime_timespec( + &queue_context, + abstime + ); _Mutex_Acquire_slow( &mutex->Mutex, owner, executing, level, &queue_context ); return STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) ); diff --git a/cpukit/score/src/semaphore.c b/cpukit/score/src/semaphore.c index a912fbc4d2..4edd25a387 100644 --- a/cpukit/score/src/semaphore.c +++ b/cpukit/score/src/semaphore.c @@ -61,7 +61,6 @@ void _Semaphore_Wait( struct _Semaphore_Control *_sem ) STATES_WAITING_FOR_SEMAPHORE ); _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); - _Thread_queue_Context_set_no_timeout( &queue_context ); _Thread_queue_Context_set_ISR_level( &queue_context, level ); _Thread_queue_Enqueue( &sem->Queue.Queue, diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index 40fb69bbd3..62d3671222 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -359,6 +359,7 @@ bool _Thread_queue_Path_acquire_critical( void _Thread_queue_Enqueue_do_nothing_extra( Thread_queue_Queue *queue, Thread_Control *the_thread, + Per_CPU_Control *cpu_self, Thread_queue_Context *queue_context ) { @@ -375,36 +376,6 @@ void _Thread_queue_Deadlock_fatal( Thread_Control *the_thread ) _Internal_error( INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK ); } -static void _Thread_queue_Timeout( - Thread_Control *the_thread, - Per_CPU_Control *cpu_self, - Thread_queue_Context *queue_context -) -{ - switch ( queue_context->timeout_discipline ) { - case WATCHDOG_RELATIVE: - /* A relative timeout of 0 is a special case indefinite (no) timeout */ - if ( queue_context->timeout != 0 ) { - _Thread_Add_timeout_ticks( - the_thread, - cpu_self, - (Watchdog_Interval) queue_context->timeout - ); - } - break; - case WATCHDOG_ABSOLUTE: - _Thread_Timer_insert_realtime( - the_thread, - cpu_self, - _Thread_Timeout, - queue_context->timeout - ); - break; - default: - break; - } -} - void _Thread_queue_Enqueue( Thread_queue_Queue *queue, const Thread_queue_Operations *operations, @@ -416,7 +387,6 @@ void _Thread_queue_Enqueue( bool success; _Assert( queue_context->enqueue_callout != NULL ); - _Assert( (uint8_t) queue_context->timeout_discipline != 0x7f ); #if defined(RTEMS_MULTIPROCESSING) if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet ) { @@ -447,18 +417,18 @@ void _Thread_queue_Enqueue( cpu_self = _Thread_queue_Dispatch_disable( queue_context ); _Thread_queue_Queue_release( queue, &queue_context->Lock_context.Lock_context ); - ( *queue_context->enqueue_callout )( queue, the_thread, queue_context ); + ( *queue_context->enqueue_callout )( + queue, + the_thread, + cpu_self, + queue_context + ); /* * Set the blocking state for this thread queue in the thread. */ _Thread_Set_state( the_thread, queue_context->thread_state ); - /* - * If the thread wants to timeout, then schedule its timer. - */ - _Thread_queue_Timeout( the_thread, cpu_self, queue_context ); - /* * At this point thread dispatching is disabled, however, we already released * the thread queue lock. Thus, interrupts or threads on other processors @@ -491,6 +461,8 @@ Status_Control _Thread_queue_Enqueue_sticky( { Per_CPU_Control *cpu_self; + _Assert( queue_context->enqueue_callout != NULL ); + _Thread_Wait_claim( the_thread, queue ); if ( !_Thread_queue_Path_acquire_critical( queue, the_thread, queue_context ) ) { @@ -519,7 +491,13 @@ Status_Control _Thread_queue_Enqueue_sticky( ); } - _Thread_queue_Timeout( the_thread, cpu_self, queue_context ); + ( *queue_context->enqueue_callout )( + queue, + the_thread, + cpu_self, + queue_context + ); + _Thread_Priority_update( queue_context ); _Thread_Priority_and_sticky_update( the_thread, 1 ); _Thread_Dispatch_enable( cpu_self ); diff --git a/cpukit/score/src/threadqtimeout.c b/cpukit/score/src/threadqtimeout.c new file mode 100644 index 0000000000..3f052fcf6f --- /dev/null +++ b/cpukit/score/src/threadqtimeout.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016, 2017 embedded brains GmbH + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +void _Thread_queue_Add_timeout_ticks( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context +) +{ + Watchdog_Interval ticks; + + ticks = queue_context->Timeout.ticks; + + if ( ticks != WATCHDOG_NO_TIMEOUT ) { + _Thread_Add_timeout_ticks( + the_thread, + cpu_self, + queue_context->Timeout.ticks + ); + } +} + +static bool _Thread_queue_Lazy_insert_monotonic_timespec( + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + const struct timespec *abstime +) +{ + uint64_t expire; + ISR_lock_Context lock_context; + bool insert; + + if ( abstime->tv_sec < 0 ) { + expire = 0; + } else if ( _Watchdog_Is_far_future_monotonic_timespec( abstime ) ) { + expire = WATCHDOG_MAXIMUM_TICKS; + } else { + expire = _Watchdog_Monotonic_from_timespec( abstime ); + } + + _ISR_lock_ISR_disable_and_acquire( + &the_thread->Timer.Lock, + &lock_context + ); + + the_thread->Timer.header = + &cpu_self->Watchdog.Header[ PER_CPU_WATCHDOG_MONOTONIC ]; + the_thread->Timer.Watchdog.routine = _Thread_Timeout; + insert = _Watchdog_Per_CPU_lazy_insert_monotonic( + &the_thread->Timer.Watchdog, + cpu_self, + expire + ); + + _ISR_lock_Release_and_ISR_enable( + &the_thread->Timer.Lock, + &lock_context + ); + return insert; +} + +void _Thread_queue_Add_timeout_monotonic_timespec( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context +) +{ + const struct timespec *abstime; + + abstime = queue_context->Timeout.arg; + + if ( _Watchdog_Is_valid_timespec( abstime ) ) { + if ( + !_Thread_queue_Lazy_insert_monotonic_timespec( + the_thread, + cpu_self, + abstime + ) + ) { + _Thread_Continue( the_thread, STATUS_TIMEOUT ); + } + } else { + _Thread_Continue( the_thread, STATUS_INVALID_NUMBER ); + } +} + +void _Thread_queue_Add_timeout_realtime_timespec( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context +) +{ + const struct timespec *abstime; + + abstime = queue_context->Timeout.arg; + + if ( _Watchdog_Is_valid_timespec( abstime ) ) { + uint64_t expire; + struct timespec now; + + if ( abstime->tv_sec < 0 ) { + expire = 0; + } else if ( _Watchdog_Is_far_future_realtime_timespec( abstime ) ) { + expire = WATCHDOG_MAXIMUM_TICKS; + } else { + expire = _Watchdog_Realtime_from_timespec( abstime ); + } + + _Timecounter_Getnanotime( &now ); + + if ( expire > _Watchdog_Realtime_from_timespec( &now ) ) { + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable_and_acquire( + &the_thread->Timer.Lock, + &lock_context + ); + + the_thread->Timer.header = + &cpu_self->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ]; + the_thread->Timer.Watchdog.routine = _Thread_Timeout; + _Watchdog_Per_CPU_insert_realtime( + &the_thread->Timer.Watchdog, + cpu_self, + expire + ); + + _ISR_lock_Release_and_ISR_enable( + &the_thread->Timer.Lock, + &lock_context + ); + } else { + _Thread_Continue( the_thread, STATUS_TIMEOUT ); + } + } else { + _Thread_Continue( the_thread, STATUS_INVALID_NUMBER ); + } +} diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index 7ee1f880c4..0430ca0407 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -514,6 +514,7 @@ void _Thread_Cancel( static void _Thread_Close_enqueue_callout( Thread_queue_Queue *queue, Thread_Control *the_thread, + Per_CPU_Control *cpu_self, Thread_queue_Context *queue_context ) { @@ -534,7 +535,6 @@ void _Thread_Close( &context->Base, _Thread_Close_enqueue_callout ); - _Thread_queue_Context_set_no_timeout( &context->Base ); _Thread_State_acquire_critical( the_thread, &context->Base.Lock_context.Lock_context -- cgit v1.2.3