source: rtems/cpukit/score/src/threaddispatch.c @ a936aa49

4.115
Last change on this file since a936aa49 was a936aa49, checked in by Sebastian Huber <sebastian.huber@…>, on 06/06/13 at 13:41:00

scheduler: New simple SMP scheduler implementation

The new Simple SMP Scheduler allocates a processor for the processor
count highest priority ready threads. The thread priority and position
in the ready chain are the only information to determine the scheduling
decision. Threads with an allocated processor are in the scheduled
chain. After initialization the scheduled chain has exactly processor
count nodes. Each processor has exactly one allocated thread after
initialization. All enqueue and extract operations may exchange threads
with the scheduled chain. One thread will be added and another will be
removed. The scheduled and ready chain is ordered according to the
thread priority order. The chain insert operations are O(count of ready
threads), thus this scheduler is unsuitable for most real-time
applications.

The thread preempt mode will be ignored.

  • Property mode set to 100644
File size: 5.7 KB
RevLine 
[bf54252]1/**
2 * @file
3 *
4 * @brief Dispatch Thread
5 * @ingroup ScoreThread
6 */
7
[05df0a8]8/*
[dca9a82]9 *  COPYRIGHT (c) 1989-2009.
[05df0a8]10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
[dcf3687]13 *  found in the file LICENSE in this distribution or at
[dd687d97]14 *  http://www.rtems.com/license/LICENSE.
[05df0a8]15 */
16
[a8eed23]17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
[05df0a8]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>
[4fc370e]31#include <rtems/score/threaddispatch.h>
[05df0a8]32#include <rtems/score/threadq.h>
[3be0c9a]33#include <rtems/score/userextimpl.h>
[05df0a8]34#include <rtems/score/wkspace.h>
35
[c6f7e060]36#ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
[c16bcc0]37  #include <rtems/score/timestamp.h>
[c3330a8]38#endif
39
[d4dc7c8]40#if defined(RTEMS_SMP)
41  #include <rtems/score/smp.h>
42#endif
43
[05df0a8]44void _Thread_Dispatch( void )
45{
46  Thread_Control   *executing;
47  Thread_Control   *heir;
48  ISR_Level         level;
49
[d4dc7c8]50  #if defined(RTEMS_SMP)
[9b83a66]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     *
[04b5d17]73     *   _API_extensions_Run_post_switch();
[9b83a66]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
[d4dc7c8]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   */
[05df0a8]93  executing   = _Thread_Executing;
94  _ISR_Disable( level );
[4b1d261]95  while ( _Thread_Dispatch_necessary == true ) {
[05df0a8]96    heir = _Thread_Heir;
[a936aa49]97    #if defined(RTEMS_SMP)
98      executing->is_executing = false;
99      heir->is_executing = true;
100    #else
[9b83a66]101      _Thread_Dispatch_set_disable_level( 1 );
102    #endif
[4b1d261]103    _Thread_Dispatch_necessary = false;
[05df0a8]104    _Thread_Executing = heir;
[11e8bc5]105
106    /*
107     *  When the heir and executing are the same, then we are being
108     *  requested to do the post switch dispatching.  This is normally
109     *  done to dispatch signals.
110     */
111    if ( heir == executing )
112      goto post_switch;
113
114    /*
115     *  Since heir and executing are not the same, we need to do a real
116     *  context switch.
117     */
[81b329a]118#if __RTEMS_ADA__
[05df0a8]119    executing->rtems_ada_self = rtems_ada_self;
120    rtems_ada_self = heir->rtems_ada_self;
[81b329a]121#endif
[e9f6d10]122    if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )
123      heir->cpu_time_budget = _Thread_Ticks_per_timeslice;
[11e8bc5]124
[05df0a8]125    _ISR_Enable( level );
126
[c6f7e060]127    #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
[c3330a8]128      {
[c16bcc0]129        Timestamp_Control uptime, ran;
[c3330a8]130        _TOD_Get_uptime( &uptime );
[c16bcc0]131        _Timestamp_Subtract(
132          &_Thread_Time_of_last_context_switch,
133          &uptime,
134          &ran
135        );
136        _Timestamp_Add_to( &executing->cpu_time_used, &ran );
[c3330a8]137        _Thread_Time_of_last_context_switch = uptime;
138      }
139    #else
[d4dc7c8]140      {
[8896c97]141        _TOD_Get_uptime( &_Thread_Time_of_last_context_switch );
[d4dc7c8]142        heir->cpu_time_used++;
143      }
[c3330a8]144    #endif
[05df0a8]145
[0df8293e]146    /*
147     * Switch libc's task specific data.
148     */
149    if ( _Thread_libc_reent ) {
150      executing->libc_reent = *_Thread_libc_reent;
151      *_Thread_libc_reent = heir->libc_reent;
152    }
153
[05df0a8]154    _User_extensions_Thread_switch( executing, heir );
155
156    /*
157     *  If the CPU has hardware floating point, then we must address saving
158     *  and restoring it as part of the context switch.
159     *
160     *  The second conditional compilation section selects the algorithm used
161     *  to context switch between floating point tasks.  The deferred algorithm
162     *  can be significantly better in a system with few floating point tasks
163     *  because it reduces the total number of save and restore FP context
164     *  operations.  However, this algorithm can not be used on all CPUs due
165     *  to unpredictable use of FP registers by some compilers for integer
166     *  operations.
167     */
168
[48f89683]169#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
170#if ( CPU_USE_DEFERRED_FP_SWITCH != TRUE )
171    if ( executing->fp_context != NULL )
172      _Context_Save_fp( &executing->fp_context );
173#endif
174#endif
175
176    _Context_Switch( &executing->Registers, &heir->Registers );
177
[ca7858bb]178#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
[05df0a8]179#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
[63f786e]180    if ( (executing->fp_context != NULL) &&
181         !_Thread_Is_allocated_fp( executing ) ) {
[05df0a8]182      if ( _Thread_Allocated_fp != NULL )
183        _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
[48f89683]184      _Context_Restore_fp( &executing->fp_context );
185      _Thread_Allocated_fp = executing;
[05df0a8]186    }
187#else
188    if ( executing->fp_context != NULL )
[48f89683]189      _Context_Restore_fp( &executing->fp_context );
[05df0a8]190#endif
191#endif
192
193    executing = _Thread_Executing;
194
195    _ISR_Disable( level );
196  }
197
[11e8bc5]198post_switch:
[9b83a66]199  #ifndef RTEMS_SMP
200    _Thread_Dispatch_set_disable_level( 0 );
201  #endif
[05df0a8]202
203  _ISR_Enable( level );
204
[9b83a66]205  #ifdef RTEMS_SMP
206    _Thread_Unnest_dispatch();
207  #endif
208
[04b5d17]209  _API_extensions_Run_post_switch( executing );
[05df0a8]210}
Note: See TracBrowser for help on using the repository browser.