source: rtems/cpukit/score/src/threaddispatch.c @ 4fc370e

4.115
Last change on this file since 4fc370e was 4fc370e, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 5, 2013 at 10:08:23 AM

score: Move thread dispatch content to new file

Move thread dispatch declarations and inline functions to new header
<rtems/score/threaddispatch.h> to make it independent of the
Thread_Control structure. This avoids a cyclic dependency in case
thread dispatch functions are used for the object implementation.

  • 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 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.com/license/LICENSE.
15 */
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <rtems/system.h>
22#include <rtems/score/apiext.h>
23#include <rtems/score/context.h>
24#include <rtems/score/interr.h>
25#include <rtems/score/isr.h>
26#include <rtems/score/object.h>
27#include <rtems/score/priority.h>
28#include <rtems/score/states.h>
29#include <rtems/score/sysstate.h>
30#include <rtems/score/thread.h>
31#include <rtems/score/threaddispatch.h>
32#include <rtems/score/threadq.h>
33#include <rtems/score/userextimpl.h>
34#include <rtems/score/wkspace.h>
35
36#ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
37  #include <rtems/score/timestamp.h>
38#endif
39
40#if defined(RTEMS_SMP)
41  #include <rtems/score/smp.h>
42#endif
43
44void _Thread_Dispatch( void )
45{
46  Thread_Control   *executing;
47  Thread_Control   *heir;
48  ISR_Level         level;
49
50  #if defined(RTEMS_SMP)
51    /*
52     * WARNING: The SMP sequence has severe defects regarding the real-time
53     * performance.
54     *
55     * Consider the following scenario.  We have three tasks L (lowest
56     * priority), M (middle priority), and H (highest priority).  Now let a
57     * thread dispatch from M to L happen.  An interrupt occurs in
58     * _Thread_Dispatch() here:
59     *
60     * void _Thread_Dispatch( void )
61     * {
62     *   [...]
63     *
64     * post_switch:
65     *
66     *   _ISR_Enable( level );
67     *
68     *   <-- INTERRUPT
69     *   <-- AFTER INTERRUPT
70     *
71     *   _Thread_Unnest_dispatch();
72     *
73     *   _API_extensions_Run_post_switch();
74     * }
75     *
76     * The interrupt event makes task H ready.  The interrupt code will see
77     * _Thread_Dispatch_disable_level > 0 and thus doesn't perform a
78     * _Thread_Dispatch().  Now we return to position "AFTER INTERRUPT".  This
79     * means task L executes now although task H is ready!  Task H will execute
80     * once someone calls _Thread_Dispatch().
81     */
82    _Thread_Disable_dispatch();
83
84    /*
85     *  If necessary, send dispatch request to other cores.
86     */
87    _SMP_Request_other_cores_to_dispatch();
88  #endif
89
90  /*
91   *  Now determine if we need to perform a dispatch on the current CPU.
92   */
93  executing   = _Thread_Executing;
94  _ISR_Disable( level );
95  while ( _Thread_Dispatch_necessary == true ) {
96    heir = _Thread_Heir;
97    #ifndef RTEMS_SMP
98      _Thread_Dispatch_set_disable_level( 1 );
99    #endif
100    _Thread_Dispatch_necessary = false;
101    _Thread_Executing = heir;
102
103    /*
104     *  When the heir and executing are the same, then we are being
105     *  requested to do the post switch dispatching.  This is normally
106     *  done to dispatch signals.
107     */
108    if ( heir == executing )
109      goto post_switch;
110
111    /*
112     *  Since heir and executing are not the same, we need to do a real
113     *  context switch.
114     */
115#if __RTEMS_ADA__
116    executing->rtems_ada_self = rtems_ada_self;
117    rtems_ada_self = heir->rtems_ada_self;
118#endif
119    if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )
120      heir->cpu_time_budget = _Thread_Ticks_per_timeslice;
121
122    _ISR_Enable( level );
123
124    #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
125      {
126        Timestamp_Control uptime, ran;
127        _TOD_Get_uptime( &uptime );
128        _Timestamp_Subtract(
129          &_Thread_Time_of_last_context_switch,
130          &uptime,
131          &ran
132        );
133        _Timestamp_Add_to( &executing->cpu_time_used, &ran );
134        _Thread_Time_of_last_context_switch = uptime;
135      }
136    #else
137      {
138        _TOD_Get_uptime( &_Thread_Time_of_last_context_switch );
139        heir->cpu_time_used++;
140      }
141    #endif
142
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
151    _User_extensions_Thread_switch( executing, heir );
152
153    /*
154     *  If the CPU has hardware floating point, then we must address saving
155     *  and restoring it as part of the context switch.
156     *
157     *  The second conditional compilation section selects the algorithm used
158     *  to context switch between floating point tasks.  The deferred algorithm
159     *  can be significantly better in a system with few floating point tasks
160     *  because it reduces the total number of save and restore FP context
161     *  operations.  However, this algorithm can not be used on all CPUs due
162     *  to unpredictable use of FP registers by some compilers for integer
163     *  operations.
164     */
165
166#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
167#if ( CPU_USE_DEFERRED_FP_SWITCH != TRUE )
168    if ( executing->fp_context != NULL )
169      _Context_Save_fp( &executing->fp_context );
170#endif
171#endif
172
173    _Context_Switch( &executing->Registers, &heir->Registers );
174
175#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
176#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
177    if ( (executing->fp_context != NULL) &&
178         !_Thread_Is_allocated_fp( executing ) ) {
179      if ( _Thread_Allocated_fp != NULL )
180        _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
181      _Context_Restore_fp( &executing->fp_context );
182      _Thread_Allocated_fp = executing;
183    }
184#else
185    if ( executing->fp_context != NULL )
186      _Context_Restore_fp( &executing->fp_context );
187#endif
188#endif
189
190    executing = _Thread_Executing;
191
192    _ISR_Disable( level );
193  }
194
195post_switch:
196  #ifndef RTEMS_SMP
197    _Thread_Dispatch_set_disable_level( 0 );
198  #endif
199
200  _ISR_Enable( level );
201
202  #ifdef RTEMS_SMP
203    _Thread_Unnest_dispatch();
204  #endif
205
206  _API_extensions_Run_post_switch( executing );
207}
Note: See TracBrowser for help on using the repository browser.