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

4.115
Last change on this file since be3c257 was be3c257, checked in by Sebastian Huber <sebastian.huber@…>, on 06/05/14 at 09:17:26

score: Avoid NULL pointer access

Check that the executing thread is not NULL in _Scheduler_Tick(). It
may be NULL in case the processor has an optional scheduler assigned and
the system was not able to start the processor.

  • Property mode set to 100644
File size: 17.1 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 Initializes a scheduler node.
177 *
178 * The scheduler node contains arbitrary data on function entry.  The caller
179 * must ensure that _Scheduler_Node_destroy() will be called after a
180 * _Scheduler_Node_initialize() before the memory of the scheduler node is
181 * destroyed.
182 *
183 * @param[in] scheduler The scheduler instance.
184 * @param[in] the_thread The thread containing the scheduler node.
185 */
186RTEMS_INLINE_ROUTINE void _Scheduler_Node_initialize(
187  const Scheduler_Control *scheduler,
188  Thread_Control          *the_thread
189)
190{
191  return ( *scheduler->Operations.node_initialize )( scheduler, the_thread );
192}
193
194/**
195 * @brief Destroys a scheduler node.
196 *
197 * The caller must ensure that _Scheduler_Node_destroy() will be called only
198 * after a corresponding _Scheduler_Node_initialize().
199 *
200 * @param[in] scheduler The scheduler instance.
201 * @param[in] the_thread The thread containing the scheduler node.
202 */
203RTEMS_INLINE_ROUTINE void _Scheduler_Node_destroy(
204  const Scheduler_Control *scheduler,
205  Thread_Control          *the_thread
206)
207{
208  ( *scheduler->Operations.node_destroy )( scheduler, the_thread );
209}
210
211/**
212 * @brief Updates the scheduler about a priority change of a not ready thread.
213 *
214 * @param[in] the_thread The thread.
215 * @param[in] new_priority The new priority of the thread.
216 */
217RTEMS_INLINE_ROUTINE void _Scheduler_Update_priority(
218  const Scheduler_Control *scheduler,
219  Thread_Control          *the_thread,
220  Priority_Control         new_priority
221)
222{
223  ( *scheduler->Operations.update_priority )(
224    scheduler,
225    the_thread,
226    new_priority
227  );
228}
229
230/**
231 * @brief Compares two priority values.
232 *
233 * @param[in] scheduler The scheduler instance.
234 * @param[in] p1 The first priority value.
235 * @param[in] p2 The second priority value.
236 *
237 * @retval negative The value @a p1 encodes a lower priority than @a p2 in the
238 * intuitive sense of priority.
239 * @retval 0 The priorities @a p1 and @a p2 are equal.
240 * @retval positive The value @a p1 encodes a higher priority than @a p2 in the
241 * intuitive sense of priority.
242 *
243 * @see _Scheduler_Is_priority_lower_than() and
244 * _Scheduler_Is_priority_higher_than().
245 */
246RTEMS_INLINE_ROUTINE int _Scheduler_Priority_compare(
247  const Scheduler_Control *scheduler,
248  Priority_Control         p1,
249  Priority_Control         p2
250)
251{
252  return ( *scheduler->Operations.priority_compare )( p1, p2 );
253}
254
255/**
256 * @brief Scheduler release job.
257 *
258 * This routine is called when a new period of task is issued.
259 */
260RTEMS_INLINE_ROUTINE void _Scheduler_Release_job(
261  const Scheduler_Control *scheduler,
262  Thread_Control          *the_thread,
263  uint32_t                 length
264)
265{
266  ( *scheduler->Operations.release_job )( scheduler, the_thread, length );
267}
268
269/**
270 * @brief Scheduler method invoked at each clock tick.
271 *
272 * This method is invoked at each clock tick to allow the scheduler
273 * implementation to perform any activities required.  For the
274 * scheduler which support standard RTEMS features, this includes
275 * time-slicing management.
276 */
277RTEMS_INLINE_ROUTINE void _Scheduler_Tick( void )
278{
279  uint32_t cpu_count = _SMP_Get_processor_count();
280  uint32_t cpu_index;
281
282  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
283    const Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
284    const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu );
285    Thread_Control *executing = cpu->executing;
286
287    if ( scheduler != NULL && executing != NULL ) {
288      ( *scheduler->Operations.tick )( scheduler, executing );
289    }
290  }
291}
292
293/**
294 * @brief Starts the idle thread for a particular processor.
295 *
296 * @param[in,out] the_thread The idle thread for the processor.
297 * @parma[in,out] processor The processor for the idle thread.
298 *
299 * @see _Thread_Create_idle().
300 */
301RTEMS_INLINE_ROUTINE void _Scheduler_Start_idle(
302  const Scheduler_Control *scheduler,
303  Thread_Control          *the_thread,
304  Per_CPU_Control         *cpu
305)
306{
307  ( *scheduler->Operations.start_idle )( scheduler, the_thread, cpu );
308}
309
310#if defined(RTEMS_SMP)
311RTEMS_INLINE_ROUTINE const Scheduler_Assignment *_Scheduler_Get_assignment(
312  uint32_t cpu_index
313)
314{
315  return &_Scheduler_Assignments[ cpu_index ];
316}
317
318RTEMS_INLINE_ROUTINE bool _Scheduler_Is_mandatory_processor(
319  const Scheduler_Assignment *assignment
320)
321{
322  return (assignment->attributes & SCHEDULER_ASSIGN_PROCESSOR_MANDATORY) != 0;
323}
324
325RTEMS_INLINE_ROUTINE bool _Scheduler_Should_start_processor(
326  const Scheduler_Assignment *assignment
327)
328{
329  return assignment->scheduler != NULL;
330}
331#endif /* defined(RTEMS_SMP) */
332
333RTEMS_INLINE_ROUTINE bool _Scheduler_Has_processor_ownership(
334  const Scheduler_Control *scheduler,
335  uint32_t cpu_index
336)
337{
338#if defined(RTEMS_SMP)
339  const Scheduler_Assignment *assignment =
340    _Scheduler_Get_assignment( cpu_index );
341
342  return assignment->scheduler == scheduler;
343#else
344  (void) scheduler;
345  (void) cpu_index;
346
347  return true;
348#endif
349}
350
351RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get(
352  const Thread_Control *the_thread
353)
354{
355#if defined(RTEMS_SMP)
356  return the_thread->scheduler;
357#else
358  (void) the_thread;
359
360  return &_Scheduler_Table[ 0 ];
361#endif
362}
363
364RTEMS_INLINE_ROUTINE void _Scheduler_Set(
365  const Scheduler_Control *scheduler,
366  Thread_Control          *the_thread
367)
368{
369#if defined(RTEMS_SMP)
370  const Scheduler_Control *current_scheduler = _Scheduler_Get( the_thread );
371
372  if ( current_scheduler != scheduler ) {
373    _Thread_Set_state( the_thread, STATES_MIGRATING );
374    _Scheduler_Node_destroy( current_scheduler, the_thread );
375    the_thread->scheduler = scheduler;
376    _Scheduler_Node_initialize( scheduler, the_thread );
377    _Scheduler_Update_priority(
378      scheduler,
379      the_thread,
380      the_thread->current_priority
381    );
382    _Thread_Clear_state( the_thread, STATES_MIGRATING );
383  }
384#else
385  (void) scheduler;
386#endif
387}
388
389#if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
390
391RTEMS_INLINE_ROUTINE void _Scheduler_Get_processor_set(
392  const Scheduler_Control *scheduler,
393  size_t                   cpusetsize,
394  cpu_set_t               *cpuset
395)
396{
397  uint32_t cpu_count = _SMP_Get_processor_count();
398  uint32_t cpu_index;
399
400  CPU_ZERO_S( cpusetsize, cpuset );
401
402  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
403#if defined(RTEMS_SMP)
404    if ( _Scheduler_Has_processor_ownership( scheduler, cpu_index ) ) {
405      CPU_SET_S( (int) cpu_index, cpusetsize, cpuset );
406    }
407#else
408    (void) scheduler;
409
410    CPU_SET_S( (int) cpu_index, cpusetsize, cpuset );
411#endif
412  }
413}
414
415RTEMS_INLINE_ROUTINE bool _Scheduler_default_Get_affinity_body(
416  const Scheduler_Control *scheduler,
417  Thread_Control          *the_thread,
418  size_t                   cpusetsize,
419  cpu_set_t               *cpuset
420)
421{
422  (void) the_thread;
423
424  _Scheduler_Get_processor_set( scheduler, cpusetsize, cpuset );
425
426  return true;
427}
428
429bool _Scheduler_Get_affinity(
430  Thread_Control *the_thread,
431  size_t          cpusetsize,
432  cpu_set_t      *cpuset
433);
434
435RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body(
436  const Scheduler_Control *scheduler,
437  Thread_Control          *the_thread,
438  size_t                   cpusetsize,
439  const cpu_set_t         *cpuset
440)
441{
442  uint32_t cpu_count = _SMP_Get_processor_count();
443  uint32_t cpu_index;
444  bool     ok = true;
445
446  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
447#if defined(RTEMS_SMP)
448    const Scheduler_Control *scheduler_of_cpu =
449      _Scheduler_Get_by_CPU_index( cpu_index );
450
451    ok = ok
452      && ( CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset )
453        || ( !CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset )
454          && scheduler != scheduler_of_cpu ) );
455#else
456    (void) scheduler;
457
458    ok = ok && CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset );
459#endif
460  }
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 Scheduler_Context *_Scheduler_Get_context(
582  const Scheduler_Control *scheduler
583)
584{
585  return scheduler->context;
586}
587
588RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_processor_count(
589  const Scheduler_Control *scheduler
590)
591{
592#if defined(RTEMS_SMP)
593  return _Scheduler_Get_context( scheduler )->processor_count;
594#else
595  (void) scheduler;
596
597  return 1;
598#endif
599}
600
601RTEMS_INLINE_ROUTINE Objects_Id _Scheduler_Build_id( uint32_t scheduler_index )
602{
603  return _Objects_Build_id(
604    OBJECTS_FAKE_OBJECTS_API,
605    OBJECTS_FAKE_OBJECTS_SCHEDULERS,
606    _Objects_Local_node,
607    scheduler_index + 1
608  );
609}
610
611RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index_by_id( Objects_Id id )
612{
613  uint32_t minimum_id = _Scheduler_Build_id( 0 );
614
615  return id - minimum_id;
616}
617
618RTEMS_INLINE_ROUTINE bool _Scheduler_Get_by_id(
619  Objects_Id                id,
620  const Scheduler_Control **scheduler_p
621)
622{
623  uint32_t index = _Scheduler_Get_index_by_id( id );
624  const Scheduler_Control *scheduler = &_Scheduler_Table[ index ];
625
626  *scheduler_p = scheduler;
627
628  return index < _Scheduler_Count
629    && _Scheduler_Get_processor_count( scheduler ) > 0;
630}
631
632RTEMS_INLINE_ROUTINE bool _Scheduler_Is_id_valid( Objects_Id id )
633{
634  const Scheduler_Control *scheduler;
635  bool ok = _Scheduler_Get_by_id( id, &scheduler );
636
637  (void) scheduler;
638
639  return ok;
640}
641
642RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index(
643  const Scheduler_Control *scheduler
644)
645{
646  return (uint32_t) (scheduler - &_Scheduler_Table[ 0 ]);
647}
648
649RTEMS_INLINE_ROUTINE Scheduler_Node *_Scheduler_Node_get(
650  Thread_Control *the_thread
651)
652{
653  return the_thread->scheduler_node;
654}
655
656/** @} */
657
658#ifdef __cplusplus
659}
660#endif
661
662#endif
663/* end of include file */
Note: See TracBrowser for help on using the repository browser.