source: rtems/cpukit/score/src/threadinitialize.c @ 1ac4a85

Last change on this file since 1ac4a85 was 1ac4a85, checked in by Sebastian Huber <sebastian.huber@…>, on 02/25/21 at 18:08:52

score: Fix thread initialization

Close the thread object if a thread create extension fails. Also call
the delete extension to avoid resource leaks in early extensions if a
late extension fails.

Close #4270.

  • Property mode set to 100644
File size: 9.9 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#include <rtems/config.h>
31
32void _Thread_Free(
33  Thread_Information *information,
34  Thread_Control     *the_thread
35)
36{
37#if defined(RTEMS_SMP)
38  Scheduler_Node *scheduler_node;
39  size_t          scheduler_index;
40#endif
41
42  _User_extensions_Thread_delete( the_thread );
43  _User_extensions_Destroy_iterators( the_thread );
44  _ISR_lock_Destroy( &the_thread->Keys.Lock );
45
46#if defined(RTEMS_SMP)
47  scheduler_node = the_thread->Scheduler.nodes;
48  scheduler_index = 0;
49
50  while ( scheduler_index < _Scheduler_Count ) {
51    _Scheduler_Node_destroy(
52      &_Scheduler_Table[ scheduler_index ],
53      scheduler_node
54    );
55    scheduler_node = (Scheduler_Node *)
56      ( (uintptr_t) scheduler_node + _Scheduler_Node_size );
57    ++scheduler_index;
58  }
59#else
60  _Scheduler_Node_destroy(
61    _Thread_Scheduler_get_home( the_thread ),
62    _Thread_Scheduler_get_home_node( the_thread )
63  );
64#endif
65
66  _ISR_lock_Destroy( &the_thread->Timer.Lock );
67
68  /*
69   *  The thread might have been FP.  So deal with that.
70   */
71#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
72#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
73  if ( _Thread_Is_allocated_fp( the_thread ) )
74    _Thread_Deallocate_fp();
75#endif
76#endif
77
78  _Freechain_Push(
79    &information->Thread_queue_heads.Free,
80    the_thread->Wait.spare_heads
81  );
82
83  /*
84   *  Free the rest of the memory associated with this task
85   *  and set the associated pointers to NULL for safety.
86   */
87  ( *the_thread->Start.stack_free )( the_thread->Start.Initial_stack.area );
88
89#if defined(RTEMS_SMP)
90  _ISR_lock_Destroy( &the_thread->Scheduler.Lock );
91  _ISR_lock_Destroy( &the_thread->Wait.Lock.Default );
92  _SMP_lock_Stats_destroy( &the_thread->Potpourri_stats );
93#endif
94
95  _Thread_queue_Destroy( &the_thread->Join_queue );
96  _Context_Destroy( the_thread, &the_thread->Registers );
97  _Objects_Free( &information->Objects, &the_thread->Object );
98}
99
100static bool _Thread_Try_initialize(
101  Thread_Information         *information,
102  Thread_Control             *the_thread,
103  const Thread_Configuration *config
104)
105{
106  uintptr_t                tls_size;
107  size_t                   i;
108  char                    *stack_begin;
109  char                    *stack_end;
110  Scheduler_Node          *scheduler_node;
111#if defined(RTEMS_SMP)
112  Scheduler_Node          *scheduler_node_for_index;
113  const Scheduler_Control *scheduler_for_index;
114  size_t                   scheduler_index;
115#endif
116  Per_CPU_Control         *cpu = _Per_CPU_Get_by_index( 0 );
117
118  memset(
119    &the_thread->Join_queue,
120    0,
121    information->Objects.object_size - offsetof( Thread_Control, Join_queue )
122  );
123
124  for ( i = 0 ; i < _Thread_Control_add_on_count ; ++i ) {
125    const Thread_Control_add_on *add_on = &_Thread_Control_add_ons[ i ];
126
127    *(void **) ( (char *) the_thread + add_on->destination_offset ) =
128      (char *) the_thread + add_on->source_offset;
129  }
130
131  stack_begin = config->stack_area;
132  stack_end = stack_begin + config->stack_size;
133
134  /* Allocate floating-point context in stack area */
135#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
136  if ( config->is_fp ) {
137    stack_end -= CONTEXT_FP_SIZE;
138    the_thread->fp_context = (Context_Control_fp *) stack_end;
139    the_thread->Start.fp_context = (Context_Control_fp *) stack_end;
140  }
141#endif
142
143  tls_size = _TLS_Get_allocation_size();
144
145  /* Allocate thread-local storage (TLS) area in stack area */
146  if ( tls_size > 0 ) {
147    uintptr_t tls_align;
148
149    stack_end -= tls_size;
150    tls_align = (uintptr_t) _TLS_Alignment;
151    the_thread->Start.tls_area = (void *)
152      ( ( (uintptr_t) stack_end + tls_align - 1 ) & ~( tls_align - 1 ) );
153  }
154
155  _Stack_Initialize(
156    &the_thread->Start.Initial_stack,
157    stack_begin,
158    stack_end - stack_begin
159  );
160
161  /*
162   *  Get thread queue heads
163   */
164  the_thread->Wait.spare_heads = _Freechain_Pop(
165    &information->Thread_queue_heads.Free
166  );
167  _Thread_queue_Heads_initialize( the_thread->Wait.spare_heads );
168
169  /*
170   *  General initialization
171   */
172
173  the_thread->is_fp                  = config->is_fp;
174  the_thread->Start.isr_level        = config->isr_level;
175  the_thread->Start.is_preemptible   = config->is_preemptible;
176  the_thread->Start.budget_algorithm = config->budget_algorithm;
177  the_thread->Start.budget_callout   = config->budget_callout;
178  the_thread->Start.stack_free       = config->stack_free;
179
180  _Thread_Timer_initialize( &the_thread->Timer, cpu );
181
182  switch ( config->budget_algorithm ) {
183    case THREAD_CPU_BUDGET_ALGORITHM_NONE:
184    case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE:
185      break;
186    #if defined(RTEMS_SCORE_THREAD_ENABLE_EXHAUST_TIMESLICE)
187      case THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE:
188        the_thread->cpu_time_budget =
189          rtems_configuration_get_ticks_per_timeslice();
190        break;
191    #endif
192    #if defined(RTEMS_SCORE_THREAD_ENABLE_SCHEDULER_CALLOUT)
193      case THREAD_CPU_BUDGET_ALGORITHM_CALLOUT:
194        break;
195    #endif
196  }
197
198#if defined(RTEMS_SMP)
199  scheduler_node = NULL;
200  scheduler_node_for_index = the_thread->Scheduler.nodes;
201  scheduler_for_index = &_Scheduler_Table[ 0 ];
202  scheduler_index = 0;
203
204  while ( scheduler_index < _Scheduler_Count ) {
205    Priority_Control priority_for_index;
206
207    if ( scheduler_for_index == config->scheduler ) {
208      priority_for_index = config->priority;
209      scheduler_node = scheduler_node_for_index;
210    } else {
211      /*
212       * Use the idle thread priority for the non-home scheduler instances by
213       * default.
214       */
215      priority_for_index = _Scheduler_Map_priority(
216        scheduler_for_index,
217        scheduler_for_index->maximum_priority
218      );
219    }
220
221    _Scheduler_Node_initialize(
222      scheduler_for_index,
223      scheduler_node_for_index,
224      the_thread,
225      priority_for_index
226    );
227    scheduler_node_for_index = (Scheduler_Node *)
228      ( (uintptr_t) scheduler_node_for_index + _Scheduler_Node_size );
229    ++scheduler_for_index;
230    ++scheduler_index;
231  }
232
233  _Assert( scheduler_node != NULL );
234  _Chain_Initialize_one(
235    &the_thread->Scheduler.Wait_nodes,
236    &scheduler_node->Thread.Wait_node
237  );
238  _Chain_Initialize_one(
239    &the_thread->Scheduler.Scheduler_nodes,
240    &scheduler_node->Thread.Scheduler_node.Chain
241  );
242#else
243  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
244  _Scheduler_Node_initialize(
245    config->scheduler,
246    scheduler_node,
247    the_thread,
248    config->priority
249  );
250#endif
251
252  _Priority_Node_initialize( &the_thread->Real_priority, config->priority );
253  _Priority_Initialize_one(
254    &scheduler_node->Wait.Priority,
255    &the_thread->Real_priority
256  );
257
258#if defined(RTEMS_SMP)
259  RTEMS_STATIC_ASSERT( THREAD_SCHEDULER_BLOCKED == 0, Scheduler_state );
260  the_thread->Scheduler.home_scheduler = config->scheduler;
261  _ISR_lock_Initialize( &the_thread->Scheduler.Lock, "Thread Scheduler" );
262  _Processor_mask_Assign(
263    &the_thread->Scheduler.Affinity,
264    _SMP_Get_online_processors()
265   );
266  _ISR_lock_Initialize( &the_thread->Wait.Lock.Default, "Thread Wait Default" );
267  _Thread_queue_Gate_open( &the_thread->Wait.Lock.Tranquilizer );
268  _RBTree_Initialize_node( &the_thread->Wait.Link.Registry_node );
269  _SMP_lock_Stats_initialize( &the_thread->Potpourri_stats, "Thread Potpourri" );
270  _SMP_lock_Stats_initialize( &the_thread->Join_queue.Lock_stats, "Thread State" );
271#endif
272
273  /* Initialize the CPU for the non-SMP schedulers */
274  _Thread_Set_CPU( the_thread, cpu );
275
276  the_thread->current_state           = STATES_DORMANT;
277  the_thread->Wait.operations         = &_Thread_queue_Operations_default;
278  the_thread->Start.initial_priority  = config->priority;
279
280  RTEMS_STATIC_ASSERT( THREAD_WAIT_FLAGS_INITIAL == 0, Wait_flags );
281
282  /* POSIX Keys */
283  _RBTree_Initialize_empty( &the_thread->Keys.Key_value_pairs );
284  _ISR_lock_Initialize( &the_thread->Keys.Lock, "POSIX Key Value Pairs" );
285
286  _Thread_Action_control_initialize( &the_thread->Post_switch_actions );
287
288  _Objects_Open_u32( &information->Objects, &the_thread->Object, config->name );
289
290  /*
291   * We do following checks of simple error conditions after the thread is
292   * fully initialized to simplify the clean up in case of an error.  With a
293   * fully initialized thread we can simply use _Thread_Free() and do not have
294   * to bother with partially initialized threads.
295   */
296
297#if defined(RTEMS_SMP)
298  if (
299    !config->is_preemptible
300      && !_Scheduler_Is_non_preempt_mode_supported( config->scheduler )
301  ) {
302    return false;
303  }
304#endif
305
306#if defined(RTEMS_SMP) || CPU_ENABLE_ROBUST_THREAD_DISPATCH == TRUE
307  if (
308    config->isr_level != 0
309#if CPU_ENABLE_ROBUST_THREAD_DISPATCH == FALSE
310      && _SMP_Need_inter_processor_interrupts()
311#endif
312  ) {
313    return false;
314  }
315#endif
316
317  /*
318   *  We assume the Allocator Mutex is locked and dispatching is
319   *  enabled when we get here.  We want to be able to run the
320   *  user extensions with dispatching enabled.  The Allocator
321   *  Mutex provides sufficient protection to let the user extensions
322   *  run safely.
323   */
324  return _User_extensions_Thread_create( the_thread );
325}
326
327Status_Control _Thread_Initialize(
328  Thread_Information         *information,
329  Thread_Control             *the_thread,
330  const Thread_Configuration *config
331)
332{
333  bool ok;
334
335  ok = _Thread_Try_initialize( information, the_thread, config );
336
337  if ( !ok ) {
338    _Objects_Close( &information->Objects, &the_thread->Object );
339    _Thread_Free( information, the_thread );
340
341    return STATUS_UNSATISFIED;
342  }
343
344  return STATUS_SUCCESSFUL;
345}
Note: See TracBrowser for help on using the repository browser.