source: rtems/cpukit/score/src/threaddispatch.c @ 6c7caa1a

4.115
Last change on this file since 6c7caa1a was 38b59a6, checked in by Sebastian Huber <sebastian.huber@…>, on 05/02/14 at 08:31:09

score: Implement forced thread migration

The current implementation of task migration in RTEMS has some
implications with respect to the interrupt latency. It is crucial to
preserve the system invariant that a task can execute on at most one
processor in the system at a time. This is accomplished with a boolean
indicator in the task context. The processor architecture specific
low-level task context switch code will mark that a task context is no
longer executing and waits that the heir context stopped execution
before it restores the heir context and resumes execution of the heir
task. So there is one point in time in which a processor is without a
task. This is essential to avoid cyclic dependencies in case multiple
tasks migrate at once. Otherwise some supervising entity is necessary to
prevent life-locks. Such a global supervisor would lead to scalability
problems so this approach is not used. Currently the thread dispatch is
performed with interrupts disabled. So in case the heir task is
currently executing on another processor then this prolongs the time of
disabled interrupts since one processor has to wait for another
processor to make progress.

It is difficult to avoid this issue with the interrupt latency since
interrupts normally store the context of the interrupted task on its
stack. In case a task is marked as not executing we must not use its
task stack to store such an interrupt context. We cannot use the heir
stack before it stopped execution on another processor. So if we enable
interrupts during this transition we have to provide an alternative task
independent stack for this time frame. This issue needs further
investigation.

  • Property mode set to 100644
