source: rtems/cpukit/score/include/rtems/score/schedulerimpl.h @ 2d36931

4.11
Last change on this file since 2d36931 was 2d36931, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 11, 2014 at 9:03:25 AM

score: Collect scheduler related fields in TCB

Add Thread_Scheduler_control to collect scheduler related fields of the
TCB.

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