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

4.115
Last change on this file since 2903090 was 2903090, checked in by Sebastian Huber <sebastian.huber@…>, on 04/15/15 at 09:26:46

score: Add header to _Watchdog_Remove()

Add watchdog header parameter to _Watchdog_Remove() to be in line with
the other operations. Add _Watchdog_Remove_ticks() and
_Watchdog_Remove_seconds() for convenience.

Update #2307.

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