/* * Copyright (c) 2015 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 * 82178 Puchheim * Germany * * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include static void _Thread_queue_Do_nothing_priority_change( Thread_Control *the_thread, Priority_Control new_priority, Thread_queue_Queue *queue ) { /* Do nothing */ } static void _Thread_queue_Do_nothing_extract( Thread_queue_Queue *queue, Thread_Control *the_thread ) { /* Do nothing */ } static void _Thread_queue_Queue_enqueue( Thread_queue_Queue *queue, Thread_Control *the_thread, void ( *initialize )( Thread_queue_Heads * ), void ( *enqueue )( Thread_queue_Heads *, Thread_Control * ) ) { Thread_queue_Heads *heads = queue->heads; Thread_queue_Heads *spare_heads = the_thread->Wait.spare_heads; the_thread->Wait.spare_heads = NULL; if ( heads == NULL ) { _Assert( spare_heads != NULL ); _Assert( _Chain_Is_empty( &spare_heads->Free_chain ) ); heads = spare_heads; queue->heads = heads; ( *initialize )( heads ); } _Chain_Prepend_unprotected( &heads->Free_chain, &spare_heads->Free_node ); ( *enqueue )( heads, the_thread ); } static void _Thread_queue_Queue_extract( Thread_queue_Queue *queue, Thread_Control *the_thread, void ( *extract )( Thread_queue_Heads *, Thread_Control * ) ) { Thread_queue_Heads *heads = queue->heads; _Assert( heads != NULL ); the_thread->Wait.spare_heads = RTEMS_CONTAINER_OF( _Chain_Get_first_unprotected( &heads->Free_chain ), Thread_queue_Heads, Free_node ); if ( _Chain_Is_empty( &heads->Free_chain ) ) { queue->heads = NULL; } ( *extract )( heads, the_thread ); } static void _Thread_queue_FIFO_do_initialize( Thread_queue_Heads *heads ) { _Chain_Initialize_empty( &heads->Heads.Fifo ); } static void _Thread_queue_FIFO_do_enqueue( Thread_queue_Heads *heads, Thread_Control *the_thread ) { _Chain_Append_unprotected( &heads->Heads.Fifo, &the_thread->Wait.Node.Chain ); } static void _Thread_queue_FIFO_do_extract( Thread_queue_Heads *heads, Thread_Control *the_thread ) { _Chain_Extract_unprotected( &the_thread->Wait.Node.Chain ); } static void _Thread_queue_FIFO_enqueue( Thread_queue_Queue *queue, Thread_Control *the_thread ) { _Thread_queue_Queue_enqueue( queue, the_thread, _Thread_queue_FIFO_do_initialize, _Thread_queue_FIFO_do_enqueue ); } static void _Thread_queue_FIFO_extract( Thread_queue_Queue *queue, Thread_Control *the_thread ) { _Thread_queue_Queue_extract( queue, the_thread, _Thread_queue_FIFO_do_extract ); } static Thread_Control *_Thread_queue_FIFO_first( Thread_queue_Heads *heads ) { Chain_Control *fifo = &heads->Heads.Fifo; Chain_Node *first; _Assert( !_Chain_Is_empty( fifo ) ); first = _Chain_First( fifo ); return THREAD_CHAIN_NODE_TO_THREAD( first ); } static Thread_queue_Priority_queue *_Thread_queue_Priority_queue( Thread_queue_Heads *heads, const Thread_Control *the_thread ) { #if defined(RTEMS_SMP) return &heads->Priority[ _Scheduler_Get_index( _Scheduler_Get_own( the_thread ) ) ]; #else (void) the_thread; return &heads->Heads.Priority; #endif } static void _Thread_queue_Priority_priority_change( Thread_Control *the_thread, Priority_Control new_priority, Thread_queue_Queue *queue ) { Thread_queue_Heads *heads = queue->heads; Thread_queue_Priority_queue *priority_queue; _Assert( heads != NULL ); priority_queue = _Thread_queue_Priority_queue( heads, the_thread ); _RBTree_Extract( &priority_queue->Queue, &the_thread->Wait.Node.RBTree ); _RBTree_Insert( &priority_queue->Queue, &the_thread->Wait.Node.RBTree, _Thread_queue_Compare_priority, false ); } static void _Thread_queue_Priority_do_initialize( Thread_queue_Heads *heads ) { #if defined(RTEMS_SMP) _Chain_Initialize_empty( &heads->Heads.Fifo ); #else _RBTree_Initialize_empty( &heads->Heads.Priority.Queue ); #endif } static void _Thread_queue_Priority_do_enqueue( Thread_queue_Heads *heads, Thread_Control *the_thread ) { Thread_queue_Priority_queue *priority_queue = _Thread_queue_Priority_queue( heads, the_thread ); #if defined(RTEMS_SMP) if ( _RBTree_Is_empty( &priority_queue->Queue ) ) { _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node ); } #endif _RBTree_Insert( &priority_queue->Queue, &the_thread->Wait.Node.RBTree, _Thread_queue_Compare_priority, false ); } static void _Thread_queue_Priority_do_extract( Thread_queue_Heads *heads, Thread_Control *the_thread ) { Thread_queue_Priority_queue *priority_queue = _Thread_queue_Priority_queue( heads, the_thread ); _RBTree_Extract( &priority_queue->Queue, &the_thread->Wait.Node.RBTree ); #if defined(RTEMS_SMP) _Chain_Extract_unprotected( &priority_queue->Node ); if ( !_RBTree_Is_empty( &priority_queue->Queue ) ) { _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node ); } #endif } static void _Thread_queue_Priority_enqueue( Thread_queue_Queue *queue, Thread_Control *the_thread ) { _Thread_queue_Queue_enqueue( queue, the_thread, _Thread_queue_Priority_do_initialize, _Thread_queue_Priority_do_enqueue ); } static void _Thread_queue_Priority_extract( Thread_queue_Queue *queue, Thread_Control *the_thread ) { _Thread_queue_Queue_extract( queue, the_thread, _Thread_queue_Priority_do_extract ); } static Thread_Control *_Thread_queue_Priority_first( Thread_queue_Heads *heads ) { Thread_queue_Priority_queue *priority_queue; RBTree_Node *first; #if defined(RTEMS_SMP) _Assert( !_Chain_Is_empty( &heads->Heads.Fifo ) ); priority_queue = (Thread_queue_Priority_queue *) _Chain_First( &heads->Heads.Fifo ); #else priority_queue = &heads->Heads.Priority; #endif _Assert( !_RBTree_Is_empty( &priority_queue->Queue ) ); first = _RBTree_Minimum( &priority_queue->Queue ); return THREAD_RBTREE_NODE_TO_THREAD( first ); } #if defined(RTEMS_SMP) void _Thread_queue_Boost_priority( Thread_queue_Queue *queue, Thread_Control *the_thread ) { Thread_queue_Heads *heads = queue->heads; if ( heads != NULL && ( !_Chain_Has_only_one_node( &heads->Heads.Fifo ) || _RBTree_Is_empty( &_Thread_queue_Priority_queue( heads, the_thread )->Queue ) ) ) { _Thread_Raise_priority( the_thread, PRIORITY_PSEUDO_ISR ); } } #endif const Thread_queue_Operations _Thread_queue_Operations_default = { .priority_change = _Thread_queue_Do_nothing_priority_change, .extract = _Thread_queue_Do_nothing_extract /* * The default operations are only used in _Thread_Change_priority() and * _Thread_Timeout() and don't have a thread queue associated with them, so * the enqueue and first operations are superfluous. */ }; const Thread_queue_Operations _Thread_queue_Operations_FIFO = { .priority_change = _Thread_queue_Do_nothing_priority_change, .enqueue = _Thread_queue_FIFO_enqueue, .extract = _Thread_queue_FIFO_extract, .first = _Thread_queue_FIFO_first }; const Thread_queue_Operations _Thread_queue_Operations_priority = { .priority_change = _Thread_queue_Priority_priority_change, .enqueue = _Thread_queue_Priority_enqueue, .extract = _Thread_queue_Priority_extract, .first = _Thread_queue_Priority_first };