summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpukit/score/Makefile.am3
-rw-r--r--cpukit/score/include/rtems/score/threadq.h25
-rw-r--r--cpukit/score/include/rtems/score/threadqimpl.h189
-rw-r--r--cpukit/score/include/rtems/score/threadsync.h60
-rw-r--r--cpukit/score/preinstall.am4
-rw-r--r--cpukit/score/src/threadq.c1
-rw-r--r--cpukit/score/src/threadqenqueue.c232
-rw-r--r--cpukit/score/src/threadqfirst.c7
-rw-r--r--cpukit/score/src/threadqflush.c24
-rw-r--r--cpukit/score/src/threadqops.c23
-rw-r--r--cpukit/score/src/threadqprocesstimeout.c80
-rw-r--r--cpukit/score/src/threadqtimeout.c44
-rw-r--r--cpukit/score/src/threadtimeout.c6
-rw-r--r--testsuites/sptests/spintrcritical01/init.c38
-rw-r--r--testsuites/sptests/spintrcritical09/init.c28
-rw-r--r--testsuites/sptests/spintrcritical16/init.c37
-rw-r--r--testsuites/sptests/spintrcritical20/init.c10
-rw-r--r--testsuites/sptests/spintrcritical22/init.c8
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);