source: rtems/cpukit/score/include/rtems/score/scheduler.h @ 9bfad8c

5
Last change on this file since 9bfad8c was 9bfad8c, checked in by Sebastian Huber <sebastian.huber@…>, on 06/08/16 at 20:22:46

score: Add thread priority to scheduler nodes

The thread priority is manifest in two independent areas. One area is
the user visible thread priority along with a potential thread queue.
The other is the scheduler. Currently, a thread priority update via
_Thread_Change_priority() first updates the user visble thread priority
and the thread queue, then the scheduler is notified if necessary. The
priority is passed to the scheduler via a local variable. A generation
counter ensures that the scheduler discards out-of-date priorities.

This use of a local variable ties the update in these two areas close
together. For later enhancements and the OMIP locking protocol
implementation we need more flexibility. Add a thread priority
information block to Scheduler_Node and synchronize priority value
updates via a sequence lock on SMP configurations.

Update #2556.

  • Property mode set to 100644
File size: 16.1 KB
Line 
1/**
2 *  @file  rtems/score/scheduler.h
3 *
4 *  @brief Constants and Structures Associated with the Scheduler
5 *
6 *  This include file contains all the constants and structures associated
7 *  with 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_SCHEDULER_H
20#define _RTEMS_SCORE_SCHEDULER_H
21
22#include <rtems/score/priority.h>
23#include <rtems/score/smplockseq.h>
24#include <rtems/score/thread.h>
25#if defined(__RTEMS_HAVE_SYS_CPUSET_H__) && defined(RTEMS_SMP)
26  #include <sys/cpuset.h>
27#endif
28
29#ifdef __cplusplus
30extern "C" {
31#endif
32
33struct Per_CPU_Control;
34
35/**
36 *  @defgroup ScoreScheduler Scheduler Handler
37 *
38 *  @ingroup Score
39 *
40 *  This handler encapsulates functionality related to managing sets of threads
41 *  that are ready for execution.
42 */
43/**@{*/
44
45typedef struct Scheduler_Control Scheduler_Control;
46
47typedef struct Scheduler_Node Scheduler_Node;
48
49#if defined(RTEMS_SMP)
50  typedef Thread_Control * Scheduler_Void_or_thread;
51
52  #define SCHEDULER_RETURN_VOID_OR_NULL return NULL
53#else
54  typedef void Scheduler_Void_or_thread;
55
56  #define SCHEDULER_RETURN_VOID_OR_NULL return
57#endif
58
59/**
60 * @brief The scheduler operations.
61 */
62typedef struct {
63  /** @see _Scheduler_Handler_initialization() */
64  void ( *initialize )( const Scheduler_Control * );
65
66  /** @see _Scheduler_Schedule() */
67  void ( *schedule )( const Scheduler_Control *, Thread_Control *);
68
69  /** @see _Scheduler_Yield() */
70  Scheduler_Void_or_thread ( *yield )(
71    const Scheduler_Control *,
72    Thread_Control *
73  );
74
75  /** @see _Scheduler_Block() */
76  void ( *block )(
77    const Scheduler_Control *,
78    Thread_Control *
79  );
80
81  /** @see _Scheduler_Unblock() */
82  Scheduler_Void_or_thread ( *unblock )(
83    const Scheduler_Control *,
84    Thread_Control *
85  );
86
87  /** @see _Scheduler_Update_priority() */
88  Scheduler_Void_or_thread ( *update_priority )(
89    const Scheduler_Control *,
90    Thread_Control *
91  );
92
93  /** @see _Scheduler_Map_priority() */
94  Priority_Control ( *map_priority )(
95    const Scheduler_Control *,
96    Priority_Control
97  );
98
99  /** @see _Scheduler_Unmap_priority() */
100  Priority_Control ( *unmap_priority )(
101    const Scheduler_Control *,
102    Priority_Control
103  );
104
105#if defined(RTEMS_SMP)
106  /**
107   * Ask for help operation.
108   *
109   * @param[in] scheduler The scheduler of the thread offering help.
110   * @param[in] offers_help The thread offering help.
111   * @param[in] needs_help The thread needing help.
112   *
113   * @retval needs_help It was not possible to schedule the thread needing
114   *   help, so it is returned to continue the search for help.
115   * @retval next_needs_help It was possible to schedule the thread needing
116   *   help, but this displaced another thread eligible to ask for help.  So
117   *   this thread is returned to start a new search for help.
118   * @retval NULL It was possible to schedule the thread needing help, and no
119   *   other thread needs help as a result.
120   *
121   * @see _Scheduler_Ask_for_help().
122   */
123  Thread_Control *( *ask_for_help )(
124    const Scheduler_Control *scheduler,
125    Thread_Control          *offers_help,
126    Thread_Control          *needs_help
127  );
128#endif
129
130  /** @see _Scheduler_Node_initialize() */
131  void ( *node_initialize )(
132    const Scheduler_Control *,
133    Thread_Control *,
134    Priority_Control
135  );
136
137  /** @see _Scheduler_Node_destroy() */
138  void ( *node_destroy )( const Scheduler_Control *, Thread_Control * );
139
140  /** @see _Scheduler_Release_job() */
141  void ( *release_job ) (
142    const Scheduler_Control *,
143    Thread_Control *,
144    uint64_t
145  );
146
147  /** @see _Scheduler_Tick() */
148  void ( *tick )( const Scheduler_Control *, Thread_Control * );
149
150  /** @see _Scheduler_Start_idle() */
151  void ( *start_idle )(
152    const Scheduler_Control *,
153    Thread_Control *,
154    struct Per_CPU_Control *
155  );
156
157#if defined(__RTEMS_HAVE_SYS_CPUSET_H__) && defined(RTEMS_SMP)
158  /** @see _Scheduler_Get_affinity() */
159  bool ( *get_affinity )(
160    const Scheduler_Control *,
161    Thread_Control *,
162    size_t,
163    cpu_set_t *
164  );
165 
166  /** @see _Scheduler_Set_affinity() */
167  bool ( *set_affinity )(
168    const Scheduler_Control *,
169    Thread_Control *,
170    size_t,
171    const cpu_set_t *
172  );
173#endif
174} Scheduler_Operations;
175
176/**
177 * @brief Scheduler context.
178 *
179 * The scheduler context of a particular scheduler implementation must place
180 * this structure at the begin of its context structure.
181 */
182typedef struct Scheduler_Context {
183#if defined(RTEMS_SMP)
184  /**
185   * @brief Count of processors owned by this scheduler instance.
186   */
187  uint32_t processor_count;
188#endif
189} Scheduler_Context;
190
191/**
192 * @brief Scheduler control.
193 */
194struct Scheduler_Control {
195  /**
196   * @brief Reference to a statically allocated scheduler context.
197   */
198  Scheduler_Context *context;
199
200  /**
201   * @brief The scheduler operations.
202   */
203  Scheduler_Operations Operations;
204
205  /**
206   * @brief The maximum priority value of this scheduler.
207   *
208   * It defines the lowest (least important) thread priority for this
209   * scheduler.  For example the idle threads have this priority.
210   */
211  Priority_Control maximum_priority;
212
213  /**
214   * @brief The scheduler name.
215   */
216  uint32_t name;
217};
218
219#if defined(RTEMS_SMP)
220/**
221 * @brief State to indicate potential help for other threads.
222 *
223 * @dot
224 * digraph state {
225 *   y [label="HELP YOURSELF"];
226 *   ao [label="HELP ACTIVE OWNER"];
227 *   ar [label="HELP ACTIVE RIVAL"];
228 *
229 *   y -> ao [label="obtain"];
230 *   y -> ar [label="wait for obtain"];
231 *   ao -> y [label="last release"];
232 *   ao -> r [label="wait for obtain"];
233 *   ar -> r [label="timeout"];
234 *   ar -> ao [label="timeout"];
235 * }
236 * @enddot
237 */
238typedef enum {
239  /**
240   * @brief This scheduler node is solely used by the owner thread.
241   *
242   * This thread owns no resources using a helping protocol and thus does not
243   * take part in the scheduler helping protocol.  No help will be provided for
244   * other thread.
245   */
246  SCHEDULER_HELP_YOURSELF,
247
248  /**
249   * @brief This scheduler node is owned by a thread actively owning a resource.
250   *
251   * This scheduler node can be used to help out threads.
252   *
253   * In case this scheduler node changes its state from ready to scheduled and
254   * the thread executes using another node, then an idle thread will be
255   * provided as a user of this node to temporarily execute on behalf of the
256   * owner thread.  Thus lower priority threads are denied access to the
257   * processors of this scheduler instance.
258   *
259   * In case a thread actively owning a resource performs a blocking operation,
260   * then an idle thread will be used also in case this node is in the
261   * scheduled state.
262   */
263  SCHEDULER_HELP_ACTIVE_OWNER,
264
265  /**
266   * @brief This scheduler node is owned by a thread actively obtaining a
267   * resource currently owned by another thread.
268   *
269   * This scheduler node can be used to help out threads.
270   *
271   * The thread owning this node is ready and will give away its processor in
272   * case the thread owning the resource asks for help.
273   */
274  SCHEDULER_HELP_ACTIVE_RIVAL,
275
276  /**
277   * @brief This scheduler node is owned by a thread obtaining a
278   * resource currently owned by another thread.
279   *
280   * This scheduler node can be used to help out threads.
281   *
282   * The thread owning this node is blocked.
283   */
284  SCHEDULER_HELP_PASSIVE
285} Scheduler_Help_state;
286#endif
287
288/**
289 * @brief Scheduler node for per-thread data.
290 */
291struct Scheduler_Node {
292#if defined(RTEMS_SMP)
293  /**
294   * @brief Chain node for usage in various scheduler data structures.
295   *
296   * Strictly this is the wrong place for this field since the data structures
297   * to manage scheduler nodes belong to the particular scheduler
298   * implementation.  Currently all SMP scheduler implementations use chains.
299   * The node is here to simplify things, just like the object node in the
300   * thread control block.  It may be replaced with a union to add a red-black
301   * tree node in the future.
302   */
303  Chain_Node Node;
304
305  /**
306   * @brief The thread using this node.
307   */
308  Thread_Control *user;
309
310  /**
311   * @brief The help state of this node.
312   */
313  Scheduler_Help_state help_state;
314
315  /**
316   * @brief The thread owning this node.
317   */
318  Thread_Control *owner;
319
320  /**
321   * @brief The idle thread claimed by this node in case the help state is
322   * SCHEDULER_HELP_ACTIVE_OWNER.
323   *
324   * Active owners will lend their own node to an idle thread in case they
325   * execute currently using another node or in case they perform a blocking
326   * operation.  This is necessary to ensure the priority ceiling protocols
327   * work across scheduler boundaries.
328   */
329  Thread_Control *idle;
330
331  /**
332   * @brief The thread accepting help by this node in case the help state is
333   * not SCHEDULER_HELP_YOURSELF.
334   */
335  Thread_Control *accepts_help;
336#endif
337
338  /**
339   * @brief The thread priority information used by the scheduler.
340   *
341   * The thread priority is manifest in two independent areas.  One area is the
342   * user visible thread priority along with a potential thread queue.  The
343   * other is the scheduler.  During a thread priority change, the user visible
344   * thread priority and the thread queue are first updated and the thread
345   * priority value here is changed.  Once this is done the scheduler is
346   * notified via the update priority operation, so that it can update its
347   * internal state and honour a new thread priority value.
348   */
349  struct {
350    /**
351     * @brief The thread priority value of this scheduler node.
352     *
353     * The producer of this value is _Thread_Change_priority().  The consumer
354     * is the scheduler via the unblock and update priority operations.
355     */
356    Priority_Control value;
357
358#if defined(RTEMS_SMP)
359    /**
360     * @brief Sequence lock to synchronize priority value updates.
361     */
362    SMP_sequence_lock_Control Lock;
363#endif
364
365    /**
366     * @brief In case a priority update is necessary and this is true, then
367     * enqueue the thread as the first of its priority group, otherwise enqueue
368     * the thread as the last of its priority group.
369     */
370    bool prepend_it;
371  } Priority;
372};
373
374/**
375 * @brief Registered schedulers.
376 *
377 * Application provided via <rtems/confdefs.h>.
378 *
379 * @see _Scheduler_Count.
380 */
381extern const Scheduler_Control _Scheduler_Table[];
382
383/**
384 * @brief Count of registered schedulers.
385 *
386 * Application provided via <rtems/confdefs.h> on SMP configurations.
387 *
388 * It is very important that this is a compile-time constant on uni-processor
389 * configurations (in this case RTEMS_SMP is not defined) so that the compiler
390 * can optimize the some loops away
391 *
392 * @see _Scheduler_Table.
393 */
394#if defined(RTEMS_SMP)
395  extern const size_t _Scheduler_Count;
396#else
397  #define _Scheduler_Count ( (size_t) 1 )
398#endif
399
400#if defined(RTEMS_SMP)
401  /**
402   * @brief The scheduler assignment default attributes.
403   */
404  #define SCHEDULER_ASSIGN_DEFAULT UINT32_C(0x0)
405
406  /**
407   * @brief The presence of this processor is optional.
408   */
409  #define SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL SCHEDULER_ASSIGN_DEFAULT
410
411  /**
412   * @brief The presence of this processor is mandatory.
413   */
414  #define SCHEDULER_ASSIGN_PROCESSOR_MANDATORY UINT32_C(0x1)
415
416  /**
417   * @brief Scheduler assignment.
418   */
419  typedef struct {
420    /**
421     * @brief The scheduler for this processor.
422     */
423    const Scheduler_Control *scheduler;
424
425    /**
426     * @brief The scheduler assignment attributes.
427     *
428     * Use @ref SCHEDULER_ASSIGN_DEFAULT to select default attributes.
429     *
430     * The presence of a processor can be
431     * - @ref SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL, or
432     * - @ref SCHEDULER_ASSIGN_PROCESSOR_MANDATORY.
433     */
434    uint32_t attributes;
435  } Scheduler_Assignment;
436
437  /**
438   * @brief The scheduler assignments.
439   *
440   * The length of this array must be equal to the maximum processors.
441   *
442   * Application provided via <rtems/confdefs.h>.
443   *
444   * @see _Scheduler_Table and rtems_configuration_get_maximum_processors().
445   */
446  extern const Scheduler_Assignment _Scheduler_Assignments[];
447#endif
448
449/**
450 * @brief Returns the thread priority.
451 *
452 * @param[in] scheduler Unused.
453 * @param[in] priority The thread priority.
454 *
455 * @return priority The thread priority.
456 */
457Priority_Control _Scheduler_default_Map_priority(
458  const Scheduler_Control *scheduler,
459  Priority_Control         priority
460);
461
462#define _Scheduler_default_Unmap_priority _Scheduler_default_Map_priority
463
464#if defined(RTEMS_SMP)
465  /**
466   * @brief Does nothing.
467   *
468   * @param[in] scheduler Unused.
469   * @param[in] offers_help Unused.
470   * @param[in] needs_help Unused.
471   *
472   * @retval NULL Always.
473   */
474  Thread_Control *_Scheduler_default_Ask_for_help(
475    const Scheduler_Control *scheduler,
476    Thread_Control          *offers_help,
477    Thread_Control          *needs_help
478  );
479
480  #define SCHEDULER_OPERATION_DEFAULT_ASK_FOR_HELP \
481    _Scheduler_default_Ask_for_help,
482#else
483  #define SCHEDULER_OPERATION_DEFAULT_ASK_FOR_HELP
484#endif
485
486/**
487 * @brief Does nothing.
488 *
489 * @param[in] scheduler Unused.
490 * @param[in] the_thread Unused.
491 */
492void _Scheduler_default_Schedule(
493  const Scheduler_Control *scheduler,
494  Thread_Control          *the_thread
495);
496
497/**
498 * @brief Performs the scheduler base node initialization.
499 *
500 * @param[in] scheduler Unused.
501 * @param[in] the_thread Unused.
502 * @param[in] priority The thread priority.
503 */
504void _Scheduler_default_Node_initialize(
505  const Scheduler_Control *scheduler,
506  Thread_Control          *the_thread,
507  Priority_Control         priority
508);
509
510/**
511 * @brief Does nothing.
512 *
513 * @param[in] scheduler Unused.
514 * @param[in] the_thread Unused.
515 */
516void _Scheduler_default_Node_destroy(
517  const Scheduler_Control *scheduler,
518  Thread_Control          *the_thread
519);
520
521/**
522 * @brief Does nothing.
523 *
524 * @param[in] scheduler Unused.
525 * @param[in] the_thread Unused.
526 * @param[in] deadline Unused.
527 */
528void _Scheduler_default_Release_job(
529  const Scheduler_Control *scheduler,
530  Thread_Control          *the_thread,
531  uint64_t                 deadline
532);
533
534/**
535 * @brief Performs tick operations depending on the CPU budget algorithm for
536 * each executing thread.
537 *
538 * This routine is invoked as part of processing each clock tick.
539 *
540 * @param[in] scheduler The scheduler.
541 * @param[in] executing An executing thread.
542 */
543void _Scheduler_default_Tick(
544  const Scheduler_Control *scheduler,
545  Thread_Control          *executing
546);
547
548/**
549 * @brief Starts an idle thread.
550 *
551 * @param[in] scheduler The scheduler.
552 * @param[in] the_thread An idle thread.
553 * @param[in] cpu This parameter is unused.
554 */
555void _Scheduler_default_Start_idle(
556  const Scheduler_Control *scheduler,
557  Thread_Control          *the_thread,
558  struct Per_CPU_Control  *cpu
559);
560
561#if defined(__RTEMS_HAVE_SYS_CPUSET_H__) && defined(RTEMS_SMP)
562  /**
563   * @brief Get affinity for the default scheduler.
564   *
565   * @param[in] scheduler The scheduler instance.
566   * @param[in] thread The associated thread.
567   * @param[in] cpusetsize The size of the cpuset.
568   * @param[out] cpuset Affinity set containing all CPUs.
569   *
570   * @retval 0 Successfully got cpuset
571   * @retval -1 The cpusetsize is invalid for the system
572   */
573  bool _Scheduler_default_Get_affinity(
574    const Scheduler_Control *scheduler,
575    Thread_Control          *thread,
576    size_t                   cpusetsize,
577    cpu_set_t               *cpuset
578  );
579
580  /**
581   * @brief Set affinity for the default scheduler.
582   *
583   * @param[in] scheduler The scheduler instance.
584   * @param[in] thread The associated thread.
585   * @param[in] cpusetsize The size of the cpuset.
586   * @param[in] cpuset Affinity new affinity set.
587   *
588   * @retval 0 Successful
589   *
590   *  This method always returns successful and does not save
591   *  the cpuset.
592   */
593  bool _Scheduler_default_Set_affinity(
594    const Scheduler_Control *scheduler,
595    Thread_Control          *thread,
596    size_t                   cpusetsize,
597    const cpu_set_t         *cpuset
598  );
599
600  #define SCHEDULER_OPERATION_DEFAULT_GET_SET_AFFINITY \
601    , _Scheduler_default_Get_affinity \
602    , _Scheduler_default_Set_affinity
603#else
604  #define SCHEDULER_OPERATION_DEFAULT_GET_SET_AFFINITY
605#endif
606
607/**
608 * @brief This defines the lowest (least important) thread priority of the
609 * first scheduler instance.
610 */
611#define PRIORITY_MAXIMUM ( _Scheduler_Table[ 0 ].maximum_priority )
612
613/**@}*/
614
615#ifdef __cplusplus
616}
617#endif
618
619#endif
620/* end of include file */
Note: See TracBrowser for help on using the repository browser.