[rtems commit] score: New thread queue implementation
Sebastian Huber
sebh at rtems.org
Wed May 20 07:12:03 UTC 2015
Module: rtems
Branch: master
Commit: cc366ec8c9ecaab838a745175a0d53a7a5db437e
Changeset: http://git.rtems.org/rtems/commit/?id=cc366ec8c9ecaab838a745175a0d53a7a5db437e
Author: Sebastian Huber <sebastian.huber at embedded-brains.de>
Date: Fri Apr 24 12:02:20 2015 +0200
score: New thread queue implementation
Use thread wait flags for synchronization. The enqueue operation is now
part of the initial critical section. This is the key change and
enables fine grained locking on SMP for objects using a thread queue
like semaphores and message queues.
Update #2273.
---
cpukit/score/Makefile.am | 3 +-
cpukit/score/include/rtems/score/threadq.h | 25 ---
cpukit/score/include/rtems/score/threadqimpl.h | 189 ++++++++++++++------
cpukit/score/include/rtems/score/threadsync.h | 60 -------
cpukit/score/preinstall.am | 4 -
cpukit/score/src/threadq.c | 1 -
cpukit/score/src/threadqenqueue.c | 232 +++++++++++--------------
cpukit/score/src/threadqfirst.c | 7 -
cpukit/score/src/threadqflush.c | 24 ++-
cpukit/score/src/threadqops.c | 23 ---
cpukit/score/src/threadqprocesstimeout.c | 80 ---------
cpukit/score/src/threadqtimeout.c | 44 -----
cpukit/score/src/threadtimeout.c | 6 +
testsuites/sptests/spintrcritical01/init.c | 38 ++--
testsuites/sptests/spintrcritical09/init.c | 28 ++-
testsuites/sptests/spintrcritical16/init.c | 37 ++--
testsuites/sptests/spintrcritical20/init.c | 10 +-
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 18becdb..19d3237 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 59781ac..b891986 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 04e6730..9893aae 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 fa7aeeb..0000000
--- 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 920c0d9..62e1572 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 61832c1..cdb9949 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 be08ffc..d02f2ee 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 553b28b..c46f005 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 1abe8ac..d37b9e8 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 9958ed6..2967a0e 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 dbb8f5c..0000000
--- 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 fcacd1c..0000000
--- 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 300beb5..f69bc35 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 dc36aee..b7cfee4 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 0e38351..cc119e8 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 08eeb8b..a094b41 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 daa8ac7..7e52211 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 93946c3..1a377f7 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);
More information about the vc
mailing list