source: rtems/cpukit/score/include/rtems/score/schedulerimpl.h @ beab7329

4.115
Last change on this file since beab7329 was beab7329, checked in by Sebastian Huber <sebastian.huber@…>, on 05/13/14 at 14:03:05

score: Introduce scheduler nodes

Rename scheduler per-thread information into scheduler nodes using
Scheduler_Node as the base type. Use inheritance for specialized
schedulers.

Move the scheduler specific states from the thread control block into
the scheduler node structure.

Validate the SMP scheduler node state transitions in case RTEMS_DEBUG is
defined.

  • Property mode set to 100644
File size: 16.2 KB
Line 
1/**
2 * @file
3 *
4 * @brief Inlined Routines Associated with the Manipulation of the Scheduler
5 *
6 * This inline file contains all of the inlined routines associated with
7 * the manipulation of the scheduler.
8 */
9
10/*
11 *  Copyright (C) 2010 Gedare Bloom.
12 *  Copyright (C) 2011 On-Line Applications Research Corporation (OAR).
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#ifndef _RTEMS_SCORE_SCHEDULERIMPL_H
20#define _RTEMS_SCORE_SCHEDULERIMPL_H
21
22#include <rtems/score/scheduler.h>
23#include <rtems/score/cpusetimpl.h>
24#include <rtems/score/smpimpl.h>
25#include <rtems/score/threadimpl.h>
26
27#ifdef __cplusplus
28extern "C" {
29#endif
30
31/**
32 * @addtogroup ScoreScheduler
33 */
34/**@{**/
35
36/**
37 *  @brief Initializes the scheduler to the policy chosen by the user.
38 *
39 *  This routine initializes the scheduler to the policy chosen by the user
40 *  through confdefs, or to the priority scheduler with ready chains by
41 *  default.
42 */
43void _Scheduler_Handler_initialization( void );
44
45RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU_index(
46  uint32_t cpu_index
47)
48{
49#if defined(RTEMS_SMP)
50  return _Scheduler_Assignments[ cpu_index ].scheduler;
51#else
52  (void) cpu_index;
53
54  return &_Scheduler_Table[ 0 ];
55#endif
56}
57
58RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU(
59  const Per_CPU_Control *cpu
60)
61{
62  uint32_t cpu_index = _Per_CPU_Get_index( cpu );
63
64  return _Scheduler_Get_by_CPU_index( cpu_index );
65}
66
67/**
68 * The preferred method to add a new scheduler is to define the jump table
69 * entries and add a case to the _Scheduler_Initialize routine.
70 *
71 * Generic scheduling implementations that rely on the ready queue only can
72 * be found in the _Scheduler_queue_XXX functions.
73 */
74
75/*
76 * Passing the Scheduler_Control* to these functions allows for multiple
77 * scheduler's to exist simultaneously, which could be useful on an SMP
78 * system.  Then remote Schedulers may be accessible.  How to protect such
79 * accesses remains an open problem.
80 */
81
82/**
83 * @brief Scheduler schedule.
84 *
85 * This kernel routine implements the scheduling decision logic for
86 * the scheduler. It does NOT dispatch.
87 *
88 * @param[in] the_thread The thread which state changed previously.
89 */
90RTEMS_INLINE_ROUTINE void _Scheduler_Schedule(
91  const Scheduler_Control *scheduler,
92  Thread_Control          *the_thread
93)
94{
95  ( *scheduler->Operations.schedule )( scheduler, the_thread );
96}
97
98/**
99 * @brief Scheduler yield with a particular thread.
100 *
101 * This routine is invoked when a thread wishes to voluntarily transfer control
102 * of the processor to another thread.
103 *
104 * @param[in] the_thread The yielding thread.
105 */
106RTEMS_INLINE_ROUTINE void _Scheduler_Yield(
107  const Scheduler_Control *scheduler,
108  Thread_Control          *the_thread
109)
110{
111  ( *scheduler->Operations.yield )( scheduler, the_thread );
112}
113
114/**
115 * @brief Scheduler block.
116 *
117 * This routine removes @a the_thread from the scheduling decision for
118 * the scheduler. The primary task is to remove the thread from the
119 * ready queue.  It performs any necessary schedulering operations
120 * including the selection of a new heir thread.
121 */
122RTEMS_INLINE_ROUTINE void _Scheduler_Block(
123  const Scheduler_Control *scheduler,
124  Thread_Control               *the_thread
125)
126{
127  ( *scheduler->Operations.block )( scheduler, the_thread );
128}
129
130/**
131 * @brief Scheduler unblock.
132 *
133 * This routine adds @a the_thread to the scheduling decision for
134 * the scheduler.  The primary task is to add the thread to the
135 * ready queue per the schedulering policy and update any appropriate
136 * scheduling variables, for example the heir thread.
137 */
138RTEMS_INLINE_ROUTINE void _Scheduler_Unblock(
139  const Scheduler_Control *scheduler,
140  Thread_Control          *the_thread
141)
142{
143  ( *scheduler->Operations.unblock )( scheduler, the_thread );
144}
145
146/**
147 * @brief Scheduler allocate.
148 *
149 * This routine allocates @a the_thread->scheduler
150 */
151RTEMS_INLINE_ROUTINE bool _Scheduler_Allocate(
152  const Scheduler_Control *scheduler,
153  Thread_Control          *the_thread
154)
155{
156  return ( *scheduler->Operations.allocate )( scheduler, the_thread );
157}
158
159/**
160 * @brief Scheduler free.
161 *
162 * This routine frees @a the_thread->scheduler
163 */
164RTEMS_INLINE_ROUTINE void _Scheduler_Free(
165  const Scheduler_Control *scheduler,
166  Thread_Control          *the_thread
167)
168{
169  ( *scheduler->Operations.free )( scheduler, the_thread );
170}
171
172/**
173 * @brief Scheduler update.
174 *
175 * This routine updates @a the_thread->scheduler
176 */
177RTEMS_INLINE_ROUTINE void _Scheduler_Update(
178  const Scheduler_Control *scheduler,
179  Thread_Control          *the_thread
180)
181{
182  ( *scheduler->Operations.update )( scheduler, the_thread );
183}
184
185/**
186 * @brief Enqueues a thread as the last of its priority group.
187 *
188 * @param[in] scheduler The scheduler instance.
189 * @param[in] the_thread The thread to enqueue.
190 */
191RTEMS_INLINE_ROUTINE void _Scheduler_Enqueue(
192  const Scheduler_Control *scheduler,
193  Thread_Control          *the_thread
194)
195{
196  ( *scheduler->Operations.enqueue )( scheduler, the_thread );
197}
198
199/**
200 * @brief Enqueues a thread as the first of its priority group.
201 *
202 * @param[in] scheduler The scheduler instance.
203 * @param[in] the_thread The thread to enqueue.
204 */
205RTEMS_INLINE_ROUTINE void _Scheduler_Enqueue_first(
206  const Scheduler_Control *scheduler,
207  Thread_Control          *the_thread
208)
209{
210  ( *scheduler->Operations.enqueue_first )( scheduler, the_thread );
211}
212
213/**
214 * @brief Scheduler extract.
215 *
216 * This routine extract @a the_thread->scheduler
217 */
218RTEMS_INLINE_ROUTINE void _Scheduler_Extract(
219  const Scheduler_Control *scheduler,
220  Thread_Control          *the_thread
221)
222{
223  ( *scheduler->Operations.extract )( scheduler, the_thread );
224}
225
226/**
227 * @brief Compares two priority values.
228 *
229 * @param[in] scheduler The scheduler instance.
230 * @param[in] p1 The first priority value.
231 * @param[in] p2 The second priority value.
232 *
233 * @retval negative The value @a p1 encodes a lower priority than @a p2 in the
234 * intuitive sense of priority.
235 * @retval 0 The priorities @a p1 and @a p2 are equal.
236 * @retval positive The value @a p1 encodes a higher priority than @a p2 in the
237 * intuitive sense of priority.
238 *
239 * @see _Scheduler_Is_priority_lower_than() and
240 * _Scheduler_Is_priority_higher_than().
241 */
242RTEMS_INLINE_ROUTINE int _Scheduler_Priority_compare(
243  const Scheduler_Control *scheduler,
244  Priority_Control         p1,
245  Priority_Control         p2
246)
247{
248  return ( *scheduler->Operations.priority_compare )( p1, p2 );
249}
250
251/**
252 * @brief Scheduler release job.
253 *
254 * This routine is called when a new period of task is issued.
255 */
256RTEMS_INLINE_ROUTINE void _Scheduler_Release_job(
257  const Scheduler_Control *scheduler,
258  Thread_Control          *the_thread,
259  uint32_t                 length
260)
261{
262  ( *scheduler->Operations.release_job )( scheduler, the_thread, length );
263}
264
265/**
266 * @brief Scheduler method invoked at each clock tick.
267 *
268 * This method is invoked at each clock tick to allow the scheduler
269 * implementation to perform any activities required.  For the
270 * scheduler which support standard RTEMS features, this includes
271 * time-slicing management.
272 */
273RTEMS_INLINE_ROUTINE void _Scheduler_Tick( void )
274{
275  uint32_t cpu_count = _SMP_Get_processor_count();
276  uint32_t cpu_index;
277
278  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
279    const Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
280    const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu );
281
282    if ( scheduler != NULL ) {
283      ( *scheduler->Operations.tick )( scheduler, cpu->executing );
284    }
285  }
286}
287
288/**
289 * @brief Starts the idle thread for a particular processor.
290 *
291 * @param[in,out] the_thread The idle thread for the processor.
292 * @parma[in,out] processor The processor for the idle thread.
293 *
294 * @see _Thread_Create_idle().
295 */
296RTEMS_INLINE_ROUTINE void _Scheduler_Start_idle(
297  const Scheduler_Control *scheduler,
298  Thread_Control          *the_thread,
299  Per_CPU_Control         *cpu
300)
301{
302  ( *scheduler->Operations.start_idle )( scheduler, the_thread, cpu );
303}
304
305#if defined(RTEMS_SMP)
306RTEMS_INLINE_ROUTINE const Scheduler_Assignment *_Scheduler_Get_assignment(
307  uint32_t cpu_index
308)
309{
310  return &_Scheduler_Assignments[ cpu_index ];
311}
312
313RTEMS_INLINE_ROUTINE bool _Scheduler_Is_mandatory_processor(
314  const Scheduler_Assignment *assignment
315)
316{
317  return (assignment->attributes & SCHEDULER_ASSIGN_PROCESSOR_MANDATORY) != 0;
318}
319
320RTEMS_INLINE_ROUTINE bool _Scheduler_Should_start_processor(
321  const Scheduler_Assignment *assignment
322)
323{
324  return assignment->scheduler != NULL;
325}
326#endif /* defined(RTEMS_SMP) */
327
328RTEMS_INLINE_ROUTINE bool _Scheduler_Has_processor_ownership(
329  const Scheduler_Control *scheduler,
330  uint32_t cpu_index
331)
332{
333#if defined(RTEMS_SMP)
334  const Scheduler_Assignment *assignment =
335    _Scheduler_Get_assignment( cpu_index );
336
337  return assignment->scheduler == scheduler;
338#else
339  (void) scheduler;
340  (void) cpu_index;
341
342  return true;
343#endif
344}
345
346RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get(
347  Thread_Control *the_thread
348)
349{
350#if defined(RTEMS_SMP)
351  return the_thread->scheduler;
352#else
353  (void) the_thread;
354
355  return &_Scheduler_Table[ 0 ];
356#endif
357}
358
359RTEMS_INLINE_ROUTINE void _Scheduler_Set(
360  const Scheduler_Control *scheduler,
361  Thread_Control          *the_thread
362)
363{
364#if defined(RTEMS_SMP)
365  const Scheduler_Control *current_scheduler = _Scheduler_Get( the_thread );
366
367  if ( current_scheduler != scheduler ) {
368    _Thread_Set_state( the_thread, STATES_MIGRATING );
369    _Scheduler_Free( _Scheduler_Get( the_thread ), the_thread );
370    the_thread->scheduler = scheduler;
371    _Scheduler_Allocate( scheduler, the_thread );
372    _Scheduler_Update( scheduler, the_thread );
373    _Thread_Clear_state( the_thread, STATES_MIGRATING );
374  }
375#else
376  (void) scheduler;
377#endif
378}
379
380#if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
381
382RTEMS_INLINE_ROUTINE void _Scheduler_Get_processor_set(
383  const Scheduler_Control *scheduler,
384  size_t                   cpusetsize,
385  cpu_set_t               *cpuset
386)
387{
388  uint32_t cpu_count = _SMP_Get_processor_count();
389  uint32_t cpu_index;
390
391  CPU_ZERO_S( cpusetsize, cpuset );
392
393  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
394#if defined(RTEMS_SMP)
395    if ( _Scheduler_Has_processor_ownership( scheduler, cpu_index ) ) {
396      CPU_SET_S( (int) cpu_index, cpusetsize, cpuset );
397    }
398#else
399    (void) scheduler;
400
401    CPU_SET_S( (int) cpu_index, cpusetsize, cpuset );
402#endif
403  }
404}
405
406RTEMS_INLINE_ROUTINE bool _Scheduler_default_Get_affinity_body(
407  const Scheduler_Control *scheduler,
408  Thread_Control          *the_thread,
409  size_t                   cpusetsize,
410  cpu_set_t               *cpuset
411)
412{
413  (void) the_thread;
414
415  _Scheduler_Get_processor_set( scheduler, cpusetsize, cpuset );
416
417  return true;
418}
419
420bool _Scheduler_Get_affinity(
421  const Scheduler_Control *scheduler,
422  Thread_Control          *the_thread,
423  size_t                   cpusetsize,
424  cpu_set_t               *cpuset
425);
426
427RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body(
428  const Scheduler_Control *scheduler,
429  Thread_Control          *the_thread,
430  size_t                   cpusetsize,
431  const cpu_set_t         *cpuset
432)
433{
434  size_t   cpu_max   = _CPU_set_Maximum_CPU_count( cpusetsize );
435  uint32_t cpu_count = _SMP_Get_processor_count();
436  uint32_t cpu_index;
437  bool     ok = true;
438
439  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
440#if defined(RTEMS_SMP)
441    const Scheduler_Control *scheduler_of_cpu =
442      _Scheduler_Get_by_CPU_index( cpu_index );
443
444    ok = ok
445      && ( ( CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset )
446          && scheduler == scheduler_of_cpu )
447        || ( !CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset )
448          && scheduler != scheduler_of_cpu ) );
449#else
450    (void) scheduler;
451
452    ok = ok && CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset );
453#endif
454  }
455
456  for ( ; cpu_index < cpu_max ; ++cpu_index ) {
457    ok = ok && !CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset );
458  }
459
460  _Scheduler_Set( scheduler, the_thread );
461
462  return ok;
463}
464
465bool _Scheduler_Set_affinity(
466  Thread_Control          *the_thread,
467  size_t                   cpusetsize,
468  const cpu_set_t         *cpuset
469);
470
471#endif /* defined(__RTEMS_HAVE_SYS_CPUSET_H__) */
472
473RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir(
474  Thread_Control *heir,
475  bool force_dispatch
476)
477{
478  Thread_Control *executing = _Thread_Executing;
479
480  _Thread_Heir = heir;
481
482  if ( executing != heir && ( force_dispatch || executing->is_preemptible ) )
483    _Thread_Dispatch_necessary = true;
484}
485
486RTEMS_INLINE_ROUTINE void _Scheduler_Generic_block(
487  const Scheduler_Control *scheduler,
488  Thread_Control          *the_thread,
489  void                  ( *extract )(
490                             const Scheduler_Control *,
491                             Thread_Control * ),
492  void                  ( *schedule )(
493                             const Scheduler_Control *,
494                             Thread_Control *,
495                             bool )
496)
497{
498  ( *extract )( scheduler, the_thread );
499
500  /* TODO: flash critical section? */
501
502  if ( _Thread_Is_executing( the_thread ) || _Thread_Is_heir( the_thread ) ) {
503    ( *schedule )( scheduler, the_thread, true );
504  }
505}
506
507/**
508 * @brief Returns true if @a p1 encodes a lower priority than @a p2 in the
509 * intuitive sense of priority.
510 */
511RTEMS_INLINE_ROUTINE bool _Scheduler_Is_priority_lower_than(
512  const Scheduler_Control *scheduler,
513  Priority_Control         p1,
514  Priority_Control         p2
515)
516{
517  return _Scheduler_Priority_compare( scheduler, p1,  p2 ) < 0;
518}
519
520/**
521 * @brief Returns true if @a p1 encodes a higher priority than @a p2 in the
522 * intuitive sense of priority.
523 */
524RTEMS_INLINE_ROUTINE bool _Scheduler_Is_priority_higher_than(
525  const Scheduler_Control *scheduler,
526  Priority_Control         p1,
527  Priority_Control         p2
528)
529{
530  return _Scheduler_Priority_compare( scheduler, p1,  p2 ) > 0;
531}
532
533/**
534 * @brief Returns the priority encoding @a p1 or @a p2 with the higher priority
535 * in the intuitive sense of priority.
536 */
537RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Highest_priority_of_two(
538  const Scheduler_Control *scheduler,
539  Priority_Control         p1,
540  Priority_Control         p2
541)
542{
543  return _Scheduler_Is_priority_higher_than( scheduler, p1, p2 ) ? p1 : p2;
544}
545
546/**
547 * @brief Sets the thread priority to @a priority if it is higher than the
548 * current priority of the thread in the intuitive sense of priority.
549 */
550RTEMS_INLINE_ROUTINE void _Scheduler_Set_priority_if_higher(
551  const Scheduler_Control *scheduler,
552  Thread_Control          *the_thread,
553  Priority_Control         priority
554)
555{
556  Priority_Control current = the_thread->current_priority;
557
558  if ( _Scheduler_Is_priority_higher_than( scheduler, priority, current ) ) {
559    _Thread_Set_priority( the_thread, priority );
560  }
561}
562
563/**
564 * @brief Changes the thread priority to @a priority if it is higher than the
565 * current priority of the thread in the intuitive sense of priority.
566 */
567RTEMS_INLINE_ROUTINE void _Scheduler_Change_priority_if_higher(
568  const Scheduler_Control *scheduler,
569  Thread_Control          *the_thread,
570  Priority_Control         priority,
571  bool                     prepend_it
572)
573{
574  Priority_Control current = the_thread->current_priority;
575
576  if ( _Scheduler_Is_priority_higher_than( scheduler, priority, current ) ) {
577    _Thread_Change_priority( the_thread, priority, prepend_it );
578  }
579}
580
581RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_processor_count(
582  const Scheduler_Control *scheduler
583)
584{
585#if defined(RTEMS_SMP)
586  return scheduler->context->processor_count;
587#else
588  (void) scheduler;
589
590  return 1;
591#endif
592}
593
594RTEMS_INLINE_ROUTINE Objects_Id _Scheduler_Build_id( uint32_t scheduler_index )
595{
596  return _Objects_Build_id(
597    OBJECTS_FAKE_OBJECTS_API,
598    OBJECTS_FAKE_OBJECTS_SCHEDULERS,
599    _Objects_Local_node,
600    scheduler_index + 1
601  );
602}
603
604RTEMS_INLINE_ROUTINE bool _Scheduler_Get_by_id(
605  Objects_Id                id,
606  const Scheduler_Control **scheduler_p
607)
608{
609  uint32_t minimum_id = _Scheduler_Build_id( 0 );
610  uint32_t index = id - minimum_id;
611  const Scheduler_Control *scheduler = &_Scheduler_Table[ index ];
612
613  *scheduler_p = scheduler;
614
615  return index < _Scheduler_Count
616    && _Scheduler_Get_processor_count( scheduler ) > 0;
617}
618
619RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index(
620  const Scheduler_Control *scheduler
621)
622{
623  return (uint32_t) (scheduler - &_Scheduler_Table[ 0 ]);
624}
625
626RTEMS_INLINE_ROUTINE Scheduler_Node *_Scheduler_Node_get(
627  Thread_Control *the_thread
628)
629{
630  return the_thread->scheduler_node;
631}
632
633/** @} */
634
635#ifdef __cplusplus
636}
637#endif
638
639#endif
640/* end of include file */
Note: See TracBrowser for help on using the repository browser.