diff options
Diffstat (limited to 'cpukit/score/src/threadinitialize.c')
-rw-r--r-- | cpukit/score/src/threadinitialize.c | 229 |
1 files changed, 141 insertions, 88 deletions
diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c index 9c1b809c3a..e1a6c7de93 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -11,9 +13,26 @@ * 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H @@ -96,6 +115,116 @@ void _Thread_Free( _Objects_Free( &information->Objects, &the_thread->Object ); } +static void _Thread_Initialize_scheduler_and_wait_nodes( + Thread_Control *the_thread, + const Thread_Configuration *config +) +{ + Scheduler_Node *home_scheduler_node; +#if defined(RTEMS_SMP) + Scheduler_Node *scheduler_node; + const Scheduler_Control *scheduler; + size_t scheduler_index; +#endif + +#if defined(RTEMS_SMP) + home_scheduler_node = NULL; + scheduler_node = the_thread->Scheduler.nodes; + scheduler = &_Scheduler_Table[ 0 ]; + scheduler_index = 0; + + /* + * In SMP configurations, the thread has exactly one scheduler node for each + * configured scheduler. Initialize the scheduler nodes of each scheduler. + * The application configuration ensures that we have at least one scheduler + * configured. + */ + + _Assert ( _Scheduler_Count >= 1 ); + + do { + Priority_Control priority; + + if ( scheduler == config->scheduler ) { + priority = config->priority; + home_scheduler_node = scheduler_node; + } else { + /* + * Use the idle thread priority for the non-home scheduler instances by + * default. + */ + priority = _Scheduler_Map_priority( + scheduler, + scheduler->maximum_priority + ); + } + + _Scheduler_Node_initialize( + scheduler, + scheduler_node, + the_thread, + priority + ); + + /* + * Since the size of a scheduler node depends on the application + * configuration, the _Scheduler_Node_size constant is used to get the next + * scheduler node. Using sizeof( Scheduler_Node ) would be wrong. + */ + scheduler_node = (Scheduler_Node *) + ( (uintptr_t) scheduler_node + _Scheduler_Node_size ); + ++scheduler; + ++scheduler_index; + } while ( scheduler_index < _Scheduler_Count ); + + /* + * The thread is initialized to use exactly one scheduler node which is + * provided by its home scheduler. + */ + _Assert( home_scheduler_node != NULL ); + _Chain_Initialize_one( + &the_thread->Scheduler.Wait_nodes, + &home_scheduler_node->Thread.Wait_node + ); + _Chain_Initialize_one( + &the_thread->Scheduler.Scheduler_nodes, + &home_scheduler_node->Thread.Scheduler_node.Chain + ); +#else + /* + * In uniprocessor configurations, the thread has exactly one scheduler node. + */ + home_scheduler_node = _Thread_Scheduler_get_home_node( the_thread ); + _Scheduler_Node_initialize( + config->scheduler, + home_scheduler_node, + the_thread, + config->priority + ); +#endif + + /* + * The current priority of the thread is initialized to exactly the real + * priority of the thread. During the lifetime of the thread, it may gain + * more priority nodes, for example through locking protocols such as + * priority inheritance or priority ceiling. + */ + _Priority_Node_initialize( &the_thread->Real_priority, config->priority ); + _Priority_Initialize_one( + &home_scheduler_node->Wait.Priority, + &the_thread->Real_priority + ); + +#if defined(RTEMS_SMP) + RTEMS_STATIC_ASSERT( THREAD_SCHEDULER_BLOCKED == 0, Scheduler_state ); + the_thread->Scheduler.home_scheduler = config->scheduler; + _ISR_lock_Initialize( &the_thread->Scheduler.Lock, "Thread Scheduler" ); + _ISR_lock_Initialize( &the_thread->Wait.Lock.Default, "Thread Wait Default" ); + _Thread_queue_Gate_open( &the_thread->Wait.Lock.Tranquilizer ); + _RBTree_Initialize_node( &the_thread->Wait.Link.Registry_node ); +#endif +} + static bool _Thread_Try_initialize( Thread_Information *information, Thread_Control *the_thread, @@ -107,12 +236,6 @@ static bool _Thread_Try_initialize( char *stack_begin; char *stack_end; uintptr_t stack_align; - Scheduler_Node *scheduler_node; -#if defined(RTEMS_SMP) - Scheduler_Node *scheduler_node_for_index; - const Scheduler_Control *scheduler_for_index; - size_t scheduler_index; -#endif Per_CPU_Control *cpu = _Per_CPU_Get_by_index( 0 ); memset( @@ -147,12 +270,8 @@ static bool _Thread_Try_initialize( /* Allocate thread-local storage (TLS) area in stack area */ if ( tls_size > 0 ) { - uintptr_t tls_align; - stack_end -= tls_size; - tls_align = (uintptr_t) _TLS_Alignment; - the_thread->Start.tls_area = (void *) - ( ( (uintptr_t) stack_end + tls_align - 1 ) & ~( tls_align - 1 ) ); + the_thread->Start.tls_area = stack_end; } _Stack_Initialize( @@ -173,87 +292,21 @@ static bool _Thread_Try_initialize( * General initialization */ - the_thread->is_fp = config->is_fp; - the_thread->cpu_time_budget = config->cpu_time_budget; - the_thread->Start.isr_level = config->isr_level; - the_thread->Start.is_preemptible = config->is_preemptible; - the_thread->Start.budget_algorithm = config->budget_algorithm; - the_thread->Start.budget_callout = config->budget_callout; - the_thread->Start.stack_free = config->stack_free; + the_thread->is_fp = config->is_fp; + the_thread->Start.isr_level = config->isr_level; + the_thread->Start.is_preemptible = config->is_preemptible; + the_thread->Start.cpu_budget_operations = config->cpu_budget_operations; + the_thread->Start.stack_free = config->stack_free; + the_thread->Join_queue.Queue.owner = the_thread; _Thread_Timer_initialize( &the_thread->Timer, cpu ); + _Thread_Initialize_scheduler_and_wait_nodes( the_thread, config ); #if defined(RTEMS_SMP) - scheduler_node = NULL; - scheduler_node_for_index = the_thread->Scheduler.nodes; - scheduler_for_index = &_Scheduler_Table[ 0 ]; - scheduler_index = 0; - - while ( scheduler_index < _Scheduler_Count ) { - Priority_Control priority_for_index; - - if ( scheduler_for_index == config->scheduler ) { - priority_for_index = config->priority; - scheduler_node = scheduler_node_for_index; - } else { - /* - * Use the idle thread priority for the non-home scheduler instances by - * default. - */ - priority_for_index = _Scheduler_Map_priority( - scheduler_for_index, - scheduler_for_index->maximum_priority - ); - } - - _Scheduler_Node_initialize( - scheduler_for_index, - scheduler_node_for_index, - the_thread, - priority_for_index - ); - scheduler_node_for_index = (Scheduler_Node *) - ( (uintptr_t) scheduler_node_for_index + _Scheduler_Node_size ); - ++scheduler_for_index; - ++scheduler_index; - } - - _Assert( scheduler_node != NULL ); - _Chain_Initialize_one( - &the_thread->Scheduler.Wait_nodes, - &scheduler_node->Thread.Wait_node - ); - _Chain_Initialize_one( - &the_thread->Scheduler.Scheduler_nodes, - &scheduler_node->Thread.Scheduler_node.Chain - ); -#else - scheduler_node = _Thread_Scheduler_get_home_node( the_thread ); - _Scheduler_Node_initialize( - config->scheduler, - scheduler_node, - the_thread, - config->priority - ); -#endif - - _Priority_Node_initialize( &the_thread->Real_priority, config->priority ); - _Priority_Initialize_one( - &scheduler_node->Wait.Priority, - &the_thread->Real_priority - ); - -#if defined(RTEMS_SMP) - RTEMS_STATIC_ASSERT( THREAD_SCHEDULER_BLOCKED == 0, Scheduler_state ); - the_thread->Scheduler.home_scheduler = config->scheduler; - _ISR_lock_Initialize( &the_thread->Scheduler.Lock, "Thread Scheduler" ); _Processor_mask_Assign( &the_thread->Scheduler.Affinity, _SMP_Get_online_processors() ); - _ISR_lock_Initialize( &the_thread->Wait.Lock.Default, "Thread Wait Default" ); - _Thread_queue_Gate_open( &the_thread->Wait.Lock.Tranquilizer ); - _RBTree_Initialize_node( &the_thread->Wait.Link.Registry_node ); _SMP_lock_Stats_initialize( &the_thread->Potpourri_stats, "Thread Potpourri" ); _SMP_lock_Stats_initialize( &the_thread->Join_queue.Lock_stats, "Thread State" ); #endif @@ -265,7 +318,7 @@ static bool _Thread_Try_initialize( the_thread->Wait.operations = &_Thread_queue_Operations_default; the_thread->Start.initial_priority = config->priority; - RTEMS_STATIC_ASSERT( THREAD_WAIT_FLAGS_INITIAL == 0, Wait_flags ); + RTEMS_STATIC_ASSERT( THREAD_WAIT_STATE_READY == 0, Wait_flags ); /* POSIX Keys */ _RBTree_Initialize_empty( &the_thread->Keys.Key_value_pairs ); |