source: rtems/cpukit/score/include/rtems/score/schedulerimpl.h @ 25f5730f

4.11
Last change on this file since 25f5730f was 25f5730f, checked in by Sebastian Huber <sebastian.huber@…>, on May 28, 2014 at 4:11:51 PM

score: _Scheduler_Set_affinity()

Do not change the scheduler with this function. Documentation. Coding
style.

  • Property mode set to 100644
File size: 16.3 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 Propagates a priority change of a thread to the scheduler.
148 *
149 * The caller must ensure that the thread is in the ready state.  The caller
150 * must ensure that the priority value actually changed and is not equal to the
151 * current priority value.
152 *
153 * @param[in] scheduler The scheduler instance.
154 * @param[in] the_thread The thread changing its priority.
155 * @param[in] new_priority The new thread priority.
156 * @param[in] prepend_it In case this is true, then enqueue the thread as the
157 * first of its priority group, otherwise enqueue the thread as the last of its
158 * priority group.
159 */
160RTEMS_INLINE_ROUTINE void _Scheduler_Change_priority(
161  const Scheduler_Control *scheduler,
162  Thread_Control          *the_thread,
163  Priority_Control         new_priority,
164  bool                     prepend_it
165)
166{
167  ( *scheduler->Operations.change_priority )(
168    scheduler,
169    the_thread,
170    new_priority,
171    prepend_it
172  );
173}
174
175/**
176 * @brief Scheduler allocate.
177 *
178 * This routine allocates @a the_thread->scheduler
179 */
180RTEMS_INLINE_ROUTINE bool _Scheduler_Allocate(
181  const Scheduler_Control *scheduler,
182  Thread_Control          *the_thread
183)
184{
185  return ( *scheduler->Operations.allocate )( scheduler, the_thread );
186}
187
188/**
189 * @brief Scheduler free.
190 *
191 * This routine frees @a the_thread->scheduler
192 */
193RTEMS_INLINE_ROUTINE void _Scheduler_Free(
194  const Scheduler_Control *scheduler,
195  Thread_Control          *the_thread
196)
197{
198  ( *scheduler->Operations.free )( scheduler, the_thread );
199}
200
201/**
202 * @brief Scheduler update.
203 *
204 * This routine updates @a the_thread->scheduler
205 */
206RTEMS_INLINE_ROUTINE void _Scheduler_Update(
207  const Scheduler_Control *scheduler,
208  Thread_Control          *the_thread
209)
210{
211  ( *scheduler->Operations.update )( scheduler, the_thread );
212}
213
214/**
215 * @brief Compares two priority values.
216 *
217 * @param[in] scheduler The scheduler instance.
218 * @param[in] p1 The first priority value.
219 * @param[in] p2 The second priority value.
220 *
221 * @retval negative The value @a p1 encodes a lower priority than @a p2 in the
222 * intuitive sense of priority.
223 * @retval 0 The priorities @a p1 and @a p2 are equal.
224 * @retval positive The value @a p1 encodes a higher priority than @a p2 in the
225 * intuitive sense of priority.
226 *
227 * @see _Scheduler_Is_priority_lower_than() and
228 * _Scheduler_Is_priority_higher_than().
229 */
230RTEMS_INLINE_ROUTINE int _Scheduler_Priority_compare(
231  const Scheduler_Control *scheduler,
232  Priority_Control         p1,
233  Priority_Control         p2
234)
235{
236  return ( *scheduler->Operations.priority_compare )( p1, p2 );
237}
238
239/**
240 * @brief Scheduler release job.
241 *
242 * This routine is called when a new period of task is issued.
243 */
244RTEMS_INLINE_ROUTINE void _Scheduler_Release_job(
245  const Scheduler_Control *scheduler,
246  Thread_Control          *the_thread,
247  uint32_t                 length
248)
249{
250  ( *scheduler->Operations.release_job )( scheduler, the_thread, length );
251}
252
253/**
254 * @brief Scheduler method invoked at each clock tick.
255 *
256 * This method is invoked at each clock tick to allow the scheduler
257 * implementation to perform any activities required.  For the
258 * scheduler which support standard RTEMS features, this includes
259 * time-slicing management.
260 */
261RTEMS_INLINE_ROUTINE void _Scheduler_Tick( void )
262{
263  uint32_t cpu_count = _SMP_Get_processor_count();
264  uint32_t cpu_index;
265
266  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
267    const Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
268    const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu );
269
270    if ( scheduler != NULL ) {
271      ( *scheduler->Operations.tick )( scheduler, cpu->executing );
272    }
273  }
274}
275
276/**
277 * @brief Starts the idle thread for a particular processor.
278 *
279 * @param[in,out] the_thread The idle thread for the processor.
280 * @parma[in,out] processor The processor for the idle thread.
281 *
282 * @see _Thread_Create_idle().
283 */
284RTEMS_INLINE_ROUTINE void _Scheduler_Start_idle(
285  const Scheduler_Control *scheduler,
286  Thread_Control          *the_thread,
287  Per_CPU_Control         *cpu
288)
289{
290  ( *scheduler->Operations.start_idle )( scheduler, the_thread, cpu );
291}
292
293#if defined(RTEMS_SMP)
294RTEMS_INLINE_ROUTINE const Scheduler_Assignment *_Scheduler_Get_assignment(
295  uint32_t cpu_index
296)
297{
298  return &_Scheduler_Assignments[ cpu_index ];
299}
300
301RTEMS_INLINE_ROUTINE bool _Scheduler_Is_mandatory_processor(
302  const Scheduler_Assignment *assignment
303)
304{
305  return (assignment->attributes & SCHEDULER_ASSIGN_PROCESSOR_MANDATORY) != 0;
306}
307
308RTEMS_INLINE_ROUTINE bool _Scheduler_Should_start_processor(
309  const Scheduler_Assignment *assignment
310)
311{
312  return assignment->scheduler != NULL;
313}
314#endif /* defined(RTEMS_SMP) */
315
316RTEMS_INLINE_ROUTINE bool _Scheduler_Has_processor_ownership(
317  const Scheduler_Control *scheduler,
318  uint32_t cpu_index
319)
320{
321#if defined(RTEMS_SMP)
322  const Scheduler_Assignment *assignment =
323    _Scheduler_Get_assignment( cpu_index );
324
325  return assignment->scheduler == scheduler;
326#else
327  (void) scheduler;
328  (void) cpu_index;
329
330  return true;
331#endif
332}
333
334RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get(
335  const Thread_Control *the_thread
336)
337{
338#if defined(RTEMS_SMP)
339  return the_thread->scheduler;
340#else
341  (void) the_thread;
342
343  return &_Scheduler_Table[ 0 ];
344#endif
345}
346
347RTEMS_INLINE_ROUTINE void _Scheduler_Set(
348  const Scheduler_Control *scheduler,
349  Thread_Control          *the_thread
350)
351{
352#if defined(RTEMS_SMP)
353  const Scheduler_Control *current_scheduler = _Scheduler_Get( the_thread );
354
355  if ( current_scheduler != scheduler ) {
356    _Thread_Set_state( the_thread, STATES_MIGRATING );
357    _Scheduler_Free( current_scheduler, the_thread );
358    the_thread->scheduler = scheduler;
359    _Scheduler_Allocate( scheduler, the_thread );
360    _Scheduler_Update( scheduler, the_thread );
361    _Thread_Clear_state( the_thread, STATES_MIGRATING );
362  }
363#else
364  (void) scheduler;
365#endif
366}
367
368#if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
369
370RTEMS_INLINE_ROUTINE void _Scheduler_Get_processor_set(
371  const Scheduler_Control *scheduler,
372  size_t                   cpusetsize,
373  cpu_set_t               *cpuset
374)
375{
376  uint32_t cpu_count = _SMP_Get_processor_count();
377  uint32_t cpu_index;
378
379  CPU_ZERO_S( cpusetsize, cpuset );
380
381  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
382#if defined(RTEMS_SMP)
383    if ( _Scheduler_Has_processor_ownership( scheduler, cpu_index ) ) {
384      CPU_SET_S( (int) cpu_index, cpusetsize, cpuset );
385    }
386#else
387    (void) scheduler;
388
389    CPU_SET_S( (int) cpu_index, cpusetsize, cpuset );
390#endif
391  }
392}
393
394RTEMS_INLINE_ROUTINE bool _Scheduler_default_Get_affinity_body(
395  const Scheduler_Control *scheduler,
396  Thread_Control          *the_thread,
397  size_t                   cpusetsize,
398  cpu_set_t               *cpuset
399)
400{
401  (void) the_thread;
402
403  _Scheduler_Get_processor_set( scheduler, cpusetsize, cpuset );
404
405  return true;
406}
407
408bool _Scheduler_Get_affinity(
409  Thread_Control *the_thread,
410  size_t          cpusetsize,
411  cpu_set_t      *cpuset
412);
413
414RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body(
415  const Scheduler_Control *scheduler,
416  Thread_Control          *the_thread,
417  size_t                   cpusetsize,
418  const cpu_set_t         *cpuset
419)
420{
421  uint32_t cpu_count = _SMP_Get_processor_count();
422  uint32_t cpu_index;
423  bool     ok = true;
424
425  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
426#if defined(RTEMS_SMP)
427    const Scheduler_Control *scheduler_of_cpu =
428      _Scheduler_Get_by_CPU_index( cpu_index );
429
430    ok = ok
431      && ( CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset )
432        || ( !CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset )
433          && scheduler != scheduler_of_cpu ) );
434#else
435    (void) scheduler;
436
437    ok = ok && CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset );
438#endif
439  }
440
441  return ok;
442}
443
444bool _Scheduler_Set_affinity(
445  Thread_Control          *the_thread,
446  size_t                   cpusetsize,
447  const cpu_set_t         *cpuset
448);
449
450#endif /* defined(__RTEMS_HAVE_SYS_CPUSET_H__) */
451
452RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir(
453  Thread_Control *heir,
454  bool force_dispatch
455)
456{
457  Thread_Control *executing = _Thread_Executing;
458
459  _Thread_Heir = heir;
460
461  if ( executing != heir && ( force_dispatch || executing->is_preemptible ) )
462    _Thread_Dispatch_necessary = true;
463}
464
465RTEMS_INLINE_ROUTINE void _Scheduler_Generic_block(
466  const Scheduler_Control *scheduler,
467  Thread_Control          *the_thread,
468  void                  ( *extract )(
469                             const Scheduler_Control *,
470                             Thread_Control * ),
471  void                  ( *schedule )(
472                             const Scheduler_Control *,
473                             Thread_Control *,
474                             bool )
475)
476{
477  ( *extract )( scheduler, the_thread );
478
479  /* TODO: flash critical section? */
480
481  if ( _Thread_Is_executing( the_thread ) || _Thread_Is_heir( the_thread ) ) {
482    ( *schedule )( scheduler, the_thread, true );
483  }
484}
485
486/**
487 * @brief Returns true if @a p1 encodes a lower priority than @a p2 in the
488 * intuitive sense of priority.
489 */
490RTEMS_INLINE_ROUTINE bool _Scheduler_Is_priority_lower_than(
491  const Scheduler_Control *scheduler,
492  Priority_Control         p1,
493  Priority_Control         p2
494)
495{
496  return _Scheduler_Priority_compare( scheduler, p1,  p2 ) < 0;
497}
498
499/**
500 * @brief Returns true if @a p1 encodes a higher priority than @a p2 in the
501 * intuitive sense of priority.
502 */
503RTEMS_INLINE_ROUTINE bool _Scheduler_Is_priority_higher_than(
504  const Scheduler_Control *scheduler,
505  Priority_Control         p1,
506  Priority_Control         p2
507)
508{
509  return _Scheduler_Priority_compare( scheduler, p1,  p2 ) > 0;
510}
511
512/**
513 * @brief Returns the priority encoding @a p1 or @a p2 with the higher priority
514 * in the intuitive sense of priority.
515 */
516RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Highest_priority_of_two(
517  const Scheduler_Control *scheduler,
518  Priority_Control         p1,
519  Priority_Control         p2
520)
521{
522  return _Scheduler_Is_priority_higher_than( scheduler, p1, p2 ) ? p1 : p2;
523}
524
525/**
526 * @brief Sets the thread priority to @a priority if it is higher than the
527 * current priority of the thread in the intuitive sense of priority.
528 */
529RTEMS_INLINE_ROUTINE void _Scheduler_Set_priority_if_higher(
530  const Scheduler_Control *scheduler,
531  Thread_Control          *the_thread,
532  Priority_Control         priority
533)
534{
535  Priority_Control current = the_thread->current_priority;
536
537  if ( _Scheduler_Is_priority_higher_than( scheduler, priority, current ) ) {
538    _Thread_Set_priority( the_thread, priority );
539  }
540}
541
542/**
543 * @brief Changes the thread priority to @a priority if it is higher than the
544 * current priority of the thread in the intuitive sense of priority.
545 */
546RTEMS_INLINE_ROUTINE void _Scheduler_Change_priority_if_higher(
547  const Scheduler_Control *scheduler,
548  Thread_Control          *the_thread,
549  Priority_Control         priority,
550  bool                     prepend_it
551)
552{
553  Priority_Control current = the_thread->current_priority;
554
555  if ( _Scheduler_Is_priority_higher_than( scheduler, priority, current ) ) {
556    _Thread_Change_priority( the_thread, priority, prepend_it );
557  }
558}
559
560RTEMS_INLINE_ROUTINE Scheduler_Context *_Scheduler_Get_context(
561  const Scheduler_Control *scheduler
562)
563{
564  return scheduler->context;
565}
566
567RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_processor_count(
568  const Scheduler_Control *scheduler
569)
570{
571#if defined(RTEMS_SMP)
572  return _Scheduler_Get_context( scheduler )->processor_count;
573#else
574  (void) scheduler;
575
576  return 1;
577#endif
578}
579
580RTEMS_INLINE_ROUTINE Objects_Id _Scheduler_Build_id( uint32_t scheduler_index )
581{
582  return _Objects_Build_id(
583    OBJECTS_FAKE_OBJECTS_API,
584    OBJECTS_FAKE_OBJECTS_SCHEDULERS,
585    _Objects_Local_node,
586    scheduler_index + 1
587  );
588}
589
590RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index_by_id( Objects_Id id )
591{
592  uint32_t minimum_id = _Scheduler_Build_id( 0 );
593
594  return id - minimum_id;
595}
596
597RTEMS_INLINE_ROUTINE bool _Scheduler_Get_by_id(
598  Objects_Id                id,
599  const Scheduler_Control **scheduler_p
600)
601{
602  uint32_t index = _Scheduler_Get_index_by_id( id );
603  const Scheduler_Control *scheduler = &_Scheduler_Table[ index ];
604
605  *scheduler_p = scheduler;
606
607  return index < _Scheduler_Count
608    && _Scheduler_Get_processor_count( scheduler ) > 0;
609}
610
611RTEMS_INLINE_ROUTINE bool _Scheduler_Is_id_valid( Objects_Id id )
612{
613  const Scheduler_Control *scheduler;
614  bool ok = _Scheduler_Get_by_id( id, &scheduler );
615
616  (void) scheduler;
617
618  return ok;
619}
620
621RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index(
622  const Scheduler_Control *scheduler
623)
624{
625  return (uint32_t) (scheduler - &_Scheduler_Table[ 0 ]);
626}
627
628RTEMS_INLINE_ROUTINE Scheduler_Node *_Scheduler_Node_get(
629  Thread_Control *the_thread
630)
631{
632  return the_thread->scheduler_node;
633}
634
635/** @} */
636
637#ifdef __cplusplus
638}
639#endif
640
641#endif
642/* end of include file */
Note: See TracBrowser for help on using the repository browser.