source: rtems/cpukit/score/src/threadrestart.c @ e1598a6

4.115
Last change on this file since e1598a6 was e1598a6, checked in by Sebastian Huber <sebastian.huber@…>, on 04/04/14 at 08:56:36

score: Static scheduler configuration

Do not allocate the scheduler control structures from the workspace.
This is a preparation step for configuration of clustered/partitioned
schedulers on SMP.

  • Property mode set to 100644
File size: 10.7 KB
RevLine 
[f7f1d77]1/**
2 * @file
[05df0a8]3 *
[f7f1d77]4 * @brief Restart Thread
5 * @ingroup ScoreThread
6 */
7
8/*
[08311cc3]9 *  COPYRIGHT (c) 1989-1999.
[05df0a8]10 *  On-Line Applications Research Corporation (OAR).
11 *
[1b1be254]12 *  Copyright (c) 2014 embedded brains GmbH.
13 *
[05df0a8]14 *  The license and distribution terms for this file may be
[dcf3687]15 *  found in the file LICENSE in this distribution or at
[c499856]16 *  http://www.rtems.org/license/LICENSE.
[05df0a8]17 */
18
[a8eed23]19#if HAVE_CONFIG_H
20#include "config.h"
21#endif
22
[5618c37a]23#include <rtems/score/threadimpl.h>
[1b1be254]24#include <rtems/score/apimutex.h>
25#include <rtems/score/assert.h>
26#include <rtems/score/chainimpl.h>
27#include <rtems/score/isrlock.h>
28#include <rtems/score/schedulerimpl.h>
29#include <rtems/score/sysstate.h>
[dcd5e26]30#include <rtems/score/threadqimpl.h>
[3be0c9a]31#include <rtems/score/userextimpl.h>
[dcd5e26]32#include <rtems/score/watchdogimpl.h>
[1b1be254]33#include <rtems/score/wkspace.h>
34
35typedef struct {
36  Chain_Control Chain;
37  ISR_lock_Control Lock;
38} Thread_Zombie_control;
39
40static Thread_Zombie_control _Thread_Zombies = {
41  .Chain = CHAIN_INITIALIZER_EMPTY( _Thread_Zombies.Chain ),
42  .Lock = ISR_LOCK_INITIALIZER( "thread zombies" )
43};
44
45static void _Thread_Make_zombie( Thread_Control *the_thread )
46{
47  ISR_lock_Context lock_context;
48  Thread_Zombie_control *zombies = &_Thread_Zombies;
49
[3f5f2ce]50  if ( the_thread->resource_count != 0 ) {
51    _Terminate(
52      INTERNAL_ERROR_CORE,
53      false,
54      INTERNAL_ERROR_RESOURCE_IN_USE
55    );
56  }
57
[1b1be254]58  _Thread_Set_state( the_thread, STATES_ZOMBIE );
59  _Thread_queue_Extract_with_proxy( the_thread );
60  _Watchdog_Remove( &the_thread->Timer );
61
62  _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context );
63  _Chain_Append_unprotected( &zombies->Chain, &the_thread->Object.Node );
64  _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context );
65}
66
67static void _Thread_Free( Thread_Control *the_thread )
68{
69  _User_extensions_Thread_delete( the_thread );
70
71  /*
72   * Free the per-thread scheduling information.
73   */
[24934e36]74  _Scheduler_Free( _Scheduler_Get( the_thread ), the_thread );
[1b1be254]75
76  /*
77   *  The thread might have been FP.  So deal with that.
78   */
79#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
80#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
81  if ( _Thread_Is_allocated_fp( the_thread ) )
82    _Thread_Deallocate_fp();
83#endif
84
85  _Workspace_Free( the_thread->Start.fp_context );
86#endif
87
88  /*
89   *  Free the rest of the memory associated with this task
90   *  and set the associated pointers to NULL for safety.
91   */
92  _Thread_Stack_Free( the_thread );
93
94  _Workspace_Free( the_thread->extensions );
95
96  _Workspace_Free( the_thread->Start.tls_area );
97
98  _Objects_Free(
99    _Objects_Get_information_id( the_thread->Object.id ),
100    &the_thread->Object
101  );
102}
103
104static void _Thread_Wait_for_execution_stop( Thread_Control *the_thread )
105{
106#if defined(RTEMS_SMP)
107  /*
108   * It is very unlikely that we see an executing thread here.  It can happen
109   * in case the thread termination sequence is interrupted by a slow interrupt
110   * service on a remote processor.
111   */
112  while (the_thread->is_executing) {
113    /* Wait */
114  }
115#else
116  (void) the_thread;
117#endif
118}
119
120void _Thread_Kill_zombies( void )
121{
122  ISR_lock_Context lock_context;
123  Thread_Zombie_control *zombies = &_Thread_Zombies;
124  Thread_Control *the_thread;
125
126  _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context );
127
128  the_thread = (Thread_Control *) _Chain_Get_unprotected( &zombies->Chain );
129  while ( the_thread != NULL ) {
130    _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context );
131
132    _Thread_Wait_for_execution_stop( the_thread );
133    _Thread_Free( the_thread );
134
135    _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context );
136
137    the_thread = (Thread_Control *) _Chain_Get_unprotected( &zombies->Chain );
138  }
139
140  _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context );
141}
142
143static void _Thread_Start_life_change_for_executing(
144  Thread_Control *executing
145)
146{
147  _Assert( executing->Timer.state == WATCHDOG_INACTIVE );
148  _Assert(
149    executing->current_state == STATES_READY
150      || executing->current_state == STATES_SUSPENDED
151  );
152
153  _Thread_Add_post_switch_action( executing, &executing->Life.Action );
154}
[05df0a8]155
[5c731a83]156void _Thread_Life_action_handler(
157  Thread_Control  *executing,
158  Thread_Action   *action,
159  Per_CPU_Control *cpu,
160  ISR_Level        level
161)
162{
[1b1be254]163  Thread_Life_state previous_life_state;
164
[5c731a83]165  (void) action;
[1b1be254]166
167  previous_life_state = executing->Life.state;
168  executing->Life.state = THREAD_LIFE_PROTECTED;
169
[5c731a83]170  _Thread_Action_release_and_ISR_enable( cpu, level );
171
[1b1be254]172  if ( _Thread_Is_life_terminating( previous_life_state ) ) {
173    _User_extensions_Thread_terminate( executing );
174  } else {
175    _Assert( _Thread_Is_life_restarting( previous_life_state ) );
176
177    _User_extensions_Thread_restart( executing );
178  }
[391ad3e]179
[5c731a83]180  _Thread_Disable_dispatch();
181
[1b1be254]182  if ( _Thread_Is_life_terminating( previous_life_state ) ) {
183    _Thread_Make_zombie( executing );
184
185    if ( executing->Life.terminator != NULL ) {
186      _Thread_Clear_state(
187        executing->Life.terminator,
188        STATES_WAITING_FOR_TERMINATION
189      );
190    }
191
192    _Thread_Enable_dispatch();
193
194    _Assert_Not_reached();
195  } else {
196    _Assert( _Thread_Is_life_restarting( previous_life_state ) );
197
198    if ( _Thread_Is_life_terminating( executing->Life.state ) ) {
199      /* Someone deleted us in the mean-time */
200      _Thread_Start_life_change_for_executing( executing );
201    } else {
202      _Assert( executing->Timer.state == WATCHDOG_INACTIVE );
203      _Assert(
204        executing->current_state == STATES_READY
205          || executing->current_state == STATES_SUSPENDED
206      );
207
208      executing->Life.state = THREAD_LIFE_NORMAL;
209
210      _Thread_Load_environment( executing );
211      _Thread_Restart_self( executing );
212
213      _Assert_Not_reached();
214    }
215  }
[5c731a83]216}
217
[226c731]218static void _Thread_Start_life_change(
[e1598a6]219  Thread_Control          *the_thread,
220  const Scheduler_Control *scheduler,
221  Priority_Control         priority
[226c731]222)
[dcd5e26]223{
224  the_thread->is_preemptible   = the_thread->Start.is_preemptible;
225  the_thread->budget_algorithm = the_thread->Start.budget_algorithm;
226  the_thread->budget_callout   = the_thread->Start.budget_callout;
[226c731]227  the_thread->real_priority    = priority;
[dcd5e26]228
[226c731]229  _Thread_Set_transient( the_thread );
230  _Thread_queue_Extract_with_proxy( the_thread );
231  _Watchdog_Remove( &the_thread->Timer );
[24934e36]232  _Scheduler_Set_priority_if_higher( scheduler, the_thread, priority );
[226c731]233  _Thread_Add_post_switch_action( the_thread, &the_thread->Life.Action );
234  _Thread_Ready( the_thread );
235  _Thread_Request_dispatch_if_executing( the_thread );
[dcd5e26]236}
237
[8690b53]238static void _Thread_Request_life_change(
[226c731]239  Thread_Control    *the_thread,
240  Thread_Control    *executing,
[1b1be254]241  Priority_Control   priority,
242  Thread_Life_state  additional_life_state
[8690b53]243)
[05df0a8]244{
[1b1be254]245  Thread_Life_state previous_life_state;
246  Per_CPU_Control *cpu;
247  ISR_Level level;
[e1598a6]248  const Scheduler_Control *scheduler;
[1b1be254]249
250  cpu = _Thread_Action_ISR_disable_and_acquire( the_thread, &level );
251  previous_life_state = the_thread->Life.state;
252  the_thread->Life.state = previous_life_state | additional_life_state;
253  _Thread_Action_release_and_ISR_enable( cpu, level );
254
[24934e36]255  scheduler = _Scheduler_Get( the_thread );
[1b1be254]256  if ( the_thread == executing ) {
257    executing->real_priority = priority;
258
[24934e36]259    _Scheduler_Set_priority_if_higher( scheduler, the_thread, priority );
[1b1be254]260    _Thread_Start_life_change_for_executing( executing );
261  } else if ( previous_life_state == THREAD_LIFE_NORMAL ) {
[24934e36]262    _Thread_Start_life_change( the_thread, scheduler, priority );
[1b1be254]263  } else {
264    _Thread_Clear_state( the_thread, STATES_SUSPENDED );
265
266    if ( _Thread_Is_life_terminating( additional_life_state ) ) {
267      the_thread->real_priority = _Scheduler_Highest_priority_of_two(
[24934e36]268        scheduler,
[1b1be254]269        the_thread->real_priority,
270        priority
271      );
272
[24934e36]273      _Scheduler_Change_priority_if_higher(
274        scheduler,
275        the_thread,
276        priority,
277        false
278      );
[1b1be254]279    }
280  }
281}
282
283void _Thread_Close( Thread_Control *the_thread, Thread_Control *executing )
284{
285  _Assert( _Thread_Is_life_protected( executing->Life.state ) );
286
287  _Objects_Close(
288    _Objects_Get_information_id( the_thread->Object.id ),
289    &the_thread->Object
290  );
291
292  if ( _States_Is_dormant( the_thread->current_state ) ) {
293    _Thread_Make_zombie( the_thread );
294  } else {
295    if (
296      the_thread != executing
297        && !_Thread_Is_life_terminating( executing->Life.state )
298    ) {
299      /*
300       * Wait for termination of victim thread.  If the executing thread is
301       * also terminated, then do not wait.  This avoids potential cyclic
302       * dependencies and thus dead lock.
303       */
304       the_thread->Life.terminator = executing;
305       _Thread_Set_state( executing, STATES_WAITING_FOR_TERMINATION );
306    }
307
308    _Thread_Request_life_change(
309      the_thread,
310      executing,
311      executing->current_priority,
312      THREAD_LIFE_TERMINATING
313    );
314  }
[5c731a83]315}
[05279b84]316
[5c731a83]317bool _Thread_Restart(
318  Thread_Control            *the_thread,
[8690b53]319  Thread_Control            *executing,
[5c731a83]320  void                      *pointer_argument,
321  Thread_Entry_numeric_type  numeric_argument
322)
323{
324  if ( !_States_Is_dormant( the_thread->current_state ) ) {
[084c5cc]325    the_thread->Start.pointer_argument = pointer_argument;
326    the_thread->Start.numeric_argument = numeric_argument;
327
[8690b53]328    _Thread_Request_life_change(
329      the_thread,
[226c731]330      executing,
[1b1be254]331      the_thread->Start.initial_priority,
332      THREAD_LIFE_RESTARTING
[8690b53]333    );
[05279b84]334
[aae7f1a1]335    return true;
[05df0a8]336  }
[05279b84]337
[aae7f1a1]338  return false;
[05df0a8]339}
[1b1be254]340
341bool _Thread_Set_life_protection( bool protect )
342{
343  bool previous_life_protection;
344  ISR_Level level;
345  Per_CPU_Control *cpu;
346  Thread_Control *executing;
347  Thread_Life_state previous_life_state;
348
349  cpu = _Thread_Action_ISR_disable_and_acquire_for_executing( &level );
350  executing = cpu->executing;
351
352  previous_life_state = executing->Life.state;
353  previous_life_protection = _Thread_Is_life_protected( previous_life_state );
354
355  if ( protect ) {
356    executing->Life.state = previous_life_state | THREAD_LIFE_PROTECTED;
357  } else {
358    executing->Life.state = previous_life_state & ~THREAD_LIFE_PROTECTED;
359  }
360
361  _Thread_Action_release_and_ISR_enable( cpu, level );
362
363#if defined(RTEMS_SMP)
364  /*
365   * On SMP configurations it is possible that a life change of an executing
366   * thread is requested, but this thread didn't notice it yet.  The life
367   * change is first marked in the life state field and then all scheduling and
368   * other thread state updates are performed.  The last step is to issues an
369   * inter-processor interrupt if necessary.  Since this takes some time we
370   * have to synchronize here.
371   */
372  if (
373    !_Thread_Is_life_protected( previous_life_state )
374      && _Thread_Is_life_changing( previous_life_state )
375  ) {
376    _Thread_Disable_dispatch();
377    _Thread_Enable_dispatch();
378
379    _Assert_Not_reached();
380  }
381#endif
382
383  if (
384    !protect
385      && _Thread_Is_life_changing( previous_life_state )
386  ) {
387    _Thread_Disable_dispatch();
388    _Thread_Start_life_change_for_executing( executing );
389    _Thread_Enable_dispatch();
390
391    _Assert_Not_reached();
392  }
393
394  return previous_life_protection;
395}
Note: See TracBrowser for help on using the repository browser.