File size: 5.7 KB
Line 
1/**
2 * @file
3 *
4 * @brief Dispatch Thread
5 * @ingroup ScoreThread
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2009.
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/threaddispatch.h>
24#include <rtems/score/apiext.h>
25#include <rtems/score/assert.h>
26#include <rtems/score/isr.h>
27#include <rtems/score/threadimpl.h>
28#include <rtems/score/todimpl.h>
29#include <rtems/score/userextimpl.h>
30#include <rtems/score/wkspace.h>
31#include <rtems/config.h>
32
33static Thread_Action *_Thread_Get_post_switch_action(
34  Thread_Control *executing
35)
36{
37  Chain_Control *chain = &executing->Post_switch_actions.Chain;
38
39  return (Thread_Action *) _Chain_Get_unprotected( chain );
40}
41
42static void _Thread_Run_post_switch_actions( Thread_Control *executing )
43{
44  ISR_Level        level;
45  Per_CPU_Control *cpu_self;
46  Thread_Action   *action;
47
48  cpu_self = _Thread_Action_ISR_disable_and_acquire( executing, &level );
49  action = _Thread_Get_post_switch_action( executing );
50
51  while ( action != NULL ) {
52    _Chain_Set_off_chain( &action->Node );
53
54    ( *action->handler )( executing, action, cpu_self, level );
55
56    cpu_self = _Thread_Action_ISR_disable_and_acquire( executing, &level );
57    action = _Thread_Get_post_switch_action( executing );
58  }
59
60  _Thread_Action_release_and_ISR_enable( cpu_self, level );
61}
62
63void _Thread_Dispatch( void )
64{
65  Per_CPU_Control  *cpu_self;
66  Thread_Control   *executing;
67  ISR_Level         level;
68
69#if defined( RTEMS_SMP )
70  /*
71   * On SMP the complete context switch must be atomic with respect to one
72   * processor.  See also _Thread_Handler() since _Context_switch() may branch
73   * to this function.
74   */
75  _ISR_Disable_without_giant( level );
76#endif
77
78  cpu_self = _Per_CPU_Get();
79  _Assert( cpu_self->thread_dispatch_disable_level == 0 );
80  _Profiling_Thread_dispatch_disable( cpu_self, 0 );
81  cpu_self->thread_dispatch_disable_level = 1;
82
83  /*
84   *  Now determine if we need to perform a dispatch on the current CPU.
85   */
86  executing = cpu_self->executing;
87
88#if !defined( RTEMS_SMP )
89  _ISR_Disable( level );
90#endif
91
92#if defined( RTEMS_SMP )
93  if ( cpu_self->dispatch_necessary ) {
94#else
95  while ( cpu_self->dispatch_necessary ) {
96#endif
97    Thread_Control *heir = _Thread_Get_heir_and_make_it_executing( cpu_self );
98
99    /*
100     *  When the heir and executing are the same, then we are being
101     *  requested to do the post switch dispatching.  This is normally
102     *  done to dispatch signals.
103     */
104    if ( heir == executing )
105      goto post_switch;
106
107    /*
108     *  Since heir and executing are not the same, we need to do a real
109     *  context switch.
110     */
111#if __RTEMS_ADA__
112    executing->rtems_ada_self = rtems_ada_self;
113    rtems_ada_self = heir->rtems_ada_self;
114#endif
115    if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )
116      heir->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice();
117
118#if !defined( RTEMS_SMP )
119    _ISR_Enable( level );
120#endif
121
122    #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
123      _Thread_Update_cpu_time_used(
124        executing,
125        &cpu_self->time_of_last_context_switch
126      );
127    #else
128      {
129        _TOD_Get_uptime( &cpu_self->time_of_last_context_switch );
130        heir->cpu_time_used++;
131      }
132    #endif
133
134#if !defined(__DYNAMIC_REENT__)
135    /*
136     * Switch libc's task specific data.
137     */
138    if ( _Thread_libc_reent ) {
139      executing->libc_reent = *_Thread_libc_reent;
140      *_Thread_libc_reent = heir->libc_reent;
141    }
142#endif
143
144    _User_extensions_Thread_switch( executing, heir );
145
146    /*
147     *  If the CPU has hardware floating point, then we must address saving
148     *  and restoring it as part of the context switch.
149     *
150     *  The second conditional compilation section selects the algorithm used
151     *  to context switch between floating point tasks.  The deferred algorithm
152     *  can be significantly better in a system with few floating point tasks
153     *  because it reduces the total number of save and restore FP context
154     *  operations.  However, this algorithm can not be used on all CPUs due
155     *  to unpredictable use of FP registers by some compilers for integer
156     *  operations.
157     */
158
159#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
160#if ( CPU_USE_DEFERRED_FP_SWITCH != TRUE )
161    if ( executing->fp_context != NULL )
162      _Context_Save_fp( &executing->fp_context );
163#endif
164#endif
165
166    _Context_Switch( &executing->Registers, &heir->Registers );
167
168#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
169#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
170    if ( (executing->fp_context != NULL) &&
171         !_Thread_Is_allocated_fp( executing ) ) {
172      if ( _Thread_Allocated_fp != NULL )
173        _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
174      _Context_Restore_fp( &executing->fp_context );
175      _Thread_Allocated_fp = executing;
176    }
177#else
178    if ( executing->fp_context != NULL )
179      _Context_Restore_fp( &executing->fp_context );
180#endif
181#endif
182
183    /*
184     * We have to obtain this value again after the context switch since the
185     * heir thread may have migrated from another processor.  Values from the
186     * stack or non-volatile registers reflect the old execution environment.
187     */
188    cpu_self = _Per_CPU_Get();
189
190    _Thread_Debug_set_real_processor( executing, cpu_self );
191
192#if !defined( RTEMS_SMP )
193    _ISR_Disable( level );
194#endif
195  }
196
197post_switch:
198  _Assert( cpu_self->thread_dispatch_disable_level == 1 );
199  cpu_self->thread_dispatch_disable_level = 0;
200  _Profiling_Thread_dispatch_enable( cpu_self, 0 );
201
202  _ISR_Enable_without_giant( level );
203
204  _Thread_Run_post_switch_actions( executing );
205}
Note: See TracBrowser for help on using the repository browser.