source: rtems/cpukit/score/include/rtems/score/schedulersmpimpl.h @ 6741427a

4.115
Last change on this file since 6741427a was a336d51, checked in by Sebastian Huber <sebastian.huber@…>, on 04/28/14 at 07:56:33

score: Avoid copy and paste

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/**
2 * @file
3 *
4 * @brief SMP Scheduler Implementation
5 *
6 * @ingroup ScoreSchedulerSMP
7 */
8
9/*
10 * Copyright (c) 2013-2014 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#ifndef _RTEMS_SCORE_SCHEDULERSMPIMPL_H
24#define _RTEMS_SCORE_SCHEDULERSMPIMPL_H
25
26#include <rtems/score/schedulersmp.h>
27#include <rtems/score/schedulersimpleimpl.h>
28#include <rtems/score/chainimpl.h>
29#include <rtems/score/scheduler.h>
30
31#ifdef __cplusplus
32extern "C" {
33#endif /* __cplusplus */
34
35/**
36 * @addtogroup ScoreSchedulerSMP
37 *
38 * @{
39 */
40
41typedef Thread_Control *( *Scheduler_SMP_Get_highest_ready )(
42  Scheduler_SMP_Context *self
43);
44
45typedef void ( *Scheduler_SMP_Extract )(
46  Scheduler_SMP_Context *self,
47  Thread_Control *thread
48);
49
50typedef void ( *Scheduler_SMP_Insert )(
51  Scheduler_SMP_Context *self,
52  Thread_Control *thread_to_insert
53);
54
55typedef void ( *Scheduler_SMP_Move )(
56  Scheduler_SMP_Context *self,
57  Thread_Control *thread_to_move
58);
59
60static inline void _Scheduler_SMP_Initialize(
61  Scheduler_SMP_Context *self
62)
63{
64  _Chain_Initialize_empty( &self->Scheduled );
65}
66
67static inline void _Scheduler_SMP_Allocate_processor(
68  Thread_Control *scheduled,
69  Thread_Control *victim
70)
71{
72  Per_CPU_Control *cpu_of_scheduled = _Thread_Get_CPU( scheduled );
73  Per_CPU_Control *cpu_of_victim = _Thread_Get_CPU( victim );
74  Thread_Control *heir;
75
76  scheduled->is_scheduled = true;
77  victim->is_scheduled = false;
78
79  _Per_CPU_Acquire( cpu_of_scheduled );
80
81  if ( scheduled->is_executing ) {
82    heir = cpu_of_scheduled->heir;
83    cpu_of_scheduled->heir = scheduled;
84  } else {
85    heir = scheduled;
86  }
87
88  _Per_CPU_Release( cpu_of_scheduled );
89
90  if ( heir != victim ) {
91    const Per_CPU_Control *cpu_of_executing = _Per_CPU_Get();
92
93    _Thread_Set_CPU( heir, cpu_of_victim );
94
95    cpu_of_victim->heir = heir;
96
97    /*
98     * It is critical that we first update the heir and then the dispatch
99     * necessary so that _Thread_Dispatch() cannot miss an update.
100     */
101    _Atomic_Fence( ATOMIC_ORDER_RELEASE );
102
103    cpu_of_victim->dispatch_necessary = true;
104
105    if ( cpu_of_victim != cpu_of_executing ) {
106      _Per_CPU_Send_interrupt( cpu_of_victim );
107    }
108  }
109}
110
111static inline Thread_Control *_Scheduler_SMP_Get_lowest_scheduled(
112  Scheduler_SMP_Context *self
113)
114{
115  Thread_Control *lowest_ready = NULL;
116  Chain_Control *scheduled = &self->Scheduled;
117
118  if ( !_Chain_Is_empty( scheduled ) ) {
119    lowest_ready = (Thread_Control *) _Chain_Last( scheduled );
120  }
121
122  return lowest_ready;
123}
124
125static inline void _Scheduler_SMP_Enqueue_ordered(
126  Scheduler_SMP_Context *self,
127  Thread_Control *thread,
128  Chain_Node_order order,
129  Scheduler_SMP_Get_highest_ready get_highest_ready,
130  Scheduler_SMP_Insert insert_ready,
131  Scheduler_SMP_Insert insert_scheduled,
132  Scheduler_SMP_Move move_from_ready_to_scheduled,
133  Scheduler_SMP_Move move_from_scheduled_to_ready
134)
135{
136  if ( thread->is_in_the_air ) {
137    Thread_Control *highest_ready = ( *get_highest_ready )( self );
138
139    thread->is_in_the_air = false;
140
141    /*
142     * The thread has been extracted from the scheduled chain.  We have to
143     * place it now on the scheduled or ready chain.
144     *
145     * NOTE: Do not exchange parameters to do the negation of the order check.
146     */
147    if (
148      highest_ready != NULL
149        && !( *order )( &thread->Object.Node, &highest_ready->Object.Node )
150    ) {
151      _Scheduler_SMP_Allocate_processor( highest_ready, thread );
152
153      ( *insert_ready )( self, thread );
154      ( *move_from_ready_to_scheduled )( self, highest_ready );
155    } else {
156      thread->is_scheduled = true;
157
158      ( *insert_scheduled )( self, thread );
159    }
160  } else {
161    Thread_Control *lowest_scheduled = _Scheduler_SMP_Get_lowest_scheduled( self );
162
163    /*
164     * The scheduled chain is empty if nested interrupts change the priority of
165     * all scheduled threads.  These threads are in the air.
166     */
167    if (
168      lowest_scheduled != NULL
169        && ( *order )( &thread->Object.Node, &lowest_scheduled->Object.Node )
170    ) {
171      _Scheduler_SMP_Allocate_processor( thread, lowest_scheduled );
172
173      ( *insert_scheduled )( self, thread );
174      ( *move_from_scheduled_to_ready )( self, lowest_scheduled );
175    } else {
176      ( *insert_ready )( self, thread );
177    }
178  }
179}
180
181static inline void _Scheduler_SMP_Schedule_highest_ready(
182  Scheduler_SMP_Context *self,
183  Thread_Control *victim,
184  Scheduler_SMP_Get_highest_ready get_highest_ready,
185  Scheduler_SMP_Move move_from_ready_to_scheduled
186)
187{
188  Thread_Control *highest_ready = ( *get_highest_ready )( self );
189
190  _Scheduler_SMP_Allocate_processor( highest_ready, victim );
191
192  ( *move_from_ready_to_scheduled )( self, highest_ready );
193}
194
195static inline void _Scheduler_SMP_Schedule(
196  Scheduler_SMP_Context *self,
197  Thread_Control *thread,
198  Scheduler_SMP_Get_highest_ready get_highest_ready,
199  Scheduler_SMP_Move move_from_ready_to_scheduled
200)
201{
202  if ( thread->is_in_the_air ) {
203    thread->is_in_the_air = false;
204
205    _Scheduler_SMP_Schedule_highest_ready(
206      self,
207      thread,
208      get_highest_ready,
209      move_from_ready_to_scheduled
210    );
211  }
212}
213
214static inline void _Scheduler_SMP_Block(
215  Scheduler_SMP_Context *self,
216  Thread_Control *thread,
217  Scheduler_SMP_Extract extract,
218  Scheduler_SMP_Get_highest_ready get_highest_ready,
219  Scheduler_SMP_Move move_from_ready_to_scheduled
220)
221{
222  ( *extract )( self, thread );
223
224  _Scheduler_SMP_Schedule(
225    self,
226    thread,
227    get_highest_ready,
228    move_from_ready_to_scheduled
229  );
230}
231
232static inline void _Scheduler_SMP_Extract(
233  Scheduler_SMP_Context *self,
234  Thread_Control *thread,
235  Scheduler_SMP_Extract extract
236)
237{
238  ( *extract )( self, thread );
239}
240
241static inline void _Scheduler_SMP_Insert_scheduled_lifo(
242  Scheduler_SMP_Context *self,
243  Thread_Control *thread
244)
245{
246  _Chain_Insert_ordered_unprotected(
247    &self->Scheduled,
248    &thread->Object.Node,
249    _Scheduler_simple_Insert_priority_lifo_order
250  );
251}
252
253static inline void _Scheduler_SMP_Insert_scheduled_fifo(
254  Scheduler_SMP_Context *self,
255  Thread_Control *thread
256)
257{
258  _Chain_Insert_ordered_unprotected(
259    &self->Scheduled,
260    &thread->Object.Node,
261    _Scheduler_simple_Insert_priority_fifo_order
262  );
263}
264
265static inline void _Scheduler_SMP_Start_idle(
266  Scheduler_SMP_Context *self,
267  Thread_Control *thread,
268  Per_CPU_Control *cpu
269)
270{
271  thread->is_scheduled = true;
272  _Thread_Set_CPU( thread, cpu );
273  _Chain_Append_unprotected( &self->Scheduled, &thread->Object.Node );
274}
275
276/** @} */
277
278#ifdef __cplusplus
279}
280#endif /* __cplusplus */
281
282#endif /* _RTEMS_SCORE_SCHEDULERSMPIMPL_H */
Note: See TracBrowser for help on using the repository browser.