source: rtems/cpukit/score/src/threaddispatch.c @ 8061f56

4.115
Last change on this file since 8061f56 was 8061f56, checked in by Sebastian Huber <sebastian.huber@…>, on 03/14/14 at 10:55:28

score: Delete post-switch API extensions

Use thread post-switch actions instead.

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