From 15b5678dcd72a11909a54b63ddc8e57869d63244 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 1 Aug 2016 11:03:16 +0200 Subject: score: Move thread wait node to scheduler node Update #2556. --- cpukit/posix/src/killinfo.c | 5 +- cpukit/score/include/rtems/score/schedulerimpl.h | 17 +- cpukit/score/include/rtems/score/schedulernode.h | 40 ++++- cpukit/score/include/rtems/score/thread.h | 201 +++++++++++------------ cpukit/score/include/rtems/score/threadimpl.h | 6 - cpukit/score/src/thread.c | 1 + cpukit/score/src/threadmp.c | 11 ++ cpukit/score/src/threadqflush.c | 10 +- cpukit/score/src/threadqops.c | 73 +++++--- 9 files changed, 220 insertions(+), 144 deletions(-) diff --git a/cpukit/posix/src/killinfo.c b/cpukit/posix/src/killinfo.c index b7f0354a0b..2e7bacbb78 100644 --- a/cpukit/posix/src/killinfo.c +++ b/cpukit/posix/src/killinfo.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -150,8 +151,10 @@ int _POSIX_signals_Send( for ( the_node = _Chain_First( the_chain ); !_Chain_Is_tail( the_chain, the_node ) ; the_node = the_node->next ) { + Scheduler_Node *scheduler_node; - the_thread = THREAD_CHAIN_NODE_TO_THREAD( the_node ); + scheduler_node = SCHEDULER_NODE_OF_WAIT_CHAIN_NODE( the_node ); + the_thread = _Scheduler_Node_get_owner( scheduler_node ); api = the_thread->API_Extensions[ THREAD_API_POSIX ]; #if defined(DEBUG_SIGNAL_PROCESSING) diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h index 1c5a697619..0832360c91 100644 --- a/cpukit/score/include/rtems/score/schedulerimpl.h +++ b/cpukit/score/include/rtems/score/schedulerimpl.h @@ -785,13 +785,14 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Node_do_initialize( Priority_Control priority ) { + node->owner = the_thread; + node->Priority.value = priority; node->Priority.prepend_it = false; #if defined(RTEMS_SMP) node->user = the_thread; node->help_state = SCHEDULER_HELP_YOURSELF; - node->owner = the_thread; node->idle = NULL; node->accepts_help = the_thread; _SMP_sequence_lock_Initialize( &node->Priority.Lock ); @@ -800,6 +801,13 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Node_do_initialize( #endif } +RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_owner( + const Scheduler_Node *node +) +{ + return node->owner; +} + RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Node_get_priority( Scheduler_Node *node, bool *prepend_it_p @@ -885,13 +893,6 @@ typedef void ( *Scheduler_Release_idle_thread )( Thread_Control *idle ); -RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_owner( - const Scheduler_Node *node -) -{ - return node->owner; -} - RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_idle( const Scheduler_Node *node ) diff --git a/cpukit/score/include/rtems/score/schedulernode.h b/cpukit/score/include/rtems/score/schedulernode.h index 6153624743..63d86e64ff 100644 --- a/cpukit/score/include/rtems/score/schedulernode.h +++ b/cpukit/score/include/rtems/score/schedulernode.h @@ -122,11 +122,6 @@ typedef struct { */ Scheduler_Help_state help_state; - /** - * @brief The thread owning this node. - */ - struct _Thread_Control *owner; - /** * @brief The idle thread claimed by this node in case the help state is * SCHEDULER_HELP_ACTIVE_OWNER. @@ -145,6 +140,35 @@ typedef struct { struct _Thread_Control *accepts_help; #endif + /** + * @brief Thread wait support block. + */ + struct { + /** + * @brief Node for thread queues. + * + * Each scheduler node can be enqueued on a thread queue on behalf of the + * thread owning the scheduler node. The scheduler node reflects the + * priority of the thread within the corresponding scheduler instance. + */ + union { + /** + * @brief A node for chains. + */ + Chain_Node Chain; + + /** + * @brief A node for red-black trees. + */ + RBTree_Node RBTree; + } Node; + } Wait; + + /** + * @brief The thread owning this node. + */ + struct _Thread_Control *owner; + /** * @brief The thread priority information used by the scheduler. * @@ -181,6 +205,12 @@ typedef struct { } Priority; } Scheduler_Node; +#define SCHEDULER_NODE_OF_WAIT_CHAIN_NODE( node ) \ + RTEMS_CONTAINER_OF( node, Scheduler_Node, Wait.Node.Chain ) + +#define SCHEDULER_NODE_OF_WAIT_RBTREE_NODE( node ) \ + RTEMS_CONTAINER_OF( node, Scheduler_Node, Wait.Node.RBTree ) + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index 2df0269491..2cd229f76f 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -210,6 +210,88 @@ typedef struct { void *tls_area; } Thread_Start_information; +#if defined(RTEMS_SMP) +/** + * @brief The thread state with respect to the scheduler. + */ +typedef enum { + /** + * @brief This thread is blocked with respect to the scheduler. + * + * This thread uses no scheduler nodes. + */ + THREAD_SCHEDULER_BLOCKED, + + /** + * @brief This thread is scheduled with respect to the scheduler. + * + * This thread executes using one of its scheduler nodes. This could be its + * own scheduler node or in case it owns resources taking part in the + * scheduler helping protocol a scheduler node of another thread. + */ + THREAD_SCHEDULER_SCHEDULED, + + /** + * @brief This thread is ready with respect to the scheduler. + * + * None of the scheduler nodes of this thread is scheduled. + */ + THREAD_SCHEDULER_READY +} Thread_Scheduler_state; +#endif + +/** + * @brief Thread scheduler control. + */ +typedef struct { +#if defined(RTEMS_SMP) + /** + * @brief The current scheduler state of this thread. + */ + Thread_Scheduler_state state; + + /** + * @brief The own scheduler control of this thread. + * + * This field is constant after initialization. + */ + const struct Scheduler_Control *own_control; + + /** + * @brief The scheduler control of this thread. + * + * The scheduler helping protocol may change this field. + */ + const struct Scheduler_Control *control; + + /** + * @brief The own scheduler node of this thread. + * + * This field is constant after initialization. It is used by change + * priority and ask for help operations. + */ + Scheduler_Node *own_node; +#endif + + /** + * @brief The scheduler node of this thread. + * + * On uni-processor configurations this field is constant after + * initialization. + * + * On SMP configurations the scheduler helping protocol may change this + * field. + */ + Scheduler_Node *node; + +#if defined(RTEMS_SMP) + /** + * @brief The processor assigned by the current scheduler. + */ + struct Per_CPU_Control *cpu; +#endif +} Thread_Scheduler_control; + /** * @brief Union type to hold a pointer to an immutable or a mutable object. * @@ -248,21 +330,6 @@ typedef unsigned int Thread_Wait_flags; * blocked and to return information to it. */ typedef struct { - /** - * @brief Node for thread queues. - */ - union { - /** - * @brief A node for chains. - */ - Chain_Node Chain; - - /** - * @brief A node for red-black trees. - */ - RBTree_Node RBTree; - } Node; - #if defined(RTEMS_MULTIPROCESSING) /* * @brief This field is the identifier of the remote object this thread is @@ -424,6 +491,11 @@ typedef struct { /** This field is the number of mutexes currently held by this proxy. */ uint32_t resource_count; + /** + * @brief Scheduler related control. + */ + Thread_Scheduler_control Scheduler; + /** This field is the blocking information for this proxy. */ Thread_Wait_information Wait; /** This field is the Watchdog used to manage proxy delays and timeouts. */ @@ -443,6 +515,12 @@ typedef struct { */ RBTree_Node Active; + /** + * @brief The scheduler node providing the thread wait nodes used to enqueue + * this thread proxy on a thread queue. + */ + Scheduler_Node Scheduler_node; + /** * @brief Provide thread queue heads for this thread proxy. * @@ -592,88 +670,6 @@ typedef struct { #endif } Thread_Life_control; -#if defined(RTEMS_SMP) -/** - * @brief The thread state with respect to the scheduler. - */ -typedef enum { - /** - * @brief This thread is blocked with respect to the scheduler. - * - * This thread uses no scheduler nodes. - */ - THREAD_SCHEDULER_BLOCKED, - - /** - * @brief This thread is scheduled with respect to the scheduler. - * - * This thread executes using one of its scheduler nodes. This could be its - * own scheduler node or in case it owns resources taking part in the - * scheduler helping protocol a scheduler node of another thread. - */ - THREAD_SCHEDULER_SCHEDULED, - - /** - * @brief This thread is ready with respect to the scheduler. - * - * None of the scheduler nodes of this thread is scheduled. - */ - THREAD_SCHEDULER_READY -} Thread_Scheduler_state; -#endif - -/** - * @brief Thread scheduler control. - */ -typedef struct { -#if defined(RTEMS_SMP) - /** - * @brief The current scheduler state of this thread. - */ - Thread_Scheduler_state state; - - /** - * @brief The own scheduler control of this thread. - * - * This field is constant after initialization. - */ - const struct Scheduler_Control *own_control; - - /** - * @brief The scheduler control of this thread. - * - * The scheduler helping protocol may change this field. - */ - const struct Scheduler_Control *control; - - /** - * @brief The own scheduler node of this thread. - * - * This field is constant after initialization. It is used by change - * priority and ask for help operations. - */ - Scheduler_Node *own_node; -#endif - - /** - * @brief The scheduler node of this thread. - * - * On uni-processor configurations this field is constant after - * initialization. - * - * On SMP configurations the scheduler helping protocol may change this - * field. - */ - Scheduler_Node *node; - -#if defined(RTEMS_SMP) - /** - * @brief The processor assigned by the current scheduler. - */ - struct Per_CPU_Control *cpu; -#endif -} Thread_Scheduler_control; - typedef struct { uint32_t flags; void * control; @@ -740,6 +736,12 @@ struct _Thread_Control { /** This field is the number of mutexes currently held by this thread. */ uint32_t resource_count; + + /** + * @brief Scheduler related control. + */ + Thread_Scheduler_control Scheduler; + /** This field is the blocking information for this thread. */ Thread_Wait_information Wait; /** This field is the Watchdog used to manage thread delays and timeouts. */ @@ -778,11 +780,6 @@ struct _Thread_Control { /** This field is true if the thread uses the floating point unit. */ bool is_fp; - /** - * @brief Scheduler related control. - */ - Thread_Scheduler_control Scheduler; - #if __RTEMS_ADA__ /** This field is the GNAT self context pointer. */ void *rtems_ada_self; diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index 03c1ed8088..e51c009a95 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -77,12 +77,6 @@ extern Thread_Information _Thread_Internal_information; extern Thread_Control *_Thread_Allocated_fp; #endif -#define THREAD_CHAIN_NODE_TO_THREAD( node ) \ - RTEMS_CONTAINER_OF( node, Thread_Control, Wait.Node.Chain ) - -#define THREAD_RBTREE_NODE_TO_THREAD( node ) \ - RTEMS_CONTAINER_OF( node, Thread_Control, Wait.Node.RBTree ) - #if defined(RTEMS_SMP) #define THREAD_RESOURCE_NODE_TO_THREAD( node ) \ RTEMS_CONTAINER_OF( node, Thread_Control, Resource_node ) diff --git a/cpukit/score/src/thread.c b/cpukit/score/src/thread.c index 8028540e10..c569ae5bab 100644 --- a/cpukit/score/src/thread.c +++ b/cpukit/score/src/thread.c @@ -36,6 +36,7 @@ THREAD_OFFSET_ASSERT( current_priority ); THREAD_OFFSET_ASSERT( real_priority ); THREAD_OFFSET_ASSERT( priority_restore_hint ); THREAD_OFFSET_ASSERT( resource_count ); +THREAD_OFFSET_ASSERT( Scheduler ); THREAD_OFFSET_ASSERT( Wait ); THREAD_OFFSET_ASSERT( Timer ); #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/score/src/threadmp.c b/cpukit/score/src/threadmp.c index f5253560a6..cbb6c1c6b1 100644 --- a/cpukit/score/src/threadmp.c +++ b/cpukit/score/src/threadmp.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -74,6 +75,16 @@ void _Thread_MP_Handler_initialization ( _Thread_Timer_initialize( &proxy->Timer, _Per_CPU_Get_by_index( 0 ) ); _RBTree_Initialize_node( &proxy->Active ); +#if defined(RTEMS_SMP) + proxy->Scheduler.own_node = &proxy->Scheduler_node; +#endif + proxy->Scheduler.node = &proxy->Scheduler_node; + _Scheduler_Node_do_initialize( + &proxy->Scheduler_node, + (Thread_Control *) proxy, + 0 + ); + proxy->Wait.spare_heads = &proxy->Thread_queue_heads[ 0 ]; _Thread_queue_Heads_initialize( proxy->Wait.spare_heads ); } diff --git a/cpukit/score/src/threadqflush.c b/cpukit/score/src/threadqflush.c index 835858dd5a..fb1323073d 100644 --- a/cpukit/score/src/threadqflush.c +++ b/cpukit/score/src/threadqflush.c @@ -19,6 +19,7 @@ #endif #include +#include #include Thread_Control *_Thread_queue_Flush_default_filter( @@ -96,7 +97,10 @@ size_t _Thread_queue_Flush_critical( queue_context ); if ( do_unblock ) { - _Chain_Append_unprotected( &unblock, &first->Wait.Node.Chain ); + Scheduler_Node *scheduler_node; + + scheduler_node = _Scheduler_Thread_get_own_node( first ); + _Chain_Append_unprotected( &unblock, &scheduler_node->Wait.Node.Chain ); } ++flushed; @@ -114,11 +118,13 @@ size_t _Thread_queue_Flush_critical( _Thread_queue_Queue_release( queue, &queue_context->Lock_context.Lock_context ); do { + Scheduler_Node *scheduler_node; Thread_Control *the_thread; Chain_Node *next; next = _Chain_Next( node ); - the_thread = THREAD_CHAIN_NODE_TO_THREAD( node ); + scheduler_node = SCHEDULER_NODE_OF_WAIT_CHAIN_NODE( node ); + the_thread = _Scheduler_Node_get_owner( scheduler_node ); _Thread_Remove_timer_and_unblock( the_thread, queue ); node = next; diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c index 2752dc46aa..4177151fae 100644 --- a/cpukit/score/src/threadqops.c +++ b/cpukit/score/src/threadqops.c @@ -99,8 +99,15 @@ static void _Thread_queue_FIFO_do_initialize( Thread_Control *the_thread ) { - _Chain_Initialize_node( &the_thread->Wait.Node.Chain ); - _Chain_Initialize_one( &heads->Heads.Fifo, &the_thread->Wait.Node.Chain ); + Scheduler_Node *scheduler_node; + + scheduler_node = _Scheduler_Thread_get_own_node( the_thread ); + + _Chain_Initialize_node( &scheduler_node->Wait.Node.Chain ); + _Chain_Initialize_one( + &heads->Heads.Fifo, + &scheduler_node->Wait.Node.Chain + ); } static void _Thread_queue_FIFO_do_enqueue( @@ -108,10 +115,14 @@ static void _Thread_queue_FIFO_do_enqueue( Thread_Control *the_thread ) { - _Chain_Initialize_node( &the_thread->Wait.Node.Chain ); + Scheduler_Node *scheduler_node; + + scheduler_node = _Scheduler_Thread_get_own_node( the_thread ); + + _Chain_Initialize_node( &scheduler_node->Wait.Node.Chain ); _Chain_Append_unprotected( &heads->Heads.Fifo, - &the_thread->Wait.Node.Chain + &scheduler_node->Wait.Node.Chain ); } @@ -120,7 +131,10 @@ static void _Thread_queue_FIFO_do_extract( Thread_Control *the_thread ) { - _Chain_Extract_unprotected( &the_thread->Wait.Node.Chain ); + Scheduler_Node *scheduler_node; + + scheduler_node = _Scheduler_Thread_get_own_node( the_thread ); + _Chain_Extract_unprotected( &scheduler_node->Wait.Node.Chain ); } static void _Thread_queue_FIFO_enqueue( @@ -156,13 +170,16 @@ static Thread_Control *_Thread_queue_FIFO_first( Thread_queue_Heads *heads ) { - Chain_Control *fifo = &heads->Heads.Fifo; - Chain_Node *first; + Chain_Control *fifo; + Chain_Node *first; + Scheduler_Node *scheduler_node; + fifo = &heads->Heads.Fifo; _Assert( !_Chain_Is_empty( fifo ) ); first = _Chain_First( fifo ); + scheduler_node = SCHEDULER_NODE_OF_WAIT_CHAIN_NODE( first ); - return THREAD_CHAIN_NODE_TO_THREAD( first ); + return _Scheduler_Node_get_owner( scheduler_node ); } static Thread_Control *_Thread_queue_FIFO_surrender( @@ -206,10 +223,12 @@ static bool _Thread_queue_Priority_less( ) { const Priority_Control *the_left; + const Scheduler_Node *scheduler_node; const Thread_Control *the_right; the_left = left; - the_right = THREAD_RBTREE_NODE_TO_THREAD( right ); + scheduler_node = SCHEDULER_NODE_OF_WAIT_RBTREE_NODE( right ); + the_right = _Scheduler_Node_get_owner( scheduler_node ); return *the_left < the_right->current_priority; } @@ -220,20 +239,23 @@ static void _Thread_queue_Priority_priority_change( Priority_Control new_priority ) { - Thread_queue_Heads *heads = queue->heads; + Thread_queue_Heads *heads; Thread_queue_Priority_queue *priority_queue; + Scheduler_Node *scheduler_node; + heads = queue->heads; _Assert( heads != NULL ); priority_queue = _Thread_queue_Priority_queue( heads, the_thread ); + scheduler_node = _Scheduler_Thread_get_own_node( the_thread ); _RBTree_Extract( &priority_queue->Queue, - &the_thread->Wait.Node.RBTree + &scheduler_node->Wait.Node.RBTree ); _RBTree_Insert_inline( &priority_queue->Queue, - &the_thread->Wait.Node.RBTree, + &scheduler_node->Wait.Node.RBTree, &new_priority, _Thread_queue_Priority_less ); @@ -245,6 +267,7 @@ static void _Thread_queue_Priority_do_initialize( ) { Thread_queue_Priority_queue *priority_queue; + Scheduler_Node *scheduler_node; priority_queue = _Thread_queue_Priority_queue( heads, the_thread ); @@ -252,10 +275,12 @@ static void _Thread_queue_Priority_do_initialize( _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node ); #endif - _RBTree_Initialize_node( &the_thread->Wait.Node.RBTree ); + scheduler_node = _Scheduler_Thread_get_own_node( the_thread ); + + _RBTree_Initialize_node( &scheduler_node->Wait.Node.RBTree ); _RBTree_Initialize_one( &priority_queue->Queue, - &the_thread->Wait.Node.RBTree + &scheduler_node->Wait.Node.RBTree ); } @@ -265,6 +290,7 @@ static void _Thread_queue_Priority_do_enqueue( ) { Thread_queue_Priority_queue *priority_queue; + Scheduler_Node *scheduler_node; Priority_Control current_priority; priority_queue = _Thread_queue_Priority_queue( heads, the_thread ); @@ -275,11 +301,13 @@ static void _Thread_queue_Priority_do_enqueue( } #endif + scheduler_node = _Scheduler_Thread_get_own_node( the_thread ); current_priority = the_thread->current_priority; - _RBTree_Initialize_node( &the_thread->Wait.Node.RBTree ); + + _RBTree_Initialize_node( &scheduler_node->Wait.Node.RBTree ); _RBTree_Insert_inline( &priority_queue->Queue, - &the_thread->Wait.Node.RBTree, + &scheduler_node->Wait.Node.RBTree, ¤t_priority, _Thread_queue_Priority_less ); @@ -290,12 +318,15 @@ static void _Thread_queue_Priority_do_extract( Thread_Control *the_thread ) { - Thread_queue_Priority_queue *priority_queue = - _Thread_queue_Priority_queue( heads, the_thread ); + Thread_queue_Priority_queue *priority_queue; + Scheduler_Node *scheduler_node; + + priority_queue = _Thread_queue_Priority_queue( heads, the_thread ); + scheduler_node = _Scheduler_Thread_get_own_node( the_thread ); _RBTree_Extract( &priority_queue->Queue, - &the_thread->Wait.Node.RBTree + &scheduler_node->Wait.Node.RBTree ); #if defined(RTEMS_SMP) @@ -342,6 +373,7 @@ static Thread_Control *_Thread_queue_Priority_first( { Thread_queue_Priority_queue *priority_queue; RBTree_Node *first; + Scheduler_Node *scheduler_node; #if defined(RTEMS_SMP) _Assert( !_Chain_Is_empty( &heads->Heads.Fifo ) ); @@ -353,8 +385,9 @@ static Thread_Control *_Thread_queue_Priority_first( _Assert( !_RBTree_Is_empty( &priority_queue->Queue ) ); first = _RBTree_Minimum( &priority_queue->Queue ); + scheduler_node = SCHEDULER_NODE_OF_WAIT_RBTREE_NODE( first ); - return THREAD_RBTREE_NODE_TO_THREAD( first ); + return _Scheduler_Node_get_owner( scheduler_node ); } static Thread_Control *_Thread_queue_Priority_surrender( -- cgit v1.2.3