source: rtems/cpukit/score/src/threadinitialize.c @ c2f24048

Last change on this file since c2f24048 was c2f24048, checked in by Sebastian Huber <sebastian.huber@…>, on 09/21/21 at 11:23:36

score: Simplify _Thread_Try_initialize()

Move a code block to its own new function
_Thread_Initialize_scheduler_and_wait_nodes(). Add comments.

  • Property mode set to 100644
File size: 10.8 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSScoreThread
5 *
6 * @brief This source file contains the implementation of
7 *   _Thread_Initialize().
8 */
9
10/*
11 *  COPYRIGHT (c) 1989-2014.
12 *  On-Line Applications Research Corporation (OAR).
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19#ifdef HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include <rtems/score/threadimpl.h>
24#include <rtems/score/freechainimpl.h>
25#include <rtems/score/schedulerimpl.h>
26#include <rtems/score/stackimpl.h>
27#include <rtems/score/tls.h>
28#include <rtems/score/userextimpl.h>
29#include <rtems/score/watchdogimpl.h>
30
31void _Thread_Free(
32  Thread_Information *information,
33  Thread_Control     *the_thread
34)
35{
36#if defined(RTEMS_SMP)
37  Scheduler_Node *scheduler_node;
38  size_t          scheduler_index;
39#endif
40
41  _User_extensions_Thread_delete( the_thread );
42  _User_extensions_Destroy_iterators( the_thread );
43  _ISR_lock_Destroy( &the_thread->Keys.Lock );
44
45#if defined(RTEMS_SMP)
46  scheduler_node = the_thread->Scheduler.nodes;
47  scheduler_index = 0;
48
49  while ( scheduler_index < _Scheduler_Count ) {
50    _Scheduler_Node_destroy(
51      &_Scheduler_Table[ scheduler_index ],
52      scheduler_node
53    );
54    scheduler_node = (Scheduler_Node *)
55      ( (uintptr_t) scheduler_node + _Scheduler_Node_size );
56    ++scheduler_index;
57  }
58#else
59  _Scheduler_Node_destroy(
60    _Thread_Scheduler_get_home( the_thread ),
61    _Thread_Scheduler_get_home_node( the_thread )
62  );
63#endif
64
65  _ISR_lock_Destroy( &the_thread->Timer.Lock );
66
67  /*
68   *  The thread might have been FP.  So deal with that.
69   */
70#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
71#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
72  if ( _Thread_Is_allocated_fp( the_thread ) )
73    _Thread_Deallocate_fp();
74#endif
75#endif
76
77  _Freechain_Push(
78    &information->Thread_queue_heads.Free,
79    the_thread->Wait.spare_heads
80  );
81
82  /*
83   *  Free the rest of the memory associated with this task
84   *  and set the associated pointers to NULL for safety.
85   */
86  ( *the_thread->Start.stack_free )( the_thread->Start.Initial_stack.area );
87
88#if defined(RTEMS_SMP)
89  _ISR_lock_Destroy( &the_thread->Scheduler.Lock );
90  _ISR_lock_Destroy( &the_thread->Wait.Lock.Default );
91  _SMP_lock_Stats_destroy( &the_thread->Potpourri_stats );
92#endif
93
94  _Thread_queue_Destroy( &the_thread->Join_queue );
95  _Context_Destroy( the_thread, &the_thread->Registers );
96  _Objects_Free( &information->Objects, &the_thread->Object );
97}
98
99static void _Thread_Initialize_scheduler_and_wait_nodes(
100  Thread_Control             *the_thread,
101  const Thread_Configuration *config
102)
103{
104  Scheduler_Node          *scheduler_node;
105#if defined(RTEMS_SMP)
106  Scheduler_Node          *scheduler_node_for_index;
107  const Scheduler_Control *scheduler_for_index;
108  size_t                   scheduler_index;
109#endif
110
111#if defined(RTEMS_SMP)
112  scheduler_node = NULL;
113  scheduler_node_for_index = the_thread->Scheduler.nodes;
114  scheduler_for_index = &_Scheduler_Table[ 0 ];
115  scheduler_index = 0;
116
117  /*
118   * In SMP configurations, the thread has exactly one scheduler node for each
119   * configured scheduler.  Initialize the scheduler nodes of each scheduler.
120   * The application configuration ensures that we have at least one scheduler
121   * configured.
122   */
123  while ( scheduler_index < _Scheduler_Count ) {
124    Priority_Control priority_for_index;
125
126    if ( scheduler_for_index == config->scheduler ) {
127      priority_for_index = config->priority;
128      scheduler_node = scheduler_node_for_index;
129    } else {
130      /*
131       * Use the idle thread priority for the non-home scheduler instances by
132       * default.
133       */
134      priority_for_index = _Scheduler_Map_priority(
135        scheduler_for_index,
136        scheduler_for_index->maximum_priority
137      );
138    }
139
140    _Scheduler_Node_initialize(
141      scheduler_for_index,
142      scheduler_node_for_index,
143      the_thread,
144      priority_for_index
145    );
146
147    /*
148     * Since the size of a scheduler node depends on the application
149     * configuration, the _Scheduler_Node_size constant is used to get the next
150     * scheduler node.  Using sizeof( Scheduler_Node ) would be wrong.
151     */
152    scheduler_node_for_index = (Scheduler_Node *)
153      ( (uintptr_t) scheduler_node_for_index + _Scheduler_Node_size );
154    ++scheduler_for_index;
155    ++scheduler_index;
156  }
157
158  /*
159   * The thread is initialized to use exactly one scheduler node which is
160   * provided by its home scheduler.
161   */
162  _Assert( scheduler_node != NULL );
163  _Chain_Initialize_one(
164    &the_thread->Scheduler.Wait_nodes,
165    &scheduler_node->Thread.Wait_node
166  );
167  _Chain_Initialize_one(
168    &the_thread->Scheduler.Scheduler_nodes,
169    &scheduler_node->Thread.Scheduler_node.Chain
170  );
171#else
172  /*
173   * In uniprocessor configurations, the thread has exactly one scheduler node.
174   */
175  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
176  _Scheduler_Node_initialize(
177    config->scheduler,
178    scheduler_node,
179    the_thread,
180    config->priority
181  );
182#endif
183
184  /*
185   * The current priority of the thread is initialized to exactly the real
186   * priority of the thread.  During the lifetime of the thread, it may gain
187   * more priority nodes, for example through locking protocols such as
188   * priority inheritance or priority ceiling.
189   */
190  _Priority_Node_initialize( &the_thread->Real_priority, config->priority );
191  _Priority_Initialize_one(
192    &scheduler_node->Wait.Priority,
193    &the_thread->Real_priority
194  );
195
196#if defined(RTEMS_SMP)
197  RTEMS_STATIC_ASSERT( THREAD_SCHEDULER_BLOCKED == 0, Scheduler_state );
198  the_thread->Scheduler.home_scheduler = config->scheduler;
199  _ISR_lock_Initialize( &the_thread->Scheduler.Lock, "Thread Scheduler" );
200  _ISR_lock_Initialize( &the_thread->Wait.Lock.Default, "Thread Wait Default" );
201  _Thread_queue_Gate_open( &the_thread->Wait.Lock.Tranquilizer );
202  _RBTree_Initialize_node( &the_thread->Wait.Link.Registry_node );
203#endif
204}
205
206static bool _Thread_Try_initialize(
207  Thread_Information         *information,
208  Thread_Control             *the_thread,
209  const Thread_Configuration *config
210)
211{
212  uintptr_t                tls_size;
213  size_t                   i;
214  char                    *stack_begin;
215  char                    *stack_end;
216  uintptr_t                stack_align;
217  Per_CPU_Control         *cpu = _Per_CPU_Get_by_index( 0 );
218
219  memset(
220    &the_thread->Join_queue,
221    0,
222    information->Objects.object_size - offsetof( Thread_Control, Join_queue )
223  );
224
225  for ( i = 0 ; i < _Thread_Control_add_on_count ; ++i ) {
226    const Thread_Control_add_on *add_on = &_Thread_Control_add_ons[ i ];
227
228    *(void **) ( (char *) the_thread + add_on->destination_offset ) =
229      (char *) the_thread + add_on->source_offset;
230  }
231
232  /* Set up the properly aligned stack area begin and end */
233  stack_begin = config->stack_area;
234  stack_end = stack_begin + config->stack_size;
235  stack_align = CPU_STACK_ALIGNMENT;
236  stack_end = (char *) RTEMS_ALIGN_DOWN( (uintptr_t) stack_end, stack_align );
237
238  /* Allocate floating-point context in stack area */
239#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
240  if ( config->is_fp ) {
241    stack_end -= CONTEXT_FP_SIZE;
242    the_thread->fp_context = (Context_Control_fp *) stack_end;
243    the_thread->Start.fp_context = (Context_Control_fp *) stack_end;
244  }
245#endif
246
247  tls_size = _TLS_Get_allocation_size();
248
249  /* Allocate thread-local storage (TLS) area in stack area */
250  if ( tls_size > 0 ) {
251    uintptr_t tls_align;
252
253    stack_end -= tls_size;
254    tls_align = (uintptr_t) _TLS_Alignment;
255    the_thread->Start.tls_area = (void *)
256      ( ( (uintptr_t) stack_end + tls_align - 1 ) & ~( tls_align - 1 ) );
257  }
258
259  _Stack_Initialize(
260    &the_thread->Start.Initial_stack,
261    stack_begin,
262    stack_end - stack_begin
263  );
264
265  /*
266   *  Get thread queue heads
267   */
268  the_thread->Wait.spare_heads = _Freechain_Pop(
269    &information->Thread_queue_heads.Free
270  );
271  _Thread_queue_Heads_initialize( the_thread->Wait.spare_heads );
272
273  /*
274   *  General initialization
275   */
276
277  the_thread->is_fp                  = config->is_fp;
278  the_thread->cpu_time_budget        = config->cpu_time_budget;
279  the_thread->Start.isr_level        = config->isr_level;
280  the_thread->Start.is_preemptible   = config->is_preemptible;
281  the_thread->Start.budget_algorithm = config->budget_algorithm;
282  the_thread->Start.budget_callout   = config->budget_callout;
283  the_thread->Start.stack_free       = config->stack_free;
284
285  _Thread_Timer_initialize( &the_thread->Timer, cpu );
286  _Thread_Initialize_scheduler_and_wait_nodes( the_thread, config );
287
288#if defined(RTEMS_SMP)
289  _Processor_mask_Assign(
290    &the_thread->Scheduler.Affinity,
291    _SMP_Get_online_processors()
292   );
293  _SMP_lock_Stats_initialize( &the_thread->Potpourri_stats, "Thread Potpourri" );
294  _SMP_lock_Stats_initialize( &the_thread->Join_queue.Lock_stats, "Thread State" );
295#endif
296
297  /* Initialize the CPU for the non-SMP schedulers */
298  _Thread_Set_CPU( the_thread, cpu );
299
300  the_thread->current_state           = STATES_DORMANT;
301  the_thread->Wait.operations         = &_Thread_queue_Operations_default;
302  the_thread->Start.initial_priority  = config->priority;
303
304  RTEMS_STATIC_ASSERT( THREAD_WAIT_FLAGS_INITIAL == 0, Wait_flags );
305
306  /* POSIX Keys */
307  _RBTree_Initialize_empty( &the_thread->Keys.Key_value_pairs );
308  _ISR_lock_Initialize( &the_thread->Keys.Lock, "POSIX Key Value Pairs" );
309
310  _Thread_Action_control_initialize( &the_thread->Post_switch_actions );
311
312  _Objects_Open_u32( &information->Objects, &the_thread->Object, config->name );
313
314  /*
315   * We do following checks of simple error conditions after the thread is
316   * fully initialized to simplify the clean up in case of an error.  With a
317   * fully initialized thread we can simply use _Thread_Free() and do not have
318   * to bother with partially initialized threads.
319   */
320
321#if defined(RTEMS_SMP)
322  if (
323    !config->is_preemptible
324      && !_Scheduler_Is_non_preempt_mode_supported( config->scheduler )
325  ) {
326    return false;
327  }
328#endif
329
330#if defined(RTEMS_SMP) || CPU_ENABLE_ROBUST_THREAD_DISPATCH == TRUE
331  if (
332    config->isr_level != 0
333#if CPU_ENABLE_ROBUST_THREAD_DISPATCH == FALSE
334      && _SMP_Need_inter_processor_interrupts()
335#endif
336  ) {
337    return false;
338  }
339#endif
340
341  /*
342   *  We assume the Allocator Mutex is locked and dispatching is
343   *  enabled when we get here.  We want to be able to run the
344   *  user extensions with dispatching enabled.  The Allocator
345   *  Mutex provides sufficient protection to let the user extensions
346   *  run safely.
347   */
348  return _User_extensions_Thread_create( the_thread );
349}
350
351Status_Control _Thread_Initialize(
352  Thread_Information         *information,
353  Thread_Control             *the_thread,
354  const Thread_Configuration *config
355)
356{
357  bool ok;
358
359  ok = _Thread_Try_initialize( information, the_thread, config );
360
361  if ( !ok ) {
362    _Objects_Close( &information->Objects, &the_thread->Object );
363    _Thread_Free( information, the_thread );
364
365    return STATUS_UNSATISFIED;
366  }
367
368  return STATUS_SUCCESSFUL;
369}
Note: See TracBrowser for help on using the repository browser.