summaryrefslogtreecommitdiffstats
path: root/cpukit/include/rtems/score/threadqimpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/include/rtems/score/threadqimpl.h')
-rw-r--r--cpukit/include/rtems/score/threadqimpl.h1265
1 files changed, 1265 insertions, 0 deletions
diff --git a/cpukit/include/rtems/score/threadqimpl.h b/cpukit/include/rtems/score/threadqimpl.h
new file mode 100644
index 0000000000..ecbd8fd42f
--- /dev/null
+++ b/cpukit/include/rtems/score/threadqimpl.h
@@ -0,0 +1,1265 @@
+/**
+ * @file rtems/score/threadq.h
+ *
+ * Constants and Structures Associated with the Manipulation of Objects
+ *
+ * This include file contains all the constants and structures associated
+ * with the manipulation of objects.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2014.
+ * 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_THREADQIMPL_H
+#define _RTEMS_SCORE_THREADQIMPL_H
+
+#include <rtems/score/threadq.h>
+#include <rtems/score/chainimpl.h>
+#include <rtems/score/priorityimpl.h>
+#include <rtems/score/scheduler.h>
+#include <rtems/score/smp.h>
+#include <rtems/score/status.h>
+#include <rtems/score/thread.h>
+#include <rtems/score/threaddispatch.h>
+
+#if defined(RTEMS_DEBUG)
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup ScoreThreadQueue
+ */
+/**@{*/
+
+#define THREAD_QUEUE_LINK_OF_PATH_NODE( node ) \
+ RTEMS_CONTAINER_OF( node, Thread_queue_Link, Path_node );
+
+/**
+ * @brief Thread queue with a layout compatible to struct _Thread_queue_Queue
+ * defined in Newlib <sys/lock.h>.
+ */
+typedef struct {
+#if !defined(RTEMS_SMP)
+ /*
+ * The struct _Thread_queue_Queue definition is independent of the RTEMS
+ * build configuration. Thus, the storage space for the SMP lock is always
+ * present. In SMP configurations, the SMP lock is contained in the
+ * Thread_queue_Queue.
+ */
+ unsigned int reserved[2];
+#endif
+
+ Thread_queue_Queue Queue;
+} Thread_queue_Syslock_queue;
+
+void _Thread_queue_Enqueue_do_nothing_extra(
+ Thread_queue_Queue *queue,
+ Thread_Control *the_thread,
+ Per_CPU_Control *cpu_self,
+ Thread_queue_Context *queue_context
+);
+
+void _Thread_queue_Add_timeout_ticks(
+ Thread_queue_Queue *queue,
+ Thread_Control *the_thread,
+ Per_CPU_Control *cpu_self,
+ Thread_queue_Context *queue_context
+);
+
+void _Thread_queue_Add_timeout_monotonic_timespec(
+ Thread_queue_Queue *queue,
+ Thread_Control *the_thread,
+ Per_CPU_Control *cpu_self,
+ Thread_queue_Context *queue_context
+);
+
+void _Thread_queue_Add_timeout_realtime_timespec(
+ Thread_queue_Queue *queue,
+ Thread_Control *the_thread,
+ Per_CPU_Control *cpu_self,
+ Thread_queue_Context *queue_context
+);
+
+/**
+ * @brief Sets the thread wait return code to STATUS_DEADLOCK.
+ */
+void _Thread_queue_Deadlock_status( Thread_Control *the_thread );
+
+/**
+ * @brief Results in an INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK fatal error.
+ */
+void _Thread_queue_Deadlock_fatal( Thread_Control *the_thread );
+
+/**
+ * @brief Initializes a thread queue context.
+ *
+ * @param queue_context The thread queue context to initialize.
+ */
+RTEMS_INLINE_ROUTINE void _Thread_queue_Context_initialize(
+ Thread_queue_Context *queue_context
+)
+{
+#if defined(RTEMS_DEBUG)
+ memset( queue_context, 0x7f, sizeof( *queue_context ) );
+#if defined(RTEMS_SMP)
+ _Chain_Initialize_node( &queue_context->Lock_context.Wait.Gate.Node );
+#endif
+ queue_context->enqueue_callout = NULL;
+ queue_context->deadlock_callout = NULL;
+#else
+ (void) queue_context;
+#endif
+}
+
+/**
+ * @brief Sets the thread state for the thread to enqueue in the thread queue
+ * context.
+ *
+ * @param queue_context The thread queue context.
+ * @param state The thread state.
+ *
+ * @see _Thread_queue_Enqueue().
+ */
+RTEMS_INLINE_ROUTINE void
+_Thread_queue_Context_set_thread_state(
+ Thread_queue_Context *queue_context,
+ States_Control thread_state
+)
+{
+ queue_context->thread_state = thread_state;
+}
+
+/**
+ * @brief Sets the timeout ticks in the thread queue context.
+ *
+ * @param queue_context The thread queue context.
+ * @param ticks The timeout in ticks.
+ *
+ * @see _Thread_queue_Enqueue().
+ */
+RTEMS_INLINE_ROUTINE void
+_Thread_queue_Context_set_timeout_ticks(
+ Thread_queue_Context *queue_context,
+ Watchdog_Interval ticks
+)
+{
+ queue_context->Timeout.ticks = ticks;
+}
+
+/**
+ * @brief Sets the timeout argument in the thread queue context.
+ *
+ * @param queue_context The thread queue context.
+ * @param arg The timeout argument.
+ *
+ * @see _Thread_queue_Enqueue().
+ */
+RTEMS_INLINE_ROUTINE void
+_Thread_queue_Context_set_timeout_argument(
+ Thread_queue_Context *queue_context,
+ const void *arg
+)
+{
+ queue_context->Timeout.arg = arg;
+}
+
+/**
+ * @brief Sets the enqueue callout in the thread queue context.
+ *
+ * @param queue_context The thread queue context.
+ * @param enqueue_callout The enqueue callout.
+ *
+ * @see _Thread_queue_Enqueue().
+ */
+RTEMS_INLINE_ROUTINE void
+_Thread_queue_Context_set_enqueue_callout(
+ Thread_queue_Context *queue_context,
+ Thread_queue_Enqueue_callout enqueue_callout
+)
+{
+ queue_context->enqueue_callout = enqueue_callout;
+}
+
+/**
+ * @brief Sets the do nothing enqueue callout in the thread queue context.
+ *
+ * @param queue_context The thread queue context.
+ *
+ * @see _Thread_queue_Enqueue().
+ */
+RTEMS_INLINE_ROUTINE void
+_Thread_queue_Context_set_enqueue_do_nothing_extra(
+ Thread_queue_Context *queue_context
+)
+{
+ queue_context->enqueue_callout = _Thread_queue_Enqueue_do_nothing_extra;
+}
+
+/**
+ * @brief Sets the enqueue callout to add a relative monotonic timeout in
+ * ticks.
+ *
+ * @param queue_context The thread queue context.
+ * @param ticks The timeout in ticks.
+ *
+ * @see _Thread_queue_Enqueue().
+ */
+RTEMS_INLINE_ROUTINE void
+_Thread_queue_Context_set_enqueue_timeout_ticks(
+ Thread_queue_Context *queue_context,
+ Watchdog_Interval ticks
+)
+{
+ queue_context->Timeout.ticks = ticks;
+ queue_context->enqueue_callout = _Thread_queue_Add_timeout_ticks;
+}
+
+/**
+ * @brief Sets the enqueue callout to add an absolute monotonic timeout in
+ * timespec format.
+ *
+ * @param queue_context The thread queue context.
+ * @param abstime The absolute monotonic timeout.
+ *
+ * @see _Thread_queue_Enqueue().
+ */
+RTEMS_INLINE_ROUTINE void
+_Thread_queue_Context_set_enqueue_timeout_monotonic_timespec(
+ Thread_queue_Context *queue_context,
+ const struct timespec *abstime
+)
+{
+ queue_context->Timeout.arg = abstime;
+ queue_context->enqueue_callout =
+ _Thread_queue_Add_timeout_monotonic_timespec;
+}
+
+/**
+ * @brief Sets the enqueue callout to add an absolute realtime timeout in
+ * timespec format.
+ *
+ * @param queue_context The thread queue context.
+ * @param abstime The absolute realtime timeout.
+ *
+ * @see _Thread_queue_Enqueue().
+ */
+RTEMS_INLINE_ROUTINE void
+_Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
+ Thread_queue_Context *queue_context,
+ const struct timespec *abstime
+)
+{
+ queue_context->Timeout.arg = abstime;
+ queue_context->enqueue_callout = _Thread_queue_Add_timeout_realtime_timespec;
+}
+
+/**
+ * @brief Sets the deadlock callout in the thread queue
+ * context.
+ *
+ * A deadlock callout must be provided for _Thread_queue_Enqueue()
+ * operations that operate on thread queues which may have an owner, e.g. mutex
+ * objects. Available deadlock callouts are _Thread_queue_Deadlock_status()
+ * and _Thread_queue_Deadlock_fatal().
+ *
+ * @param queue_context The thread queue context.
+ * @param deadlock_callout The deadlock callout.
+ *
+ * @see _Thread_queue_Enqueue().
+ */
+RTEMS_INLINE_ROUTINE void _Thread_queue_Context_set_deadlock_callout(
+ Thread_queue_Context *queue_context,
+ Thread_queue_Deadlock_callout deadlock_callout
+)
+{
+ queue_context->deadlock_callout = deadlock_callout;
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Context_clear_priority_updates(
+ Thread_queue_Context *queue_context
+)
+{
+ queue_context->Priority.update_count = 0;
+}
+
+RTEMS_INLINE_ROUTINE size_t _Thread_queue_Context_save_priority_updates(
+ Thread_queue_Context *queue_context
+)
+{
+ return queue_context->Priority.update_count;
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Context_restore_priority_updates(
+ Thread_queue_Context *queue_context,
+ size_t update_count
+)
+{
+ queue_context->Priority.update_count = update_count;
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Context_add_priority_update(
+ Thread_queue_Context *queue_context,
+ Thread_Control *the_thread
+)
+{
+ size_t n;
+
+ n = queue_context->Priority.update_count;
+ _Assert( n < RTEMS_ARRAY_SIZE( queue_context->Priority.update ) );
+
+ queue_context->Priority.update_count = n + 1;
+ queue_context->Priority.update[ n ] = the_thread;
+}
+
+#define _Thread_queue_Context_ISR_disable( queue_context, level ) \
+ do { \
+ _ISR_Local_disable( level ); \
+ _ISR_lock_ISR_disable_profile( \
+ &( queue_context )->Lock_context.Lock_context \
+ ) \
+ } while ( 0 )
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Context_set_ISR_level(
+ Thread_queue_Context *queue_context,
+ ISR_Level level
+)
+{
+ _ISR_lock_Context_set_level(
+ &queue_context->Lock_context.Lock_context,
+ level
+ );
+}
+
+RTEMS_INLINE_ROUTINE Per_CPU_Control *_Thread_queue_Dispatch_disable(
+ Thread_queue_Context *queue_context
+)
+{
+ return _Thread_Dispatch_disable_critical(
+ &queue_context->Lock_context.Lock_context
+ );
+}
+
+/**
+ * @brief Sets the MP callout in the thread queue context.
+ *
+ * @param queue_context The thread queue context.
+ * @param mp_callout Callout to unblock the thread in case it is actually a
+ * thread proxy. This parameter is only used on multiprocessing
+ * configurations. Used by thread queue extract and unblock methods for
+ * objects with multiprocessing (MP) support.
+ */
+#if defined(RTEMS_MULTIPROCESSING)
+RTEMS_INLINE_ROUTINE void _Thread_queue_Context_set_MP_callout(
+ Thread_queue_Context *queue_context,
+ Thread_queue_MP_callout mp_callout
+)
+{
+ queue_context->mp_callout = mp_callout;
+}
+#else
+#define _Thread_queue_Context_set_MP_callout( queue_context, mp_callout ) \
+ do { \
+ (void) queue_context; \
+ } while ( 0 )
+#endif
+
+#if defined(RTEMS_SMP)
+RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_close(
+ Thread_queue_Gate *gate
+)
+{
+ _Atomic_Store_uint( &gate->go_ahead, 0, ATOMIC_ORDER_RELAXED );
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_add(
+ Chain_Control *chain,
+ Thread_queue_Gate *gate
+)
+{
+ _Chain_Append_unprotected( chain, &gate->Node );
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_open(
+ Thread_queue_Gate *gate
+)
+{
+ _Atomic_Store_uint( &gate->go_ahead, 1, ATOMIC_ORDER_RELAXED );
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_wait(
+ Thread_queue_Gate *gate
+)
+{
+ while ( _Atomic_Load_uint( &gate->go_ahead, ATOMIC_ORDER_RELAXED ) == 0 ) {
+ /* Wait */
+ }
+}
+#endif
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Heads_initialize(
+ Thread_queue_Heads *heads
+)
+{
+#if defined(RTEMS_SMP)
+ size_t i;
+
+ for ( i = 0; i < _Scheduler_Count; ++i ) {
+ _Chain_Initialize_node( &heads->Priority[ i ].Node );
+ _Priority_Initialize_empty( &heads->Priority[ i ].Queue );
+ heads->Priority[ i ].Queue.scheduler = &_Scheduler_Table[ i ];
+ }
+#endif
+
+ _Chain_Initialize_empty( &heads->Free_chain );
+ _Chain_Initialize_node( &heads->Free_node );
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_initialize(
+ Thread_queue_Queue *queue,
+ const char *name
+)
+{
+#if defined(RTEMS_SMP)
+ _SMP_ticket_lock_Initialize( &queue->Lock );
+#endif
+ queue->heads = NULL;
+ queue->owner = NULL;
+ queue->name = name;
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_do_acquire_critical(
+ Thread_queue_Queue *queue,
+#if defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
+ SMP_lock_Stats *lock_stats,
+#endif
+ ISR_lock_Context *lock_context
+)
+{
+#if defined(RTEMS_SMP)
+ _SMP_ticket_lock_Acquire(
+ &queue->Lock,
+ lock_stats,
+ &lock_context->Lock_context.Stats_context
+ );
+#else
+ (void) queue;
+ (void) lock_context;
+#endif
+}
+
+#if defined(RTEMS_SMP) && defined( RTEMS_PROFILING )
+ #define \
+ _Thread_queue_Queue_acquire_critical( queue, lock_stats, lock_context ) \
+ _Thread_queue_Queue_do_acquire_critical( queue, lock_stats, lock_context )
+#else
+ #define \
+ _Thread_queue_Queue_acquire_critical( queue, lock_stats, lock_context ) \
+ _Thread_queue_Queue_do_acquire_critical( queue, lock_context )
+#endif
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_release_critical(
+ Thread_queue_Queue *queue,
+ ISR_lock_Context *lock_context
+)
+{
+#if defined(RTEMS_SMP)
+ _SMP_ticket_lock_Release(
+ &queue->Lock,
+ &lock_context->Lock_context.Stats_context
+ );
+#else
+ (void) queue;
+ (void) lock_context;
+#endif
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Queue_release(
+ Thread_queue_Queue *queue,
+ ISR_lock_Context *lock_context
+)
+{
+ _Thread_queue_Queue_release_critical( queue, lock_context );
+ _ISR_lock_ISR_enable( lock_context );
+}
+
+/**
+ * @brief Copies the thread queue name to the specified buffer.
+ *
+ * @param[in] queue The actual thread queue.
+ * @param[in] buffer The buffer for the thread queue name copy.
+ * @param[in] buffer_size The buffer size in characters.
+ * @param[in] id The object identifier in case the thread queue is embedded in
+ * an object with identifier, otherwise it is set to 0.
+ *
+ * @retval The length of the thread queue name. May be greater than or equal
+ * to the buffer size if truncation occurred.
+ */
+size_t _Thread_queue_Queue_get_name_and_id(
+ const Thread_queue_Queue *queue,
+ char *buffer,
+ size_t buffer_size,
+ Objects_Id *id
+);
+
+#if defined(RTEMS_SMP)
+void _Thread_queue_Do_acquire_critical(
+ Thread_queue_Control *the_thread_queue,
+ ISR_lock_Context *lock_context
+);
+#else
+RTEMS_INLINE_ROUTINE void _Thread_queue_Do_acquire_critical(
+ Thread_queue_Control *the_thread_queue,
+ ISR_lock_Context *lock_context
+)
+{
+ (void) the_thread_queue;
+ (void) lock_context;
+}
+#endif
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire_critical(
+ Thread_queue_Control *the_thread_queue,
+ Thread_queue_Context *queue_context
+)
+{
+ _Thread_queue_Do_acquire_critical(
+ the_thread_queue,
+ &queue_context->Lock_context.Lock_context
+ );
+}
+
+#if defined(RTEMS_SMP)
+void _Thread_queue_Acquire(
+ Thread_queue_Control *the_thread_queue,
+ Thread_queue_Context *queue_context
+);
+#else
+RTEMS_INLINE_ROUTINE void _Thread_queue_Acquire(
+ Thread_queue_Control *the_thread_queue,
+ Thread_queue_Context *queue_context
+)
+{
+ (void) the_thread_queue;
+ _ISR_lock_ISR_disable( &queue_context->Lock_context.Lock_context );
+}
+#endif
+
+#if defined(RTEMS_DEBUG)
+RTEMS_INLINE_ROUTINE bool _Thread_queue_Is_lock_owner(
+ const Thread_queue_Control *the_thread_queue
+)
+{
+#if defined(RTEMS_SMP)
+ return the_thread_queue->owner == _SMP_lock_Who_am_I();
+#else
+ return _ISR_Get_level() != 0;
+#endif
+}
+#endif
+
+#if defined(RTEMS_SMP)
+void _Thread_queue_Do_release_critical(
+ Thread_queue_Control *the_thread_queue,
+ ISR_lock_Context *lock_context
+);
+#else
+RTEMS_INLINE_ROUTINE void _Thread_queue_Do_release_critical(
+ Thread_queue_Control *the_thread_queue,
+ ISR_lock_Context *lock_context
+)
+{
+ (void) the_thread_queue;
+ (void) lock_context;
+ _Assert( _Thread_queue_Is_lock_owner( the_thread_queue ) );
+}
+#endif
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Release_critical(
+ Thread_queue_Control *the_thread_queue,
+ Thread_queue_Context *queue_context
+)
+{
+ _Thread_queue_Do_release_critical(
+ the_thread_queue,
+ &queue_context->Lock_context.Lock_context
+ );
+}
+
+#if defined(RTEMS_SMP)
+void _Thread_queue_Release(
+ Thread_queue_Control *the_thread_queue,
+ Thread_queue_Context *queue_context
+);
+#else
+RTEMS_INLINE_ROUTINE void _Thread_queue_Release(
+ Thread_queue_Control *the_thread_queue,
+ Thread_queue_Context *queue_context
+)
+{
+ (void) the_thread_queue;
+ _Assert( _Thread_queue_Is_lock_owner( the_thread_queue ) );
+ _ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
+}
+#endif
+
+Thread_Control *_Thread_queue_Do_dequeue(
+ Thread_queue_Control *the_thread_queue,
+ const Thread_queue_Operations *operations
+#if defined(RTEMS_MULTIPROCESSING)
+ ,
+ Thread_queue_MP_callout mp_callout
+#endif
+);
+
+/**
+ * @brief Gets a pointer to a thread waiting on the_thread_queue.
+ *
+ * This function returns a pointer to a thread waiting on
+ * the_thread_queue. The selection of this thread is based on
+ * the discipline of the_thread_queue. If no threads are waiting
+ * on the_thread_queue, then NULL is returned.
+ *
+ * - INTERRUPT LATENCY:
+ * + single case
+ */
+#if defined(RTEMS_MULTIPROCESSING)
+ #define _Thread_queue_Dequeue( \
+ the_thread_queue, \
+ operations, \
+ mp_callout \
+ ) \
+ _Thread_queue_Do_dequeue( \
+ the_thread_queue, \
+ operations, \
+ mp_callout \
+ )
+#else
+ #define _Thread_queue_Dequeue( \
+ the_thread_queue, \
+ operations, \
+ mp_callout \
+ ) \
+ _Thread_queue_Do_dequeue( \
+ the_thread_queue, \
+ operations \
+ )
+#endif
+
+/**
+ * @brief Blocks the thread and places it on the thread queue.
+ *
+ * This enqueues the thread on the thread queue, blocks the thread, and
+ * optionally starts the thread timer in case the timeout discipline is not
+ * WATCHDOG_NO_TIMEOUT. Timeout discipline and value are in the queue_context.
+ *
+ * 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() in case the thread must block.
+ *
+ * The thread queue context must be set up with the following functions,
+ * otherwise the behaviour is unpredictable
+ *
+ * - _Thread_queue_Context_set_thread_state(),
+ *
+ * - _Thread_queue_Context_set_enqueue_callout() or
+ * _Thread_queue_Context_set_enqueue_do_nothing_extra() or
+ * _Thread_queue_Context_set_enqueue_timeout_ticks() or
+ * _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec() or
+ * _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(),
+ *
+ * - _Thread_queue_Context_set_deadlock_callout().
+ *
+ * @code
+ * #include <rtems/score/threadqimpl.h>
+ * #include <rtems/score/statesimpl.h>
+ *
+ * #define MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
+ *
+ * typedef struct {
+ * Thread_queue_Control Queue;
+ * } Mutex;
+ *
+ * void _Mutex_Obtain( Mutex *mutex )
+ * {
+ * Thread_queue_Context queue_context;
+ * Thread_Control *executing;
+ *
+ * _Thread_queue_Context_initialize( &queue_context );
+ * _Thread_queue_Acquire( &mutex->Queue, queue_context );
+ *
+ * executing = _Thread_Executing;
+ *
+ * if ( mutex->Queue.owner == NULL ) {
+ * mutex->Queue.owner = executing;
+ * _Thread_queue_Release( &mutex->Queue, queue_context );
+ * } else {
+ * _Thread_queue_Context_set_thread_state(
+ * &queue_context,
+ * STATES_WAITING_FOR_MUTEX
+ * );
+ * _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context );
+ * _Thread_queue_Context_set_deadlock_callout(
+ * queue_context,
+ * _Thread_queue_Deadlock_fatal
+ * );
+ * _Thread_queue_Enqueue(
+ * &mutex->Queue.Queue,
+ * MUTEX_TQ_OPERATIONS,
+ * executing,
+ * &queue_context
+ * );
+ * }
+ * }
+ * @endcode
+ *
+ * @param[in] queue The actual thread queue.
+ * @param[in] operations The thread queue operations.
+ * @param[in] the_thread The thread to enqueue.
+ * @param[in] queue_context The thread queue context of the lock acquire.
+ */
+void _Thread_queue_Enqueue(
+ Thread_queue_Queue *queue,
+ const Thread_queue_Operations *operations,
+ Thread_Control *the_thread,
+ Thread_queue_Context *queue_context
+);
+
+#if defined(RTEMS_SMP)
+/**
+ * @brief Enqueues the thread on the thread queue and busy waits for dequeue.
+ *
+ * Optionally starts the thread timer in case the timeout discipline is not
+ * WATCHDOG_NO_TIMEOUT. Timeout discipline and value are in the queue_context.
+ *
+ * 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.
+ *
+ * The thread priorities of the owner and the are updated with respect to the
+ * scheduler. The sticky level of the thread is incremented. A thread
+ * dispatch is performed if necessary.
+ *
+ * Afterwards, the thread busy waits on the thread wait flags until a timeout
+ * occurs or the thread queue is surrendered to this thread. So, it sticks to
+ * the processor instead of blocking with respect to the scheduler.
+ *
+ * @param[in] queue The actual thread queue.
+ * @param[in] operations The thread queue operations.
+ * @param[in] the_thread The thread to enqueue.
+ * @param[in] queue_context The thread queue context of the lock acquire.
+ */
+Status_Control _Thread_queue_Enqueue_sticky(
+ Thread_queue_Queue *queue,
+ const Thread_queue_Operations *operations,
+ Thread_Control *the_thread,
+ Thread_queue_Context *queue_context
+);
+#endif
+
+/**
+ * @brief Extracts the thread from the thread queue, restores the default wait
+ * operations and restores the default thread lock.
+ *
+ * The caller must be the owner of the thread queue lock. The thread queue
+ * lock is not released.
+ *
+ * @param[in] queue The actual thread queue.
+ * @param[in] operations The thread queue operations.
+ * @param[in] the_thread The thread to extract.
+ * @param[in] queue_context The thread queue context.
+ *
+ * @return Returns the unblock indicator for _Thread_queue_Unblock_critical().
+ * True indicates, that this thread must be unblocked by the scheduler later in
+ * _Thread_queue_Unblock_critical(), and false otherwise. In case false is
+ * returned, then the thread queue enqueue procedure was interrupted. Thus it
+ * will unblock itself and the thread wait information is no longer accessible,
+ * since this thread may already block on another resource in an SMP
+ * configuration.
+ */
+bool _Thread_queue_Extract_locked(
+ Thread_queue_Queue *queue,
+ const Thread_queue_Operations *operations,
+ Thread_Control *the_thread,
+ Thread_queue_Context *queue_context
+);
+
+/**
+ * @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] unblock The unblock indicator returned by
+ * _Thread_queue_Extract_locked().
+ * @param[in] queue The actual 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(
+ bool unblock,
+ Thread_queue_Queue *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 )
+ * {
+ * Thread_queue_Context queue_context;
+ * Thread_Control *first;
+ *
+ * _Thread_queue_Context_initialize( &queue_context, NULL );
+ * _Thread_queue_Acquire( &mutex->Queue, queue_context );
+ *
+ * first = _Thread_queue_First_locked( &mutex->Queue );
+ * mutex->owner = first;
+ *
+ * if ( first != NULL ) {
+ * _Thread_queue_Extract_critical(
+ * &mutex->Queue.Queue,
+ * mutex->Queue.operations,
+ * first,
+ * &queue_context
+ * );
+ * }
+ * @endcode
+ *
+ * @param[in] queue The actual thread queue.
+ * @param[in] operations The thread queue operations.
+ * @param[in] the_thread The thread to extract.
+ * @param[in] queue_context The thread queue context of the lock acquire.
+ */
+void _Thread_queue_Extract_critical(
+ Thread_queue_Queue *queue,
+ const Thread_queue_Operations *operations,
+ Thread_Control *the_thread,
+ Thread_queue_Context *queue_context
+);
+
+/**
+ * @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
+ */
+void _Thread_queue_Extract( Thread_Control *the_thread );
+
+/**
+ * @brief Extracts the_thread from the_thread_queue.
+ *
+ * This routine extracts the_thread from the_thread_queue
+ * and ensures that if there is a proxy for this task on
+ * another node, it is also dealt with.
+ */
+void _Thread_queue_Extract_with_proxy(
+ Thread_Control *the_thread
+);
+
+/**
+ * @brief Surrenders the thread queue previously owned by the thread to the
+ * first enqueued thread.
+ *
+ * The owner of the thread queue must be set to NULL by the caller.
+ *
+ * This function releases the thread queue lock. In addition it performs a
+ * thread dispatch if necessary.
+ *
+ * @param[in] queue The actual thread queue.
+ * @param[in] heads The thread queue heads. It must not be NULL.
+ * @param[in] previous_owner The previous owner thread surrendering the thread
+ * queue.
+ * @param[in] queue_context The thread queue context of the lock acquire.
+ * @param[in] operations The thread queue operations.
+ */
+void _Thread_queue_Surrender(
+ Thread_queue_Queue *queue,
+ Thread_queue_Heads *heads,
+ Thread_Control *previous_owner,
+ Thread_queue_Context *queue_context,
+ const Thread_queue_Operations *operations
+);
+
+#if defined(RTEMS_SMP)
+/**
+ * @brief Surrenders the thread queue previously owned by the thread to the
+ * first enqueued thread.
+ *
+ * The owner of the thread queue must be set to NULL by the caller.
+ *
+ * The caller must be the owner of the thread queue lock. This function will
+ * release the thread queue.
+ *
+ * The thread priorities of the previous owner and the new owner are updated. The
+ * sticky level of the previous owner is decremented. A thread dispatch is
+ * performed if necessary.
+ *
+ * @param[in] queue The actual thread queue.
+ * @param[in] heads The thread queue heads. It must not be NULL.
+ * @param[in] previous_owner The previous owner thread surrendering the thread
+ * queue.
+ * @param[in] queue_context The thread queue context of the lock acquire.
+ * @param[in] operations The thread queue operations.
+ */
+void _Thread_queue_Surrender_sticky(
+ Thread_queue_Queue *queue,
+ Thread_queue_Heads *heads,
+ Thread_Control *previous_owner,
+ Thread_queue_Context *queue_context,
+ const Thread_queue_Operations *operations
+);
+#endif
+
+RTEMS_INLINE_ROUTINE bool _Thread_queue_Is_empty(
+ const Thread_queue_Queue *queue
+)
+{
+ return queue->heads == NULL;
+}
+
+/**
+ * @brief Returns the first thread on the thread queue if it exists, otherwise
+ * @c NULL.
+ *
+ * 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.
+ * @param[in] operations The thread queue operations.
+ *
+ * @retval NULL No thread is present on the thread queue.
+ * @retval first The first thread on the thread queue according to the enqueue
+ * order.
+ */
+RTEMS_INLINE_ROUTINE Thread_Control *_Thread_queue_First_locked(
+ Thread_queue_Control *the_thread_queue,
+ const Thread_queue_Operations *operations
+)
+{
+ Thread_queue_Heads *heads = the_thread_queue->Queue.heads;
+
+ if ( heads != NULL ) {
+ return ( *operations->first )( heads );
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * @brief Returns the first thread on the thread queue if it exists, otherwise
+ * @c NULL.
+ *
+ * @param[in] the_thread_queue The thread queue.
+ *
+ * @retval NULL No thread is present on the thread queue.
+ * @retval first The first thread on the thread queue according to the enqueue
+ * order.
+ */
+Thread_Control *_Thread_queue_First(
+ Thread_queue_Control *the_thread_queue,
+ const Thread_queue_Operations *operations
+);
+
+/**
+ * @brief Thread queue flush filter function.
+ *
+ * Called under protection of the thread queue lock by
+ * _Thread_queue_Flush_critical() to optionally alter the thread wait
+ * information and control the iteration.
+ *
+ * @param the_thread The thread to extract. This is the first parameter to
+ * optimize for architectures that use the same register for the first
+ * parameter and the return value.
+ * @param queue The actual thread queue.
+ * @param queue_context The thread queue context of the lock acquire. May be
+ * used to pass additional data to the filter function via an overlay
+ * structure. The filter function should not release or acquire the thread
+ * queue lock.
+ *
+ * @retval the_thread Extract this thread.
+ * @retval NULL Do not extract this thread and stop the thread queue flush
+ * operation. Threads that are already extracted will complete the flush
+ * operation.
+ */
+typedef Thread_Control *( *Thread_queue_Flush_filter )(
+ Thread_Control *the_thread,
+ Thread_queue_Queue *queue,
+ Thread_queue_Context *queue_context
+);
+
+/**
+ * @brief Default thread queue flush filter function.
+ *
+ * @param the_thread The thread to extract.
+ * @param queue Unused.
+ * @param queue_context Unused.
+ *
+ * @retval the_thread Extract this thread.
+ */
+Thread_Control *_Thread_queue_Flush_default_filter(
+ Thread_Control *the_thread,
+ Thread_queue_Queue *queue,
+ Thread_queue_Context *queue_context
+);
+
+/**
+ * @brief Status unavailable thread queue flush filter function.
+ *
+ * Sets the thread wait return code of the thread to STATUS_UNAVAILABLE.
+ *
+ * @param the_thread The thread to extract.
+ * @param queue Unused.
+ * @param queue_context Unused.
+ *
+ * @retval the_thread Extract this thread.
+ */
+Thread_Control *_Thread_queue_Flush_status_unavailable(
+ Thread_Control *the_thread,
+ Thread_queue_Queue *queue,
+ Thread_queue_Context *queue_context
+);
+
+/**
+ * @brief Status object was deleted thread queue flush filter function.
+ *
+ * Sets the thread wait return code of the thread to STATUS_OBJECT_WAS_DELETED
+ *
+ * @param the_thread The thread to extract.
+ * @param queue Unused.
+ * @param queue_context Unused.
+ *
+ * @retval the_thread Extract this thread.
+ */
+Thread_Control *_Thread_queue_Flush_status_object_was_deleted(
+ Thread_Control *the_thread,
+ Thread_queue_Queue *queue,
+ Thread_queue_Context *queue_context
+);
+
+/**
+ * @brief Unblocks all threads enqueued on the thread queue.
+ *
+ * This function iteratively extracts the first enqueued thread of the thread
+ * queue until the thread queue is empty or the filter function indicates a
+ * stop. The thread timers of the extracted threads are cancelled. The
+ * extracted threads are unblocked.
+ *
+ * @param queue The actual thread queue.
+ * @param operations The thread queue operations.
+ * @param filter The filter functions is called for each thread to extract from
+ * the thread queue. It may be used to alter the thread under protection of
+ * the thread queue lock, for example to set the thread wait return code.
+ * The return value of the filter function controls if the thread queue flush
+ * operation should stop or continue.
+ * @param queue_context The thread queue context of the lock acquire. May be
+ * used to pass additional data to the filter function via an overlay
+ * structure. The filter function should not release or acquire the thread
+ * queue lock.
+ *
+ * @return The count of extracted threads.
+ */
+size_t _Thread_queue_Flush_critical(
+ Thread_queue_Queue *queue,
+ const Thread_queue_Operations *operations,
+ Thread_queue_Flush_filter filter,
+ Thread_queue_Context *queue_context
+);
+
+void _Thread_queue_Initialize(
+ Thread_queue_Control *the_thread_queue,
+ const char *name
+);
+
+#if defined(RTEMS_SMP) && defined(RTEMS_DEBUG) && defined(RTEMS_PROFILING)
+ #define THREAD_QUEUE_INITIALIZER( _name ) \
+ { \
+ .Lock_stats = SMP_LOCK_STATS_INITIALIZER( _name ), \
+ .owner = SMP_LOCK_NO_OWNER, \
+ .Queue = { \
+ .Lock = SMP_TICKET_LOCK_INITIALIZER, \
+ .heads = NULL, \
+ .owner = NULL, \
+ .name = _name \
+ } \
+ }
+#elif defined(RTEMS_SMP) && defined(RTEMS_DEBUG)
+ #define THREAD_QUEUE_INITIALIZER( _name ) \
+ { \
+ .owner = SMP_LOCK_NO_OWNER, \
+ .Queue = { \
+ .Lock = SMP_TICKET_LOCK_INITIALIZER, \
+ .heads = NULL, \
+ .owner = NULL, \
+ .name = _name \
+ } \
+ }
+#elif defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
+ #define THREAD_QUEUE_INITIALIZER( _name ) \
+ { \
+ .Lock_stats = SMP_LOCK_STATS_INITIALIZER( _name ), \
+ .Queue = { \
+ .Lock = SMP_TICKET_LOCK_INITIALIZER, \
+ .heads = NULL, \
+ .owner = NULL, \
+ .name = _name \
+ } \
+ }
+#elif defined(RTEMS_SMP)
+ #define THREAD_QUEUE_INITIALIZER( _name ) \
+ { \
+ .Queue = { \
+ .Lock = SMP_TICKET_LOCK_INITIALIZER, \
+ .heads = NULL, \
+ .owner = NULL, \
+ .name = _name \
+ } \
+ }
+#else
+ #define THREAD_QUEUE_INITIALIZER( _name ) \
+ { \
+ .Queue = { \
+ .heads = NULL, \
+ .owner = NULL, \
+ .name = _name \
+ } \
+ }
+#endif
+
+RTEMS_INLINE_ROUTINE void _Thread_queue_Destroy(
+ Thread_queue_Control *the_thread_queue
+)
+{
+#if defined(RTEMS_SMP)
+ _SMP_ticket_lock_Destroy( &the_thread_queue->Queue.Lock );
+ _SMP_lock_Stats_destroy( &the_thread_queue->Lock_stats );
+#endif
+}
+
+#if defined(RTEMS_MULTIPROCESSING)
+void _Thread_queue_MP_callout_do_nothing(
+ Thread_Control *the_proxy,
+ Objects_Id mp_id
+);
+
+void _Thread_queue_Unblock_proxy(
+ Thread_queue_Queue *queue,
+ Thread_Control *the_thread
+);
+#endif
+
+#if defined(RTEMS_SMP)
+bool _Thread_queue_Path_acquire_critical(
+ Thread_queue_Queue *queue,
+ Thread_Control *the_thread,
+ Thread_queue_Context *queue_context
+);
+
+void _Thread_queue_Path_release_critical(
+ Thread_queue_Context *queue_context
+);
+#endif
+
+/**
+ * @brief Helper structure to ensure that all objects containing a thread queue
+ * have the right layout.
+ *
+ * @see _Thread_Wait_get_id() and THREAD_QUEUE_OBJECT_ASSERT().
+ */
+typedef struct {
+ Objects_Control Object;
+ Thread_queue_Control Wait_queue;
+} Thread_queue_Object;
+
+#define THREAD_QUEUE_OBJECT_ASSERT( object_type, wait_queue_member ) \
+ RTEMS_STATIC_ASSERT( \
+ offsetof( object_type, wait_queue_member ) \
+ == offsetof( Thread_queue_Object, Wait_queue ) \
+ && RTEMS_HAVE_MEMBER_SAME_TYPE( \
+ object_type, \
+ wait_queue_member, \
+ Thread_queue_Object, \
+ Wait_queue \
+ ), \
+ object_type \
+ )
+
+#define THREAD_QUEUE_QUEUE_TO_OBJECT( queue ) \
+ RTEMS_CONTAINER_OF( \
+ queue, \
+ Thread_queue_Object, \
+ Wait_queue.Queue \
+ )
+
+extern const Thread_queue_Operations _Thread_queue_Operations_default;
+
+extern const Thread_queue_Operations _Thread_queue_Operations_FIFO;
+
+extern const Thread_queue_Operations _Thread_queue_Operations_priority;
+
+extern const Thread_queue_Operations _Thread_queue_Operations_priority_inherit;
+
+/**
+ * @brief The special thread queue name to indicated that the thread queue is
+ * embedded in an object with identifier.
+ *
+ * @see _Thread_queue_Object_initialize().
+ */
+extern const char _Thread_queue_Object_name[];
+
+/**
+ * @brief Initializes a thread queue embedded in an object with identifier.
+ *
+ * The object must have the layout specified by Thread_queue_Object. It should
+ * be ensured with the THREAD_QUEUE_OBJECT_ASSERT() static assertion.
+ *
+ * @param[in] the_thread_queue The thread queue.
+ */
+void _Thread_queue_Object_initialize(
+ Thread_queue_Control *the_thread_queue
+);
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* end of include file */