diff options
-rw-r--r-- | cpukit/score/Makefile.am | 3 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/threadq.h | 25 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/threadqimpl.h | 189 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/threadsync.h | 60 | ||||
-rw-r--r-- | cpukit/score/preinstall.am | 4 | ||||
-rw-r--r-- | cpukit/score/src/threadq.c | 1 | ||||
-rw-r--r-- | cpukit/score/src/threadqenqueue.c | 232 | ||||
-rw-r--r-- | cpukit/score/src/threadqfirst.c | 7 | ||||
-rw-r--r-- | cpukit/score/src/threadqflush.c | 24 | ||||
-rw-r--r-- | cpukit/score/src/threadqops.c | 23 | ||||
-rw-r--r-- | cpukit/score/src/threadqprocesstimeout.c | 80 | ||||
-rw-r--r-- | cpukit/score/src/threadqtimeout.c | 44 | ||||
-rw-r--r-- | cpukit/score/src/threadtimeout.c | 6 | ||||
-rw-r--r-- | testsuites/sptests/spintrcritical01/init.c | 38 | ||||
-rw-r--r-- | testsuites/sptests/spintrcritical09/init.c | 28 | ||||
-rw-r--r-- | testsuites/sptests/spintrcritical16/init.c | 37 | ||||
-rw-r--r-- | testsuites/sptests/spintrcritical20/init.c | 10 | ||||
-rw-r--r-- | testsuites/sptests/spintrcritical22/init.c | 8 |
18 files changed, 320 insertions, 499 deletions
diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 18becdb300..19d3237607 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -82,7 +82,6 @@ include_rtems_score_HEADERS += include/rtems/score/threadimpl.h include_rtems_score_HEADERS += include/rtems/score/threaddispatch.h include_rtems_score_HEADERS += include/rtems/score/threadq.h include_rtems_score_HEADERS += include/rtems/score/threadqimpl.h -include_rtems_score_HEADERS += include/rtems/score/threadsync.h include_rtems_score_HEADERS += include/rtems/score/timespec.h include_rtems_score_HEADERS += include/rtems/score/timestamp.h include_rtems_score_HEADERS += include/rtems/score/timestamp64.h @@ -301,7 +300,7 @@ endif libscore_a_SOURCES += src/threadq.c \ src/threadqenqueue.c \ src/threadqextractwithproxy.c src/threadqfirst.c \ - src/threadqflush.c src/threadqprocesstimeout.c src/threadqtimeout.c + src/threadqflush.c libscore_a_SOURCES += src/threadqops.c ## TIMESPEC_C_FILES diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h index 59781ac73c..b89198608a 100644 --- a/cpukit/score/include/rtems/score/threadq.h +++ b/cpukit/score/include/rtems/score/threadq.h @@ -25,7 +25,6 @@ #include <rtems/score/priority.h> #include <rtems/score/rbtree.h> #include <rtems/score/states.h> -#include <rtems/score/threadsync.h> #ifdef __cplusplus extern "C" { @@ -84,21 +83,6 @@ typedef void ( *Thread_queue_Enqueue_operation )( ); /** - * @brief Thread queue dequeue operation. - * - * @param[in] the_thread_queue The thread queue. - * - * @retval NULL No thread is present on the thread queue. - * @retval first The first thread of the thread queue according to the insert - * order. This thread is no longer on the thread queue. - * - * @see _Thread_Wait_set_operations(). - */ -typedef Thread_Control *( *Thread_queue_Dequeue_operation )( - Thread_queue_Control *the_thread_queue -); - -/** * @brief Thread queue extract operation. * * @param[in] the_thread_queue The thread queue. @@ -159,13 +143,6 @@ typedef struct { Thread_queue_Enqueue_operation enqueue; /** - * @brief Thread queue dequeue operation. - * - * Called by object routines to dequeue the first waiting thread if present. - */ - Thread_queue_Dequeue_operation dequeue; - - /** * @brief Thread queue extract operation. * * Called by object routines to extract a thread from a thread queue. @@ -218,8 +195,6 @@ struct Thread_queue_Control { */ ISR_LOCK_MEMBER( Lock ) - /** This field is used to manage the critical section. */ - Thread_blocking_operation_States sync_state; /** This is the status value returned to threads which timeout while * waiting on this thread queue. */ diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h index 04e67309b2..9893aae8af 100644 --- a/cpukit/score/include/rtems/score/threadqimpl.h +++ b/cpukit/score/include/rtems/score/threadqimpl.h @@ -80,13 +80,54 @@ Thread_Control *_Thread_queue_Dequeue( ); /** - * @brief Blocks a thread and places it on a thread queue. + * @brief Blocks the thread and places it on the thread queue. * - * This routine blocks a thread, places it on a thread queue, and optionally - * starts a watchdog in case the timeout interval is not WATCHDOG_NO_TIMEOUT. + * This enqueues the thread on the thread queue, blocks the thread, and + * optionally starts the thread timer in case the timeout interval is not + * WATCHDOG_NO_TIMEOUT. * * The caller must be the owner of the thread queue lock. This function will * release the thread queue lock and register it as the new thread lock. + * Thread dispatching is disabled before the thread queue lock is released. + * Thread dispatching is enabled once the sequence to block the thread is + * complete. The operation to enqueue the thread on the queue is protected by + * the thread queue lock. This makes it possible to use the thread queue lock + * to protect the state of objects embedding the thread queue and directly + * enter _Thread_queue_Enqueue_critical() in case the thread must block. + * + * @code + * #include <rtems/score/threadqimpl.h> + * #include <rtems/score/statesimpl.h> + * + * typedef struct { + * Thread_queue_Control Queue; + * Thread_Control *owner; + * } Mutex; + * + * void _Mutex_Obtain( Mutex *mutex ) + * { + * ISR_lock_Context lock_context; + * Thread_Control *executing; + * + * _Thread_queue_Acquire( &mutex->Queue, &lock_context ); + * + * executing = _Thread_Executing; + * + * if ( mutex->owner == NULL ) { + * mutex->owner = executing; + * _Thread_queue_Release( &mutex->Queue, &lock_context ); + * } else { + * _Thread_queue_Enqueue_critical( + * &mutex->Queue, + * executing, + * STATES_WAITING_FOR_MUTEX, + * WATCHDOG_NO_TIMEOUT, + * 0, + * &lock_context + * ); + * } + * } + * @endcode * * @param[in] the_thread_queue The thread queue. * @param[in] the_thread The thread to enqueue. @@ -103,6 +144,10 @@ void _Thread_queue_Enqueue_critical( ISR_lock_Context *lock_context ); +/** + * @brief Acquires the thread queue lock and calls + * _Thread_queue_Enqueue_critical(). + */ RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread, @@ -123,33 +168,97 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue( } /** - * @brief Extracts thread from thread queue. + * @brief Extracts the thread from the thread queue, restores the default wait + * operations and restores the default thread lock. * - * This routine removes @a the_thread its thread queue - * and cancels any timeouts associated with this blocking. + * The caller must be the owner of the thread queue lock. The thread queue + * lock is not released. * - * @param[in] the_thread is the pointer to a thread control block that - * is to be removed + * @param[in] the_thread_queue The thread queue. + * @param[in] the_thread The thread to extract. */ -void _Thread_queue_Extract( Thread_Control *the_thread ); +void _Thread_queue_Extract_locked( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +); + +/** + * @brief Unblocks the thread which was on the thread queue before. + * + * The caller must be the owner of the thread queue lock. This function will + * release the thread queue lock. Thread dispatching is disabled before the + * thread queue lock is released and an unblock is necessary. Thread + * dispatching is enabled once the sequence to unblock the thread is complete. + * + * @param[in] the_thread_queue The thread queue. + * @param[in] the_thread The thread to extract. + * @param[in] lock_context The lock context of the lock acquire. + */ +void _Thread_queue_Unblock_critical( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_lock_Context *lock_context +); + +/** + * @brief Extracts the thread from the thread queue and unblocks it. + * + * The caller must be the owner of the thread queue lock. This function will + * release the thread queue lock and restore the default thread lock. Thread + * dispatching is disabled before the thread queue lock is released and an + * unblock is necessary. Thread dispatching is enabled once the sequence to + * unblock the thread is complete. This makes it possible to use the thread + * queue lock to protect the state of objects embedding the thread queue and + * directly enter _Thread_queue_Extract_critical() to finalize an operation in + * case a waiting thread exists. + * + * @code + * #include <rtems/score/threadqimpl.h> + * + * typedef struct { + * Thread_queue_Control Queue; + * Thread_Control *owner; + * } Mutex; + * + * void _Mutex_Release( Mutex *mutex ) + * { + * ISR_lock_Context lock_context; + * Thread_Control *first; + * + * _Thread_queue_Acquire( &mutex->Queue, &lock_context ); + * + * first = _Thread_queue_First_locked( &mutex->Queue ); + * mutex->owner = first; + * + * if ( first != NULL ) { + * _Thread_queue_Extract_critical( + * &mutex->Queue, + * first, + * &lock_context + * ); + * } + * @endcode + * + * @param[in] the_thread_queue The thread queue. + * @param[in] the_thread The thread to extract. + * @param[in] lock_context The lock context of the lock acquire. + */ +void _Thread_queue_Extract_critical( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_lock_Context *lock_context +); /** - * @brief Extracts thread from thread queue (w/return code). + * @brief Extracts thread from thread queue. * * This routine removes @a the_thread its thread queue * and cancels any timeouts associated with this blocking. * * @param[in] the_thread is the pointer to a thread control block that * is to be removed - * @param[in] return_code specifies the status to be returned. - * - * - INTERRUPT LATENCY: - * + single case */ -void _Thread_queue_Extract_with_return_code( - Thread_Control *the_thread, - uint32_t return_code -); +void _Thread_queue_Extract( Thread_Control *the_thread ); /** * @brief Extracts the_thread from the_thread_queue. @@ -164,9 +273,10 @@ void _Thread_queue_Extract_with_proxy( /** * @brief Returns the first thread on the thread queue if it exists, otherwise - * @c NULL (locked). + * @c NULL. * - * The caller must be the owner of the thread queue lock. + * The caller must be the owner of the thread queue lock. The thread queue + * lock is not released. * * @param[in] the_thread_queue The thread queue. * @@ -174,9 +284,12 @@ void _Thread_queue_Extract_with_proxy( * @retval first The first thread on the thread queue according to the enqueue * order. */ -Thread_Control *_Thread_queue_First_locked( +RTEMS_INLINE_ROUTINE Thread_Control *_Thread_queue_First_locked( Thread_queue_Control *the_thread_queue -); +) +{ + return ( *the_thread_queue->operations->first )( the_thread_queue ); +} /** * @brief Returns the first thread on the thread queue if it exists, otherwise @@ -235,38 +348,6 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy( } /** - * @brief Thread queue timeout. - * - * This routine is invoked when a task's request has not - * been satisfied after the timeout interval specified to - * enqueue. The task represented by ID will be unblocked and - * its status code will be set in it's control block to indicate - * that a timeout has occurred. - * - * @param[in] id thread id - */ -void _Thread_queue_Timeout( - Objects_Id id, - void *ignored -); - -/** - * @brief Process thread queue timeout. - * - * This is a shared helper routine which makes it easier to have multiple - * object class specific timeout routines. - * - * @param[in] the_thread is the thread to extract - * - * @note This method assumes thread dispatching is disabled - * and is expected to be called via the processing of - * a clock tick. - */ -void _Thread_queue_Process_timeout( - Thread_Control *the_thread -); - -/** * @brief Compare two thread's priority for RBTree Insertion. * * @param[in] left points to the left thread's RBnode diff --git a/cpukit/score/include/rtems/score/threadsync.h b/cpukit/score/include/rtems/score/threadsync.h deleted file mode 100644 index fa7aeeb003..0000000000 --- a/cpukit/score/include/rtems/score/threadsync.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file rtems/score/threadsync.h - * - * @brief Synchronize Thread Blocking Operations with Actions in an ISR - * - * This include file contains all constants and structures associated - * with synchronizing a thread blocking operation with potential - * actions in an ISR. - */ - -/* - * 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. - */ - -#ifndef _RTEMS_SCORE_THREAD_SYNC_H -#define _RTEMS_SCORE_THREAD_SYNC_H - -/** - * @defgroup ScoreThreadSync Thread Blocking Operation Synchronization Handler - * - * @ingroup Score - * - * This handler encapsulates functionality related to the management of - * synchronization critical sections during blocking operations. - */ -/**@{*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * The following enumerated types indicate what happened while the thread - * blocking was in the synchronization window. - */ -typedef enum { - THREAD_BLOCKING_OPERATION_SYNCHRONIZED, - THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED, - THREAD_BLOCKING_OPERATION_TIMEOUT, - THREAD_BLOCKING_OPERATION_SATISFIED -} Thread_blocking_operation_States; - -/* - * Operations require a thread pointer so they are prototyped - * in thread.h - */ - -#ifdef __cplusplus -} -#endif - -/**@}*/ - -#endif -/* end of include file */ diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index 920c0d9aeb..62e15720f4 100644 --- a/cpukit/score/preinstall.am +++ b/cpukit/score/preinstall.am @@ -311,10 +311,6 @@ $(PROJECT_INCLUDE)/rtems/score/threadqimpl.h: include/rtems/score/threadqimpl.h $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/threadqimpl.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/threadqimpl.h -$(PROJECT_INCLUDE)/rtems/score/threadsync.h: include/rtems/score/threadsync.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) - $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/threadsync.h -PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/threadsync.h - $(PROJECT_INCLUDE)/rtems/score/timespec.h: include/rtems/score/timespec.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timespec.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timespec.h diff --git a/cpukit/score/src/threadq.c b/cpukit/score/src/threadq.c index 61832c19a2..cdb99498fe 100644 --- a/cpukit/score/src/threadq.c +++ b/cpukit/score/src/threadq.c @@ -52,7 +52,6 @@ void _Thread_queue_Initialize( const Thread_queue_Operations *operations; the_thread_queue->timeout_status = timeout_status; - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; _ISR_lock_Initialize( &the_thread_queue->Lock, "Thread Queue" ); diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index be08ffcbf1..d02f2ee073 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -20,58 +20,28 @@ #include <rtems/score/threadqimpl.h> #include <rtems/score/assert.h> +#include <rtems/score/threaddispatch.h> #include <rtems/score/threadimpl.h> #include <rtems/score/watchdogimpl.h> -/** - * @brief Finalize a blocking operation. - * - * This method is used to finalize a blocking operation that was - * satisfied. It may be used with thread queues or any other synchronization - * object that uses the blocking states and watchdog times for timeout. - * - * This method will restore the previous ISR disable level during the cancel - * operation. Thus it is an implicit _ISR_Enable(). - * - * @param[in] the_thread is the thread whose blocking is canceled - * @param[in] lock_context is the previous ISR disable level - */ -static void _Thread_blocking_operation_Finalize( - Thread_queue_Control *the_thread_queue, - Thread_Control *the_thread, - ISR_lock_Context *lock_context -) -{ - /* - * The thread is not waiting on anything after this completes. - */ - _Thread_Wait_set_queue( the_thread, NULL ); - _Thread_Wait_restore_default_operations( the_thread ); +#define THREAD_QUEUE_INTEND_TO_BLOCK \ + (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_INTEND_TO_BLOCK) - _Thread_Lock_restore_default( the_thread ); +#define THREAD_QUEUE_BLOCKED \ + (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_BLOCKED) - /* - * If the sync state is timed out, this is very likely not needed. - * But better safe than sorry when it comes to critical sections. - */ - if ( _Watchdog_Is_active( &the_thread->Timer ) ) { - _Watchdog_Deactivate( &the_thread->Timer ); - _Thread_queue_Release( the_thread_queue, lock_context ); - _Watchdog_Remove_ticks( &the_thread->Timer ); - } else - _Thread_queue_Release( the_thread_queue, lock_context ); - - /* - * Global objects with thread queue's should not be operated on from an - * ISR. But the sync code still must allow short timeouts to be processed - * correctly. - */ +#define THREAD_QUEUE_READY_AGAIN \ + (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_READY_AGAIN) +static void _Thread_queue_Unblock( Thread_Control *the_thread ) +{ + _Watchdog_Remove_ticks( &the_thread->Timer ); _Thread_Unblock( the_thread ); #if defined(RTEMS_MULTIPROCESSING) - if ( !_Objects_Is_local_id( the_thread->Object.id ) ) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { _Thread_MP_Free_proxy( the_thread ); + } #endif } @@ -83,13 +53,20 @@ void _Thread_queue_Enqueue_critical( ISR_lock_Context *lock_context ) { - Thread_blocking_operation_States sync_state; + const Thread_queue_Operations *operations; + Per_CPU_Control *cpu_self; + bool success; _Thread_Lock_set( the_thread, &the_thread_queue->Lock ); - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; + operations = the_thread_queue->operations; _Thread_Wait_set_queue( the_thread, the_thread_queue ); + _Thread_Wait_set_operations( the_thread, operations ); + + ( *operations->enqueue )( the_thread_queue, the_thread ); + _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK ); + cpu_self = _Thread_Dispatch_disable_critical(); _Thread_queue_Release( the_thread_queue, lock_context ); #if defined(RTEMS_MULTIPROCESSING) @@ -105,121 +82,120 @@ void _Thread_queue_Enqueue_critical( /* * If the thread wants to timeout, then schedule its timer. */ - if ( timeout ) { - _Watchdog_Initialize( - &the_thread->Timer, - _Thread_queue_Timeout, - the_thread->Object.id, - NULL + if ( timeout != WATCHDOG_NO_TIMEOUT ) { + _Thread_Wait_set_timeout_code( + the_thread, + the_thread_queue->timeout_status ); - + _Watchdog_Initialize( &the_thread->Timer, _Thread_Timeout, 0, the_thread ); _Watchdog_Insert_ticks( &the_thread->Timer, timeout ); } - /* - * Now initiate the enqueuing and checking if the blocking operation - * should be completed or the thread has had its blocking condition - * satisfied before we got here. - */ - _Thread_queue_Acquire( the_thread_queue, lock_context ); + success = _Thread_Wait_flags_try_change( + the_thread, + THREAD_QUEUE_INTEND_TO_BLOCK, + THREAD_QUEUE_BLOCKED + ); + if ( !success ) { + _Thread_queue_Unblock( the_thread ); + } - sync_state = the_thread_queue->sync_state; - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; + _Thread_Dispatch_enable( cpu_self ); +} - if ( sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { - const Thread_queue_Operations *operations; +void _Thread_queue_Extract_locked( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +) +{ + ( *the_thread_queue->operations->extract )( the_thread_queue, the_thread ); - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; + _Thread_Wait_set_queue( the_thread, NULL ); + _Thread_Wait_restore_default_operations( the_thread ); + _Thread_Lock_restore_default( the_thread ); +} - operations = the_thread_queue->operations; - _Thread_Wait_set_operations( the_thread, operations ); - ( *operations->enqueue )( the_thread_queue, the_thread ); +void _Thread_queue_Unblock_critical( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_lock_Context *lock_context +) +{ + bool success; + bool unblock; - _Thread_queue_Release( the_thread_queue, lock_context ); + success = _Thread_Wait_flags_try_change_critical( + the_thread, + THREAD_QUEUE_INTEND_TO_BLOCK, + THREAD_QUEUE_READY_AGAIN + ); + if ( success ) { + unblock = false; } else { - /* Cancel a blocking operation due to ISR */ + _Assert( _Thread_Wait_flags_get( the_thread ) == THREAD_QUEUE_BLOCKED ); + _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_READY_AGAIN ); + unblock = true; + } - _Assert( - sync_state == THREAD_BLOCKING_OPERATION_TIMEOUT || - sync_state == THREAD_BLOCKING_OPERATION_SATISFIED - ); + if ( unblock ) { + Per_CPU_Control *cpu_self; - _Thread_blocking_operation_Finalize( the_thread_queue, the_thread, lock_context ); + cpu_self = _Thread_Dispatch_disable_critical(); + _Thread_queue_Release( the_thread_queue, lock_context ); + + _Thread_queue_Unblock( the_thread ); + + _Thread_Dispatch_enable( cpu_self ); + } else { + _Thread_queue_Release( the_thread_queue, lock_context ); } } -void _Thread_queue_Extract_with_return_code( - Thread_Control *the_thread, - uint32_t return_code +void _Thread_queue_Extract_critical( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_lock_Context *lock_context ) { - Thread_queue_Control *the_thread_queue; - ISR_lock_Control *lock; + _Thread_queue_Extract_locked( the_thread_queue, the_thread ); + _Thread_queue_Unblock_critical( the_thread_queue, the_thread, lock_context ); +} + +void _Thread_queue_Extract( Thread_Control *the_thread ) +{ ISR_lock_Context lock_context; + ISR_lock_Control *lock; + Thread_queue_Control *the_thread_queue; lock = _Thread_Lock_acquire( the_thread, &lock_context ); the_thread_queue = the_thread->Wait.queue; - if ( the_thread_queue == NULL ) { - _Thread_Lock_release( lock, &lock_context ); - return; - } - - _SMP_Assert( lock == &the_thread_queue->Lock ); - - ( *the_thread_queue->operations->extract )( the_thread_queue, the_thread ); - the_thread->Wait.return_code = return_code; + if ( the_thread_queue != NULL ) { + _SMP_Assert( lock == &the_thread_queue->Lock ); - /* - * We found a thread to unblock. - * - * NOTE: This is invoked with interrupts still disabled. - */ - _Thread_blocking_operation_Finalize( the_thread_queue, the_thread, &lock_context ); -} - -void _Thread_queue_Extract( Thread_Control *the_thread ) -{ - _Thread_queue_Extract_with_return_code( - the_thread, - the_thread->Wait.return_code - ); + _Thread_queue_Extract_critical( the_thread_queue, the_thread, &lock_context ); + } else { + _Thread_Lock_release( lock, &lock_context ); + } } -Thread_Control *_Thread_queue_Dequeue( - Thread_queue_Control *the_thread_queue -) +Thread_Control *_Thread_queue_Dequeue( Thread_queue_Control *the_thread_queue ) { - Thread_Control *the_thread; - ISR_lock_Context lock_context; - Thread_blocking_operation_States sync_state; + ISR_lock_Context lock_context; + Thread_Control *the_thread; _Thread_queue_Acquire( the_thread_queue, &lock_context ); - the_thread = ( *the_thread_queue->operations->dequeue )( the_thread_queue ); - if ( the_thread == NULL ) { - /* - * We did not find a thread to unblock in the queue. Maybe the executing - * thread is about to block on this thread queue. - */ - sync_state = the_thread_queue->sync_state; - if ( (sync_state == THREAD_BLOCKING_OPERATION_TIMEOUT) || - (sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED) ) { - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SATISFIED; - the_thread = _Thread_Executing; - } else { - _Thread_queue_Release( the_thread_queue, &lock_context ); - return NULL; - } - } + the_thread = _Thread_queue_First_locked( the_thread_queue ); - /* - * We found a thread to unblock. - * - * NOTE: This is invoked with interrupts still disabled. - */ - _Thread_blocking_operation_Finalize( the_thread_queue, the_thread, &lock_context ); + if ( the_thread != NULL ) { + _SMP_Assert( the_thread->Lock.current == &the_thread_queue->Lock ); + + _Thread_queue_Extract_critical( the_thread_queue, the_thread, &lock_context ); + } else { + _Thread_queue_Release( the_thread_queue, &lock_context ); + } return the_thread; } diff --git a/cpukit/score/src/threadqfirst.c b/cpukit/score/src/threadqfirst.c index 553b28bf62..c46f005c3e 100644 --- a/cpukit/score/src/threadqfirst.c +++ b/cpukit/score/src/threadqfirst.c @@ -20,13 +20,6 @@ #include <rtems/score/threadqimpl.h> -Thread_Control *_Thread_queue_First_locked( - Thread_queue_Control *the_thread_queue -) -{ - return ( *the_thread_queue->operations->first )( the_thread_queue ); -} - Thread_Control *_Thread_queue_First( Thread_queue_Control *the_thread_queue ) diff --git a/cpukit/score/src/threadqflush.c b/cpukit/score/src/threadqflush.c index 1abe8aca3e..d37b9e8ae7 100644 --- a/cpukit/score/src/threadqflush.c +++ b/cpukit/score/src/threadqflush.c @@ -31,14 +31,30 @@ void _Thread_queue_Flush( uint32_t status ) { - Thread_Control *the_thread; + ISR_lock_Context lock_context; + Thread_Control *the_thread; + + _Thread_queue_Acquire( the_thread_queue, &lock_context ); + + while ( (the_thread = _Thread_queue_First_locked( the_thread_queue ) ) ) { +#if defined(RTEMS_MULTIPROCESSING) + if ( _Objects_Is_local_id( the_thread->Object.id ) ) +#endif + the_thread->Wait.return_code = status; + + _Thread_queue_Extract_critical( + the_thread_queue, + the_thread, + &lock_context + ); - while ( (the_thread = _Thread_queue_Dequeue( the_thread_queue )) ) { #if defined(RTEMS_MULTIPROCESSING) if ( !_Objects_Is_local_id( the_thread->Object.id ) ) ( *remote_extract_callout )( the_thread ); - else #endif - the_thread->Wait.return_code = status; + + _Thread_queue_Acquire( the_thread_queue, &lock_context ); } + + _Thread_queue_Release( the_thread_queue, &lock_context ); } diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c index 9958ed667c..2967a0efc3 100644 --- a/cpukit/score/src/threadqops.c +++ b/cpukit/score/src/threadqops.c @@ -55,16 +55,6 @@ static void _Thread_queue_FIFO_enqueue( ); } -static Thread_Control *_Thread_queue_FIFO_dequeue( - Thread_queue_Control *the_thread_queue -) -{ - Chain_Control *fifo = &the_thread_queue->Queues.Fifo; - - return _Chain_Is_empty( fifo ) ? - NULL : THREAD_CHAIN_NODE_TO_THREAD( _Chain_Get_first_unprotected( fifo ) ); -} - static void _Thread_queue_FIFO_extract( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread @@ -121,17 +111,6 @@ static void _Thread_queue_Priority_enqueue( ); } -static Thread_Control *_Thread_queue_Priority_dequeue( - Thread_queue_Control *the_thread_queue -) -{ - RBTree_Node *first; - - first = _RBTree_Get( &the_thread_queue->Queues.Priority, RBT_LEFT ); - - return first != NULL ? THREAD_RBTREE_NODE_TO_THREAD( first ) : NULL; -} - static void _Thread_queue_Priority_extract( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread @@ -168,7 +147,6 @@ const Thread_queue_Operations _Thread_queue_Operations_FIFO = { .priority_change = _Thread_queue_Do_nothing_priority_change, .initialize = _Thread_queue_FIFO_initialize, .enqueue = _Thread_queue_FIFO_enqueue, - .dequeue = _Thread_queue_FIFO_dequeue, .extract = _Thread_queue_FIFO_extract, .first = _Thread_queue_FIFO_first }; @@ -177,7 +155,6 @@ const Thread_queue_Operations _Thread_queue_Operations_priority = { .priority_change = _Thread_queue_Priority_priority_change, .initialize = _Thread_queue_Priority_initialize, .enqueue = _Thread_queue_Priority_enqueue, - .dequeue = _Thread_queue_Priority_dequeue, .extract = _Thread_queue_Priority_extract, .first = _Thread_queue_Priority_first }; diff --git a/cpukit/score/src/threadqprocesstimeout.c b/cpukit/score/src/threadqprocesstimeout.c deleted file mode 100644 index dbb8f5ce45..0000000000 --- a/cpukit/score/src/threadqprocesstimeout.c +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file - * - * @brief Thread Queue Handler Process Timeout Handler - * @ingroup ScoreThreadQ - */ - -/* - * 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 <rtems/score/threadqimpl.h> -#include <rtems/score/threadimpl.h> - -void _Thread_queue_Process_timeout( - Thread_Control *the_thread -) -{ - Thread_queue_Control *the_thread_queue; - ISR_Level level; - - /* - * If the_thread_queue is not synchronized, then it is either - * "nothing happened", "timeout", or "satisfied". If the_thread - * is the executing thread, then it is in the process of blocking - * and it is the thread which is responsible for the synchronization - * process. - * - * If it is not satisfied, then it is "nothing happened" and - * this is the "timeout" transition. After a request is satisfied, - * a timeout is not allowed to occur. - */ - - _ISR_Disable( level ); - the_thread_queue = the_thread->Wait.queue; - if ( the_thread_queue != NULL ) { - if ( the_thread_queue->sync_state != THREAD_BLOCKING_OPERATION_SYNCHRONIZED && - _Thread_Is_executing( the_thread ) ) { - if ( the_thread_queue->sync_state != THREAD_BLOCKING_OPERATION_SATISFIED ) { - the_thread->Wait.return_code = the_thread_queue->timeout_status; - the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_TIMEOUT; - } - _ISR_Enable( level ); - } else { - _ISR_Enable( level ); - - /* - * After we enable interrupts here, a lot may happen in the meantime, - * e.g. nested interrupts may release the resource that times out here. - * So we enter _Thread_queue_Extract() speculatively. Inside this - * function we check the actual status under ISR disable protection. - * This ensures that exactly one executing context performs the extract - * operation (other parties may call _Thread_queue_Dequeue()). If this - * context won, then we have a timeout. - * - * We can use the_thread_queue pointer here even if - * the_thread->Wait.queue is already set to NULL since the extract - * operation will only use the thread queue discipline to select the - * right extract operation. The timeout status is set during thread - * queue initialization. - */ - _Thread_queue_Extract_with_return_code( - the_thread, - the_thread_queue->timeout_status - ); - } - } else { - _ISR_Enable( level ); - } -} - diff --git a/cpukit/score/src/threadqtimeout.c b/cpukit/score/src/threadqtimeout.c deleted file mode 100644 index fcacd1c781..0000000000 --- a/cpukit/score/src/threadqtimeout.c +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file - * - * @brief Thread Queue Timeout - * @ingroup ScoreThreadQ - */ - -/* - * 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 <rtems/score/threadqimpl.h> -#include <rtems/score/threadimpl.h> - -void _Thread_queue_Timeout( - Objects_Id id, - void *ignored __attribute__((unused)) -) -{ - Thread_Control *the_thread; - Objects_Locations location; - - the_thread = _Thread_Get( id, &location ); - switch ( location ) { - case OBJECTS_ERROR: -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* impossible */ -#endif - break; - case OBJECTS_LOCAL: - _Thread_queue_Process_timeout( the_thread ); - _Objects_Put_without_thread_dispatch( &the_thread->Object ); - break; - } -} diff --git a/cpukit/score/src/threadtimeout.c b/cpukit/score/src/threadtimeout.c index 300beb5219..f69bc35ea2 100644 --- a/cpukit/score/src/threadtimeout.c +++ b/cpukit/score/src/threadtimeout.c @@ -76,5 +76,11 @@ void _Thread_Timeout( Objects_Id id, void *arg ) if ( unblock ) { _Thread_Unblock( the_thread ); + +#if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { + _Thread_MP_Free_proxy( the_thread ); + } +#endif } } diff --git a/testsuites/sptests/spintrcritical01/init.c b/testsuites/sptests/spintrcritical01/init.c index dc36aee4fd..b7cfee42f8 100644 --- a/testsuites/sptests/spintrcritical01/init.c +++ b/testsuites/sptests/spintrcritical01/init.c @@ -14,12 +14,7 @@ #include <tmacros.h> #include <intrcritical.h> -#include <rtems/rtems/semimpl.h> - -/* forward declarations to avoid warnings */ -rtems_task Init(rtems_task_argument argument); -rtems_timer_service_routine test_release_from_isr(rtems_id timer, void *arg); -Thread_blocking_operation_States getState(void); +#include <rtems/score/threadimpl.h> #if defined(FIFO_NO_TIMEOUT) #define TEST_NAME "1" @@ -58,33 +53,28 @@ Thread_blocking_operation_States getState(void); const char rtems_test_name[] = "SPINTRCRITICAL " TEST_NAME; -rtems_id Semaphore; -volatile bool case_hit = false; +static Thread_Control *thread; + +static rtems_id Semaphore; + +static bool case_hit; -Thread_blocking_operation_States getState(void) +static bool interrupts_blocking_op(void) { - Objects_Locations location; - Semaphore_Control *sem; - - sem = (Semaphore_Control *)_Objects_Get( - &_Semaphore_Information, Semaphore, &location ); - if ( location != OBJECTS_LOCAL ) { - puts( "Bad object lookup" ); - rtems_test_exit(0); - } - _Thread_Unnest_dispatch(); + Thread_Wait_flags flags = _Thread_Wait_flags_get( thread ); - return sem->Core_control.semaphore.Wait_queue.sync_state; + return + flags == ( THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_INTEND_TO_BLOCK ); } -rtems_timer_service_routine test_release_from_isr( +static rtems_timer_service_routine test_release_from_isr( rtems_id timer, void *arg ) { rtems_status_code status; - if ( getState() == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { + if ( interrupts_blocking_op() ) { case_hit = true; } @@ -109,7 +99,7 @@ static bool test_body( void *arg ) return case_hit; } -rtems_task Init( +static rtems_task Init( rtems_task_argument ignored ) { @@ -117,6 +107,8 @@ rtems_task Init( TEST_BEGIN(); + thread = _Thread_Get_executing(); + puts( "Init - Trying to generate semaphore release from ISR while blocking" ); puts( "Init - Variation is: " TEST_STRING ); status = rtems_semaphore_create( diff --git a/testsuites/sptests/spintrcritical09/init.c b/testsuites/sptests/spintrcritical09/init.c index 0e38351d43..cc119e88c1 100644 --- a/testsuites/sptests/spintrcritical09/init.c +++ b/testsuites/sptests/spintrcritical09/init.c @@ -14,28 +14,22 @@ #include <tmacros.h> #include <intrcritical.h> -#include <rtems/rtems/semimpl.h> +#include <rtems/score/threadimpl.h> #include <rtems/score/watchdogimpl.h> const char rtems_test_name[] = "SPINTRCRITICAL 9"; +static Thread_Control *thread; + static rtems_id Semaphore; -static bool case_hit = false; -static Thread_blocking_operation_States getState(void) +static bool case_hit; + +static bool is_interrupt_timeout(void) { - Objects_Locations location; - Semaphore_Control *sem; - - sem = (Semaphore_Control *)_Objects_Get( - &_Semaphore_Information, Semaphore, &location ); - if ( location != OBJECTS_LOCAL ) { - puts( "Bad object lookup" ); - rtems_test_exit(0); - } - _Thread_Unnest_dispatch(); + Thread_Wait_flags flags = _Thread_Wait_flags_get( thread ); - return sem->Core_control.semaphore.Wait_queue.sync_state; + return flags == ( THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_READY_AGAIN ); } static rtems_timer_service_routine test_release_from_isr( @@ -50,14 +44,14 @@ static rtems_timer_service_routine test_release_from_isr( if ( watchdog->delta_interval == 0 - && watchdog->routine == _Thread_queue_Timeout + && watchdog->routine == _Thread_Timeout ) { Watchdog_States state = _Watchdog_Remove_ticks( watchdog ); rtems_test_assert( state == WATCHDOG_ACTIVE ); (*watchdog->routine)( watchdog->id, watchdog->user_data ); - if ( getState() == THREAD_BLOCKING_OPERATION_TIMEOUT ) { + if ( is_interrupt_timeout() ) { case_hit = true; } } @@ -81,6 +75,8 @@ static rtems_task Init( TEST_BEGIN(); + thread = _Thread_Get_executing(); + puts( "Init - Test may not be able to detect case is hit reliably" ); puts( "Init - Trying to generate timeout from ISR while blocking" ); sc = rtems_semaphore_create( diff --git a/testsuites/sptests/spintrcritical16/init.c b/testsuites/sptests/spintrcritical16/init.c index 08eeb8b9b4..a094b419b3 100644 --- a/testsuites/sptests/spintrcritical16/init.c +++ b/testsuites/sptests/spintrcritical16/init.c @@ -14,47 +14,36 @@ #include <tmacros.h> #include <intrcritical.h> -#include <rtems/rtems/semimpl.h> +#include <rtems/score/threadimpl.h> const char rtems_test_name[] = "SPINTRCRITICAL 16"; -/* forward declarations to avoid warnings */ -rtems_task Init(rtems_task_argument argument); -rtems_timer_service_routine test_release_from_isr(rtems_id timer, void *arg); -Thread_blocking_operation_States getState(void); +static Thread_Control *Main_TCB; -Thread_Control *Main_TCB; -rtems_id Semaphore; -volatile bool case_hit = false; +static rtems_id Semaphore; -Thread_blocking_operation_States getState(void) +static bool case_hit; + +static bool interrupts_blocking_op(void) { - Objects_Locations location; - Semaphore_Control *sem; - - sem = (Semaphore_Control *)_Objects_Get( - &_Semaphore_Information, Semaphore, &location ); - if ( location != OBJECTS_LOCAL ) { - puts( "Bad object lookup" ); - rtems_test_exit(0); - } - _Thread_Unnest_dispatch(); + Thread_Wait_flags flags = _Thread_Wait_flags_get( Main_TCB ); - return sem->Core_control.semaphore.Wait_queue.sync_state; + return + flags == ( THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_INTEND_TO_BLOCK ); } -rtems_timer_service_routine test_release_from_isr( +static rtems_timer_service_routine test_release_from_isr( rtems_id timer, void *arg ) { - if ( getState() == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { + if ( interrupts_blocking_op() ) { case_hit = true; (void) rtems_semaphore_release( Semaphore ); } if ( Main_TCB->Wait.queue != NULL ) { - _Thread_queue_Process_timeout( Main_TCB ); + _Thread_Timeout( 0, Main_TCB ); } } @@ -70,7 +59,7 @@ static bool test_body( void *arg ) return case_hit; } -rtems_task Init( +static rtems_task Init( rtems_task_argument ignored ) { diff --git a/testsuites/sptests/spintrcritical20/init.c b/testsuites/sptests/spintrcritical20/init.c index daa8ac7f7e..7e52211742 100644 --- a/testsuites/sptests/spintrcritical20/init.c +++ b/testsuites/sptests/spintrcritical20/init.c @@ -44,6 +44,10 @@ static void semaphore_task(rtems_task_argument arg) test_context *ctx = (test_context *) arg; ctx->semaphore_task_tcb = _Thread_Get_executing(); + _Thread_Wait_set_timeout_code( + ctx->semaphore_task_tcb, + CORE_SEMAPHORE_TIMEOUT + ); while (true) { rtems_status_code sc = rtems_semaphore_obtain( @@ -87,7 +91,7 @@ static bool test_body(void *arg) ctx->thread_queue_was_null = true; } - _Thread_queue_Process_timeout(ctx->semaphore_task_tcb); + _Thread_Timeout(0, ctx->semaphore_task_tcb); switch (ctx->semaphore_task_tcb->Wait.return_code) { case CORE_SEMAPHORE_STATUS_SUCCESSFUL: @@ -103,7 +107,9 @@ static bool test_body(void *arg) _Thread_Enable_dispatch(); - return false; + return ctx->thread_queue_was_null + && ctx->status_was_successful + && ctx->status_was_timeout; } static void Init(rtems_task_argument ignored) diff --git a/testsuites/sptests/spintrcritical22/init.c b/testsuites/sptests/spintrcritical22/init.c index 93946c39c5..1a377f7838 100644 --- a/testsuites/sptests/spintrcritical22/init.c +++ b/testsuites/sptests/spintrcritical22/init.c @@ -52,14 +52,18 @@ static void release_semaphore(rtems_id timer, void *arg) rtems_status_code sc; CORE_mutex_Control *mtx = &ctx->semaphore_control->Core_control.mutex; - if (mtx->Wait_queue.sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED) { + if ( + _Thread_Wait_flags_get(ctx->main_task_control) + == (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_INTEND_TO_BLOCK) + ) { ctx->done = true; sc = rtems_semaphore_release(ctx->semaphore_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert( - mtx->Wait_queue.sync_state == THREAD_BLOCKING_OPERATION_SATISFIED + _Thread_Wait_flags_get(ctx->main_task_control) + == (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_READY_AGAIN) ); rtems_test_assert(mtx->nest_count == 1); rtems_test_assert(mtx->holder == ctx->main_task_control); |