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/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 +- 22 files changed, 342 insertions(+), 313 deletions(-) delete mode 100644 cpukit/score/src/coretodabsolutetimeout.c create mode 100644 cpukit/score/src/threadqtimeout.c (limited to 'cpukit/score') 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