source: rtems-docs/c-user/symmetric_multiprocessing_services.rst @ 97e1553

5
Last change on this file since 97e1553 was 97e1553, checked in by Sebastian Huber <sebastian.huber@…>, on 01/17/17 at 09:39:08

c-user: Add support for references via bibtex

https://sphinxcontrib-bibtex.readthedocs.io/en/latest/index.html

Update #2871.

  • Property mode set to 100644
File size: 41.2 KB
Line 
1.. comment SPDX-License-Identifier: CC-BY-SA-4.0
2
3.. COMMENT: COPYRIGHT (c) 2014.
4.. COMMENT: On-Line Applications Research Corporation (OAR).
5.. COMMENT: All rights reserved.
6
7Symmetric Multiprocessing Services
8**********************************
9
10Introduction
11============
12
13The Symmetric Multiprocessing (SMP) support of the RTEMS 4.11.0 and later is available
14on
15
16- ARM,
17
18- PowerPC, and
19
20- SPARC.
21
22It must be explicitly enabled via the ``--enable-smp`` configure command line
23option.  To enable SMP in the application configuration see :ref:`Enable SMP
24Support for Applications`.  The default scheduler for SMP applications supports
25up to 32 processors and is a global fixed priority scheduler, see also
26:ref:`Configuring Clustered Schedulers`.  For example applications
27see:file:`testsuites/smptests`.
28
29.. warning::
30
31   The SMP support in the release of RTEMS is a work in progress. Before you
32   start using this RTEMS version for SMP ask on the RTEMS mailing list.
33
34This chapter describes the services related to Symmetric Multiprocessing
35provided by RTEMS.
36
37The application level services currently provided are:
38
39- rtems_get_processor_count_ - Get processor count
40
41- rtems_get_current_processor_ - Get current processor index
42
43- rtems_scheduler_ident_ - Get ID of a scheduler
44
45- rtems_scheduler_get_processor_set_ - Get processor set of a scheduler
46
47- rtems_scheduler_add_processor_ - Add processor to a scheduler
48
49- rtems_scheduler_remove_processor_ - Remove processor from a scheduler
50
51- rtems_task_get_scheduler_ - Get scheduler of a task
52
53- rtems_task_set_scheduler_ - Set scheduler of a task
54
55- rtems_task_get_affinity_ - Get task processor affinity
56
57- rtems_task_set_affinity_ - Set task processor affinity
58
59Background
60==========
61
62Uniprocessor versus SMP Parallelism
63-----------------------------------
64
65Uniprocessor systems have long been used in embedded systems. In this hardware
66model, there are some system execution characteristics which have long been
67taken for granted:
68
69- one task executes at a time
70
71- hardware events result in interrupts
72
73There is no true parallelism. Even when interrupts appear to occur at the same
74time, they are processed in largely a serial fashion.  This is true even when
75the interupt service routines are allowed to nest.  From a tasking viewpoint,
76it is the responsibility of the real-time operatimg system to simulate
77parallelism by switching between tasks.  These task switches occur in response
78to hardware interrupt events and explicit application events such as blocking
79for a resource or delaying.
80
81With symmetric multiprocessing, the presence of multiple processors allows for
82true concurrency and provides for cost-effective performance
83improvements. Uniprocessors tend to increase performance by increasing clock
84speed and complexity. This tends to lead to hot, power hungry microprocessors
85which are poorly suited for many embedded applications.
86
87The true concurrency is in sharp contrast to the single task and interrupt
88model of uniprocessor systems. This results in a fundamental change to
89uniprocessor system characteristics listed above. Developers are faced with a
90different set of characteristics which, in turn, break some existing
91assumptions and result in new challenges. In an SMP system with N processors,
92these are the new execution characteristics.
93
94- N tasks execute in parallel
95
96- hardware events result in interrupts
97
98There is true parallelism with a task executing on each processor and the
99possibility of interrupts occurring on each processor. Thus in contrast to
100their being one task and one interrupt to consider on a uniprocessor, there are
101N tasks and potentially N simultaneous interrupts to consider on an SMP system.
102
103This increase in hardware complexity and presence of true parallelism results
104in the application developer needing to be even more cautious about mutual
105exclusion and shared data access than in a uniprocessor embedded system. Race
106conditions that never or rarely happened when an application executed on a
107uniprocessor system, become much more likely due to multiple threads executing
108in parallel. On a uniprocessor system, these race conditions would only happen
109when a task switch occurred at just the wrong moment. Now there are N-1 tasks
110executing in parallel all the time and this results in many more opportunities
111for small windows in critical sections to be hit.
112
113Task Affinity
114-------------
115.. index:: task affinity
116.. index:: thread affinity
117
118RTEMS provides services to manipulate the affinity of a task. Affinity is used
119to specify the subset of processors in an SMP system on which a particular task
120can execute.
121
122By default, tasks have an affinity which allows them to execute on any
123available processor.
124
125Task affinity is a possible feature to be supported by SMP-aware
126schedulers. However, only a subset of the available schedulers support
127affinity. Although the behavior is scheduler specific, if the scheduler does
128not support affinity, it is likely to ignore all attempts to set affinity.
129
130The scheduler with support for arbitary processor affinities uses a proof of
131concept implementation.  See https://devel.rtems.org/ticket/2510.
132
133Task Migration
134--------------
135.. index:: task migration
136.. index:: thread migration
137
138With more than one processor in the system tasks can migrate from one processor
139to another.  There are three reasons why tasks migrate in RTEMS.
140
141- The scheduler changes explicitly via ``rtems_task_set_scheduler()`` or
142  similar directives.
143
144- The task resumes execution after a blocking operation.  On a priority based
145  scheduler it will evict the lowest priority task currently assigned to a
146  processor in the processor set managed by the scheduler instance.
147
148- The task moves temporarily to another scheduler instance due to locking
149  protocols like *Migratory Priority Inheritance* or the *Multiprocessor
150  Resource Sharing Protocol*.
151
152Task migration should be avoided so that the working set of a task can stay on
153the most local cache level.
154
155The current implementation of task migration in RTEMS has some implications
156with respect to the interrupt latency.  It is crucial to preserve the system
157invariant that a task can execute on at most one processor in the system at a
158time.  This is accomplished with a boolean indicator in the task context.  The
159processor architecture specific low-level task context switch code will mark
160that a task context is no longer executing and waits that the heir context
161stopped execution before it restores the heir context and resumes execution of
162the heir task.  So there is one point in time in which a processor is without a
163task.  This is essential to avoid cyclic dependencies in case multiple tasks
164migrate at once.  Otherwise some supervising entity is necessary to prevent
165life-locks.  Such a global supervisor would lead to scalability problems so
166this approach is not used.  Currently the thread dispatch is performed with
167interrupts disabled.  So in case the heir task is currently executing on
168another processor then this prolongs the time of disabled interrupts since one
169processor has to wait for another processor to make progress.
170
171It is difficult to avoid this issue with the interrupt latency since interrupts
172normally store the context of the interrupted task on its stack.  In case a
173task is marked as not executing we must not use its task stack to store such an
174interrupt context.  We cannot use the heir stack before it stopped execution on
175another processor.  So if we enable interrupts during this transition we have
176to provide an alternative task independent stack for this time frame.  This
177issue needs further investigation.
178
179Clustered Scheduling
180--------------------
181
182We have clustered scheduling in case the set of processors of a system is
183partitioned into non-empty pairwise-disjoint subsets. These subsets are called
184clusters.  Clusters with a cardinality of one are partitions.  Each cluster is
185owned by exactly one scheduler instance.
186
187Clustered scheduling helps to control the worst-case latencies in
188multi-processor systems, see :cite:`Brandenburg:2011:SL`. The goal is to reduce
189the amount of shared state in the system and thus prevention of lock
190contention. Modern multi-processor systems tend to have several layers of data
191and instruction caches.  With clustered scheduling it is possible to honour the
192cache topology of a system and thus avoid expensive cache synchronization
193traffic.  It is easy to implement.  The problem is to provide synchronization
194primitives for inter-cluster synchronization (more than one cluster is involved
195in the synchronization process). In RTEMS there are currently four means
196available
197
198- events,
199
200- message queues,
201
202- semaphores using the :ref:`Priority Inheritance` protocol (priority
203  boosting), and
204
205- semaphores using the Multiprocessor Resource Sharing Protocol :cite:`Burns:2013:MrsP`.
206
207The clustered scheduling approach enables separation of functions with
208real-time requirements and functions that profit from fairness and high
209throughput provided the scheduler instances are fully decoupled and adequate
210inter-cluster synchronization primitives are used.  This is work in progress.
211
212For the configuration of clustered schedulers see :ref:`Configuring Clustered
213Schedulers`.
214
215To set the scheduler of a task see :ref:`SCHEDULER_IDENT - Get ID of a
216scheduler` and :ref:`TASK_SET_SCHEDULER - Set scheduler of a task`.
217
218Task Priority Queues
219--------------------
220
221Due to the support for clustered scheduling the task priority queues need
222special attention.  It makes no sense to compare the priority values of two
223different scheduler instances.  Thus, it is not possible to simply use one
224plain priority queue for tasks of different scheduler instances.
225
226One solution to this problem is to use two levels of queues.  The top level
227queue provides FIFO ordering and contains priority queues.  Each priority queue
228is associated with a scheduler instance and contains only tasks of this
229scheduler instance.  Tasks are enqueued in the priority queue corresponding to
230their scheduler instance.  In case this priority queue was empty, then it is
231appended to the FIFO.  To dequeue a task the highest priority task of the first
232priority queue in the FIFO is selected.  Then the first priority queue is
233removed from the FIFO.  In case the previously first priority queue is not
234empty, then it is appended to the FIFO.  So there is FIFO fairness with respect
235to the highest priority task of each scheduler instances. See also
236:cite:`Brandenburg:2013:OMIP`.
237
238Such a two level queue may need a considerable amount of memory if fast enqueue
239and dequeue operations are desired (depends on the scheduler instance count).
240To mitigate this problem an approch of the FreeBSD kernel was implemented in
241RTEMS.  We have the invariant that a task can be enqueued on at most one task
242queue.  Thus, we need only as many queues as we have tasks.  Each task is
243equipped with spare task queue which it can give to an object on demand.  The
244task queue uses a dedicated memory space independent of the other memory used
245for the task itself. In case a task needs to block, then there are two options
246
247- the object already has task queue, then the task enqueues itself to this
248  already present queue and the spare task queue of the task is added to a list
249  of free queues for this object, or
250
251- otherwise, then the queue of the task is given to the object and the task
252  enqueues itself to this queue.
253
254In case the task is dequeued, then there are two options
255
256- the task is the last task on the queue, then it removes this queue from the
257  object and reclaims it for its own purpose, or
258
259- otherwise, then the task removes one queue from the free list of the object
260  and reclaims it for its own purpose.
261
262Since there are usually more objects than tasks, this actually reduces the
263memory demands. In addition the objects contain only a pointer to the task
264queue structure. This helps to hide implementation details and makes it
265possible to use self-contained synchronization objects in Newlib and GCC (C++
266and OpenMP run-time support).
267
268Scheduler Helping Protocol
269--------------------------
270
271The scheduler provides a helping protocol to support locking protocols like
272*Migratory Priority Inheritance* or the *Multiprocessor Resource Sharing
273Protocol*.  Each ready task can use at least one scheduler node at a time to
274gain access to a processor.  Each scheduler node has an owner, a user and an
275optional idle task.  The owner of a scheduler node is determined a task
276creation and never changes during the life time of a scheduler node.  The user
277of a scheduler node may change due to the scheduler helping protocol.  A
278scheduler node is in one of the four scheduler help states:
279
280:dfn:`help yourself`
281    This scheduler node is solely used by the owner task.  This task owns no
282    resources using a helping protocol and thus does not take part in the
283    scheduler helping protocol.  No help will be provided for other tasks.
284
285:dfn:`help active owner`
286    This scheduler node is owned by a task actively owning a resource and can
287    be used to help out tasks.  In case this scheduler node changes its state
288    from ready to scheduled and the task executes using another node, then an
289    idle task will be provided as a user of this node to temporarily execute on
290    behalf of the owner task.  Thus lower priority tasks are denied access to
291    the processors of this scheduler instance.  In case a task actively owning
292    a resource performs a blocking operation, then an idle task will be used
293    also in case this node is in the scheduled state.
294
295:dfn:`help active rival`
296    This scheduler node is owned by a task actively obtaining a resource
297    currently owned by another task and can be used to help out tasks.  The
298    task owning this node is ready and will give away its processor in case the
299    task owning the resource asks for help.
300
301:dfn:`help passive`
302    This scheduler node is owned by a task obtaining a resource currently owned
303    by another task and can be used to help out tasks.  The task owning this
304    node is blocked.
305
306The following scheduler operations return a task in need for help
307
308- unblock,
309
310- change priority,
311
312- yield, and
313
314- ask for help.
315
316A task in need for help is a task that encounters a scheduler state change from
317scheduled to ready (this is a pre-emption by a higher priority task) or a task
318that cannot be scheduled in an unblock operation.  Such a task can ask tasks
319which depend on resources owned by this task for help.
320
321In case it is not possible to schedule a task in need for help, then the
322scheduler nodes available for the task will be placed into the set of ready
323scheduler nodes of the corresponding scheduler instances.  Once a state change
324from ready to scheduled happens for one of scheduler nodes it will be used to
325schedule the task in need for help.
326
327The ask for help scheduler operation is used to help tasks in need for help
328returned by the operations mentioned above.  This operation is also used in
329case the root of a resource sub-tree owned by a task changes.
330
331The run-time of the ask for help procedures depend on the size of the resource
332tree of the task needing help and other resource trees in case tasks in need
333for help are produced during this operation.  Thus the worst-case latency in
334the system depends on the maximum resource tree size of the application.
335
336Critical Section Techniques and SMP
337-----------------------------------
338
339As discussed earlier, SMP systems have opportunities for true parallelism which
340was not possible on uniprocessor systems. Consequently, multiple techniques
341that provided adequate critical sections on uniprocessor systems are unsafe on
342SMP systems. In this section, some of these unsafe techniques will be
343discussed.
344
345In general, applications must use proper operating system provided mutual
346exclusion mechanisms to ensure correct behavior. This primarily means the use
347of binary semaphores or mutexes to implement critical sections.
348
349Disable Interrupts and Interrupt Locks
350~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
351
352A low overhead means to ensure mutual exclusion in uni-processor configurations
353is to disable interrupts around a critical section.  This is commonly used in
354device driver code and throughout the operating system core.  On SMP
355configurations, however, disabling the interrupts on one processor has no
356effect on other processors.  So, this is insufficient to ensure system wide
357mutual exclusion.  The macros
358
359- ``rtems_interrupt_disable()``,
360
361- ``rtems_interrupt_enable()``, and
362
363- ``rtems_interrupt_flush()``
364
365are disabled on SMP configurations and its use will lead to compiler warnings
366and linker errors.  In the unlikely case that interrupts must be disabled on
367the current processor, then the
368
369- ``rtems_interrupt_local_disable()``, and
370
371- ``rtems_interrupt_local_enable()``
372
373macros are now available in all configurations.
374
375Since disabling of interrupts is not enough to ensure system wide mutual
376exclusion on SMP, a new low-level synchronization primitive was added - the
377interrupt locks.  They are a simple API layer on top of the SMP locks used for
378low-level synchronization in the operating system core.  Currently they are
379implemented as a ticket lock.  On uni-processor configurations they degenerate
380to simple interrupt disable/enable sequences.  It is disallowed to acquire a
381single interrupt lock in a nested way.  This will result in an infinite loop
382with interrupts disabled.  While converting legacy code to interrupt locks care
383must be taken to avoid this situation.
384
385.. code-block:: c
386    :linenos:
387
388    void legacy_code_with_interrupt_disable_enable( void )
389    {
390        rtems_interrupt_level level;
391        rtems_interrupt_disable( level );
392        /* Some critical stuff */
393        rtems_interrupt_enable( level );
394    }
395
396    RTEMS_INTERRUPT_LOCK_DEFINE( static, lock, "Name" );
397
398    void smp_ready_code_with_interrupt_lock( void )
399    {
400        rtems_interrupt_lock_context lock_context;
401        rtems_interrupt_lock_acquire( &lock, &lock_context );
402        /* Some critical stuff */
403        rtems_interrupt_lock_release( &lock, &lock_context );
404    }
405
406The ``rtems_interrupt_lock`` structure is empty on uni-processor
407configurations.  Empty structures have a different size in C
408(implementation-defined, zero in case of GCC) and C++ (implementation-defined
409non-zero value, one in case of GCC).  Thus the
410``RTEMS_INTERRUPT_LOCK_DECLARE()``, ``RTEMS_INTERRUPT_LOCK_DEFINE()``,
411``RTEMS_INTERRUPT_LOCK_MEMBER()``, and ``RTEMS_INTERRUPT_LOCK_REFERENCE()``
412macros are provided to ensure ABI compatibility.
413
414Highest Priority Task Assumption
415~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
416
417On a uniprocessor system, it is safe to assume that when the highest priority
418task in an application executes, it will execute without being preempted until
419it voluntarily blocks. Interrupts may occur while it is executing, but there
420will be no context switch to another task unless the highest priority task
421voluntarily initiates it.
422
423Given the assumption that no other tasks will have their execution interleaved
424with the highest priority task, it is possible for this task to be constructed
425such that it does not need to acquire a binary semaphore or mutex for protected
426access to shared data.
427
428In an SMP system, it cannot be assumed there will never be a single task
429executing. It should be assumed that every processor is executing another
430application task. Further, those tasks will be ones which would not have been
431executed in a uniprocessor configuration and should be assumed to have data
432synchronization conflicts with what was formerly the highest priority task
433which executed without conflict.
434
435Disable Preemption
436~~~~~~~~~~~~~~~~~~
437
438On a uniprocessor system, disabling preemption in a task is very similar to
439making the highest priority task assumption. While preemption is disabled, no
440task context switches will occur unless the task initiates them
441voluntarily. And, just as with the highest priority task assumption, there are
442N-1 processors also running tasks. Thus the assumption that no other tasks will
443run while the task has preemption disabled is violated.
444
445Task Unique Data and SMP
446------------------------
447
448Per task variables are a service commonly provided by real-time operating
449systems for application use. They work by allowing the application to specify a
450location in memory (typically a ``void *``) which is logically added to the
451context of a task. On each task switch, the location in memory is stored and
452each task can have a unique value in the same memory location. This memory
453location is directly accessed as a variable in a program.
454
455This works well in a uniprocessor environment because there is one task
456executing and one memory location containing a task-specific value. But it is
457fundamentally broken on an SMP system because there are always N tasks
458executing. With only one location in memory, N-1 tasks will not have the
459correct value.
460
461This paradigm for providing task unique data values is fundamentally broken on
462SMP systems.
463
464Classic API Per Task Variables
465~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
466
467The Classic API provides three directives to support per task variables. These are:
468
469- ``rtems_task_variable_add`` - Associate per task variable
470
471- ``rtems_task_variable_get`` - Obtain value of a a per task variable
472
473- ``rtems_task_variable_delete`` - Remove per task variable
474
475As task variables are unsafe for use on SMP systems, the use of these services
476must be eliminated in all software that is to be used in an SMP environment.
477The task variables API is disabled on SMP. Its use will lead to compile-time
478and link-time errors. It is recommended that the application developer consider
479the use of POSIX Keys or Thread Local Storage (TLS). POSIX Keys are available
480in all RTEMS configurations.  For the availablity of TLS on a particular
481architecture please consult the *RTEMS CPU Architecture Supplement*.
482
483The only remaining user of task variables in the RTEMS code base is the Ada
484support.  So basically Ada is not available on RTEMS SMP.
485
486OpenMP
487------
488
489OpenMP support for RTEMS is available via the GCC provided libgomp.  There is
490libgomp support for RTEMS in the POSIX configuration of libgomp since GCC 4.9
491(requires a Newlib snapshot after 2015-03-12). In GCC 6.1 or later (requires a
492Newlib snapshot after 2015-07-30 for <sys/lock.h> provided self-contained
493synchronization objects) there is a specialized libgomp configuration for RTEMS
494which offers a significantly better performance compared to the POSIX
495configuration of libgomp.  In addition application configurable thread pools
496for each scheduler instance are available in GCC 6.1 or later.
497
498The run-time configuration of libgomp is done via environment variables
499documented in the `libgomp manual <https://gcc.gnu.org/onlinedocs/libgomp/>`_.
500The environment variables are evaluated in a constructor function which
501executes in the context of the first initialization task before the actual
502initialization task function is called (just like a global C++ constructor).
503To set application specific values, a higher priority constructor function must
504be used to set up the environment variables.
505
506.. code-block:: c
507
508    #include <stdlib.h>
509    void __attribute__((constructor(1000))) config_libgomp( void )
510    {
511        setenv( "OMP_DISPLAY_ENV", "VERBOSE", 1 );
512        setenv( "GOMP_SPINCOUNT", "30000", 1 );
513        setenv( "GOMP_RTEMS_THREAD_POOLS", "1$2@SCHD", 1 );
514    }
515
516The environment variable ``GOMP_RTEMS_THREAD_POOLS`` is RTEMS-specific.  It
517determines the thread pools for each scheduler instance.  The format for
518``GOMP_RTEMS_THREAD_POOLS`` is a list of optional
519``<thread-pool-count>[$<priority>]@<scheduler-name>`` configurations separated
520by ``:`` where:
521
522- ``<thread-pool-count>`` is the thread pool count for this scheduler instance.
523
524- ``$<priority>`` is an optional priority for the worker threads of a thread
525  pool according to ``pthread_setschedparam``.  In case a priority value is
526  omitted, then a worker thread will inherit the priority of the OpenMP master
527  thread that created it.  The priority of the worker thread is not changed by
528  libgomp after creation, even if a new OpenMP master thread using the worker
529  has a different priority.
530
531- ``@<scheduler-name>`` is the scheduler instance name according to the RTEMS
532  application configuration.
533
534In case no thread pool configuration is specified for a scheduler instance,
535then each OpenMP master thread of this scheduler instance will use its own
536dynamically allocated thread pool.  To limit the worker thread count of the
537thread pools, each OpenMP master thread must call ``omp_set_num_threads``.
538
539Lets suppose we have three scheduler instances ``IO``, ``WRK0``, and ``WRK1``
540with ``GOMP_RTEMS_THREAD_POOLS`` set to ``"1@WRK0:3$4@WRK1"``.  Then there are
541no thread pool restrictions for scheduler instance ``IO``.  In the scheduler
542instance ``WRK0`` there is one thread pool available.  Since no priority is
543specified for this scheduler instance, the worker thread inherits the priority
544of the OpenMP master thread that created it.  In the scheduler instance
545``WRK1`` there are three thread pools available and their worker threads run at
546priority four.
547
548Thread Dispatch Details
549-----------------------
550
551This section gives background information to developers interested in the
552interrupt latencies introduced by thread dispatching.  A thread dispatch
553consists of all work which must be done to stop the currently executing thread
554on a processor and hand over this processor to an heir thread.
555
556On SMP systems, scheduling decisions on one processor must be propagated to
557other processors through inter-processor interrupts.  So, a thread dispatch
558which must be carried out on another processor happens not instantaneous.  Thus
559several thread dispatch requests might be in the air and it is possible that
560some of them may be out of date before the corresponding processor has time to
561deal with them.  The thread dispatch mechanism uses three per-processor
562variables,
563
564- the executing thread,
565
566- the heir thread, and
567
568- an boolean flag indicating if a thread dispatch is necessary or not.
569
570Updates of the heir thread and the thread dispatch necessary indicator are
571synchronized via explicit memory barriers without the use of locks.  A thread
572can be an heir thread on at most one processor in the system.  The thread
573context is protected by a TTAS lock embedded in the context to ensure that it
574is used on at most one processor at a time.  The thread post-switch actions use
575a per-processor lock.  This implementation turned out to be quite efficient and
576no lock contention was observed in the test suite.
577
578The current implementation of thread dispatching has some implications with
579respect to the interrupt latency.  It is crucial to preserve the system
580invariant that a thread can execute on at most one processor in the system at a
581time.  This is accomplished with a boolean indicator in the thread context.
582The processor architecture specific context switch code will mark that a thread
583context is no longer executing and waits that the heir context stopped
584execution before it restores the heir context and resumes execution of the heir
585thread (the boolean indicator is basically a TTAS lock).  So, there is one
586point in time in which a processor is without a thread.  This is essential to
587avoid cyclic dependencies in case multiple threads migrate at once.  Otherwise
588some supervising entity is necessary to prevent deadlocks.  Such a global
589supervisor would lead to scalability problems so this approach is not used.
590Currently the context switch is performed with interrupts disabled.  Thus in
591case the heir thread is currently executing on another processor, the time of
592disabled interrupts is prolonged since one processor has to wait for another
593processor to make progress.
594
595It is difficult to avoid this issue with the interrupt latency since interrupts
596normally store the context of the interrupted thread on its stack.  In case a
597thread is marked as not executing, we must not use its thread stack to store
598such an interrupt context.  We cannot use the heir stack before it stopped
599execution on another processor.  If we enable interrupts during this
600transition, then we have to provide an alternative thread independent stack for
601interrupts in this time frame.  This issue needs further investigation.
602
603The problematic situation occurs in case we have a thread which executes with
604thread dispatching disabled and should execute on another processor (e.g. it is
605an heir thread on another processor).  In this case the interrupts on this
606other processor are disabled until the thread enables thread dispatching and
607starts the thread dispatch sequence.  The scheduler (an exception is the
608scheduler with thread processor affinity support) tries to avoid such a
609situation and checks if a new scheduled thread already executes on a processor.
610In case the assigned processor differs from the processor on which the thread
611already executes and this processor is a member of the processor set managed by
612this scheduler instance, it will reassign the processors to keep the already
613executing thread in place.  Therefore normal scheduler requests will not lead
614to such a situation.  Explicit thread migration requests, however, can lead to
615this situation.  Explicit thread migrations may occur due to the scheduler
616helping protocol or explicit scheduler instance changes.  The situation can
617also be provoked by interrupts which suspend and resume threads multiple times
618and produce stale asynchronous thread dispatch requests in the system.
619
620Operations
621==========
622
623Setting Affinity to a Single Processor
624--------------------------------------
625
626On some embedded applications targeting SMP systems, it may be beneficial to
627lock individual tasks to specific processors.  In this way, one can designate a
628processor for I/O tasks, another for computation, etc..  The following
629illustrates the code sequence necessary to assign a task an affinity for
630processor with index ``processor_index``.
631
632.. code-block:: c
633
634    #include <rtems.h>
635    #include <assert.h>
636
637    void pin_to_processor(rtems_id task_id, int processor_index)
638    {
639        rtems_status_code sc;
640        cpu_set_t         cpuset;
641        CPU_ZERO(&cpuset);
642        CPU_SET(processor_index, &cpuset);
643        sc = rtems_task_set_affinity(task_id, sizeof(cpuset), &cpuset);
644        assert(sc == RTEMS_SUCCESSFUL);
645    }
646
647It is important to note that the ``cpuset`` is not validated until the
648``rtems_task_set_affinity`` call is made. At that point, it is validated
649against the current system configuration.
650
651Directives
652==========
653
654This section details the symmetric multiprocessing services.  A subsection is
655dedicated to each of these services and describes the calling sequence, related
656constants, usage, and status codes.
657
658.. raw:: latex
659
660   \clearpage
661
662.. _rtems_get_processor_count:
663
664GET_PROCESSOR_COUNT - Get processor count
665-----------------------------------------
666
667CALLING SEQUENCE:
668    .. code-block:: c
669
670        uint32_t rtems_get_processor_count(void);
671
672DIRECTIVE STATUS CODES:
673    The count of processors in the system.
674
675DESCRIPTION:
676    On uni-processor configurations a value of one will be returned.
677
678    On SMP configurations this returns the value of a global variable set
679    during system initialization to indicate the count of utilized processors.
680    The processor count depends on the physically or virtually available
681    processors and application configuration.  The value will always be less
682    than or equal to the maximum count of application configured processors.
683
684NOTES:
685    None.
686
687.. raw:: latex
688
689   \clearpage
690
691.. _rtems_get_current_processor:
692
693GET_CURRENT_PROCESSOR - Get current processor index
694---------------------------------------------------
695
696CALLING SEQUENCE:
697    .. code-block:: c
698
699        uint32_t rtems_get_current_processor(void);
700
701DIRECTIVE STATUS CODES:
702    The index of the current processor.
703
704DESCRIPTION:
705    On uni-processor configurations a value of zero will be returned.
706
707    On SMP configurations an architecture specific method is used to obtain the
708    index of the current processor in the system.  The set of processor indices
709    is the range of integers starting with zero up to the processor count minus
710    one.
711
712    Outside of sections with disabled thread dispatching the current processor
713    index may change after every instruction since the thread may migrate from
714    one processor to another.  Sections with disabled interrupts are sections
715    with thread dispatching disabled.
716
717NOTES:
718    None.
719
720.. raw:: latex
721
722   \clearpage
723
724.. _rtems_scheduler_ident:
725
726SCHEDULER_IDENT - Get ID of a scheduler
727---------------------------------------
728
729CALLING SEQUENCE:
730    .. code-block:: c
731
732        rtems_status_code rtems_scheduler_ident(
733            rtems_name  name,
734            rtems_id   *id
735        );
736
737DIRECTIVE STATUS CODES:
738    .. list-table::
739     :class: rtems-table
740
741     * - ``RTEMS_SUCCESSFUL``
742       - Successful operation.
743     * - ``RTEMS_INVALID_ADDRESS``
744       - The ``id`` parameter is ``NULL``.
745     * - ``RTEMS_INVALID_NAME``
746       - Invalid scheduler name.
747
748DESCRIPTION:
749    Identifies a scheduler by its name.  The scheduler name is determined by
750    the scheduler configuration.  See :ref:`Configuring Clustered Schedulers`
751    and :ref:`Configuring a Scheduler Name`.
752
753NOTES:
754    None.
755
756.. raw:: latex
757
758   \clearpage
759
760.. _rtems_scheduler_get_processor_set:
761
762SCHEDULER_GET_PROCESSOR_SET - Get processor set of a scheduler
763--------------------------------------------------------------
764
765CALLING SEQUENCE:
766    .. code-block:: c
767
768        rtems_status_code rtems_scheduler_get_processor_set(
769            rtems_id   scheduler_id,
770            size_t     cpusetsize,
771            cpu_set_t *cpuset
772        );
773
774DIRECTIVE STATUS CODES:
775    .. list-table::
776     :class: rtems-table
777
778     * - ``RTEMS_SUCCESSFUL``
779       - Successful operation.
780     * - ``RTEMS_INVALID_ID``
781       - Invalid scheduler instance identifier.
782     * - ``RTEMS_INVALID_ADDRESS``
783       - The ``cpuset`` parameter is ``NULL``.
784     * - ``RTEMS_INVALID_NUMBER``
785       - The processor set buffer is too small for the set of processors owned
786         by the scheduler instance.
787
788DESCRIPTION:
789    Returns the processor set owned by the scheduler instance in ``cpuset``.  A
790    set bit in the processor set means that this processor is owned by the
791    scheduler instance and a cleared bit means the opposite.
792
793NOTES:
794    None.
795
796.. raw:: latex
797
798   \clearpage
799
800.. _rtems_scheduler_add_processor:
801
802SCHEDULER_ADD_PROCESSOR - Add processor to a scheduler
803------------------------------------------------------
804
805CALLING SEQUENCE:
806    .. code-block:: c
807
808        rtems_status_code rtems_scheduler_add_processor(
809            rtems_id scheduler_id,
810            uint32_t cpu_index
811        );
812
813DIRECTIVE STATUS CODES:
814    .. list-table::
815     :class: rtems-table
816
817     * - ``RTEMS_SUCCESSFUL``
818       - Successful operation.
819     * - ``RTEMS_INVALID_ID``
820       - Invalid scheduler instance identifier.
821     * - ``RTEMS_NOT_CONFIGURED``
822       - The processor is not configured to be used by the application.
823     * - ``RTEMS_INCORRECT_STATE``
824       - The processor is configured to be used by the application, however, it
825         is not online.
826     * - ``RTEMS_RESOURCE_IN_USE``
827       - The processor is already assigned to a scheduler instance.
828
829DESCRIPTION:
830    Adds a processor to the set of processors owned by the specified scheduler
831    instance.
832
833NOTES:
834    Must be called from task context.  This operation obtains and releases the
835    objects allocator lock.
836
837.. raw:: latex
838
839   \clearpage
840
841.. _rtems_scheduler_remove_processor:
842
843SCHEDULER_REMOVE_PROCESSOR - Remove processor from a scheduler
844--------------------------------------------------------------
845
846CALLING SEQUENCE:
847    .. code-block:: c
848
849        rtems_status_code rtems_scheduler_remove_processor(
850            rtems_id scheduler_id,
851            uint32_t cpu_index
852        );
853
854DIRECTIVE STATUS CODES:
855    .. list-table::
856     :class: rtems-table
857
858     * - ``RTEMS_SUCCESSFUL``
859       - Successful operation.
860     * - ``RTEMS_INVALID_ID``
861       - Invalid scheduler instance identifier.
862     * - ``RTEMS_INVALID_NUMBER``
863       - The processor is not owned by the specified scheduler instance.
864     * - ``RTEMS_RESOURCE_IN_USE``
865       - The set of processors owned by the specified scheduler instance would
866         be empty after the processor removal and there exists a non-idle task
867         that uses this scheduler instance as its home scheduler instance.
868
869DESCRIPTION:
870    Removes a processor from set of processors owned by the specified scheduler
871    instance.
872
873NOTES:
874    Must be called from task context.  This operation obtains and releases the
875    objects allocator lock.  Removing a processor from a scheduler is a complex
876    operation that involves all tasks of the system.
877
878.. raw:: latex
879
880   \clearpage
881
882.. _rtems_task_get_scheduler:
883
884TASK_GET_SCHEDULER - Get scheduler of a task
885--------------------------------------------
886
887CALLING SEQUENCE:
888    .. code-block:: c
889
890        rtems_status_code rtems_task_get_scheduler(
891            rtems_id  task_id,
892            rtems_id *scheduler_id
893        );
894
895DIRECTIVE STATUS CODES:
896    .. list-table::
897     :class: rtems-table
898
899     * - ``RTEMS_SUCCESSFUL``
900       - successful operation
901     * - ``RTEMS_INVALID_ADDRESS``
902       - ``scheduler_id`` is NULL
903     * - ``RTEMS_INVALID_ID``
904       - invalid task id
905
906DESCRIPTION:
907    Returns the scheduler identifier of a task identified by ``task_id`` in
908    ``scheduler_id``.
909
910NOTES:
911    None.
912
913.. raw:: latex
914
915   \clearpage
916
917.. _rtems_task_set_scheduler:
918.. _TASK_SET_SCHEDULER - Set scheduler of a task:
919
920TASK_SET_SCHEDULER - Set scheduler of a task
921--------------------------------------------
922
923CALLING SEQUENCE:
924    .. code-block:: c
925
926        rtems_status_code rtems_task_set_scheduler(
927            rtems_id task_id,
928            rtems_id scheduler_id
929        );
930
931DIRECTIVE STATUS CODES:
932    .. list-table::
933     :class: rtems-table
934
935     * - ``RTEMS_SUCCESSFUL``
936       - successful operation
937     * - ``RTEMS_INVALID_ID``
938       - invalid task or scheduler id
939     * - ``RTEMS_INCORRECT_STATE``
940       - the task is in the wrong state to perform a scheduler change
941
942DESCRIPTION:
943    Sets the scheduler of a task identified by ``task_id`` to the scheduler
944    identified by ``scheduler_id``.  The scheduler of a task is initialized to
945    the scheduler of the task that created it.
946
947NOTES:
948    None.
949
950EXAMPLE:
951    .. code-block:: c
952        :linenos:
953
954        #include <rtems.h>
955        #include <assert.h>
956
957        void task(rtems_task_argument arg);
958
959        void example(void)
960        {
961            rtems_status_code sc;
962            rtems_id          task_id;
963            rtems_id          scheduler_id;
964            rtems_name        scheduler_name;
965
966            scheduler_name = rtems_build_name('W', 'O', 'R', 'K');
967
968            sc = rtems_scheduler_ident(scheduler_name, &scheduler_id);
969            assert(sc == RTEMS_SUCCESSFUL);
970
971            sc = rtems_task_create(
972                    rtems_build_name('T', 'A', 'S', 'K'),
973                    1,
974                    RTEMS_MINIMUM_STACK_SIZE,
975                    RTEMS_DEFAULT_MODES,
976                    RTEMS_DEFAULT_ATTRIBUTES,
977                    &task_id
978                 );
979            assert(sc == RTEMS_SUCCESSFUL);
980
981            sc = rtems_task_set_scheduler(task_id, scheduler_id);
982            assert(sc == RTEMS_SUCCESSFUL);
983
984            sc = rtems_task_start(task_id, task, 0);
985            assert(sc == RTEMS_SUCCESSFUL);
986        }
987
988.. raw:: latex
989
990   \clearpage
991
992.. _rtems_task_get_affinity:
993
994TASK_GET_AFFINITY - Get task processor affinity
995-----------------------------------------------
996
997CALLING SEQUENCE:
998    .. code-block:: c
999
1000        rtems_status_code rtems_task_get_affinity(
1001            rtems_id   id,
1002            size_t     cpusetsize,
1003            cpu_set_t *cpuset
1004        );
1005
1006DIRECTIVE STATUS CODES:
1007    .. list-table::
1008     :class: rtems-table
1009
1010     * - ``RTEMS_SUCCESSFUL``
1011       - successful operation
1012     * - ``RTEMS_INVALID_ADDRESS``
1013       - ``cpuset`` is NULL
1014     * - ``RTEMS_INVALID_ID``
1015       - invalid task id
1016     * - ``RTEMS_INVALID_NUMBER``
1017       - the affinity set buffer is too small for the current processor affinity
1018         set of the task
1019
1020DESCRIPTION:
1021    Returns the current processor affinity set of the task in ``cpuset``.  A
1022    set bit in the affinity set means that the task can execute on this
1023    processor and a cleared bit means the opposite.
1024
1025NOTES:
1026    None.
1027
1028.. raw:: latex
1029
1030   \clearpage
1031
1032.. _rtems_task_set_affinity:
1033
1034TASK_SET_AFFINITY - Set task processor affinity
1035-----------------------------------------------
1036
1037CALLING SEQUENCE:
1038    .. code-block:: c
1039
1040        rtems_status_code rtems_task_set_affinity(
1041            rtems_id         id,
1042            size_t           cpusetsize,
1043            const cpu_set_t *cpuset
1044        );
1045
1046DIRECTIVE STATUS CODES:
1047    .. list-table::
1048     :class: rtems-table
1049
1050     * - ``RTEMS_SUCCESSFUL``
1051       - successful operation
1052     * - ``RTEMS_INVALID_ADDRESS``
1053       - ``cpuset`` is NULL
1054     * - ``RTEMS_INVALID_ID``
1055       - invalid task id
1056     * - ``RTEMS_INVALID_NUMBER``
1057       - invalid processor affinity set
1058
1059DESCRIPTION:
1060    Sets the processor affinity set for the task specified by ``cpuset``.  A
1061    set bit in the affinity set means that the task can execute on this
1062    processor and a cleared bit means the opposite.
1063
1064NOTES:
1065    This function will not change the scheduler of the task.  The intersection
1066    of the processor affinity set and the set of processors owned by the
1067    scheduler of the task must be non-empty.  It is not an error if the
1068    processor affinity set contains processors that are not part of the set of
1069    processors owned by the scheduler instance of the task.  A task will simply
1070    not run under normal circumstances on these processors since the scheduler
1071    ignores them.  Some locking protocols may temporarily use processors that
1072    are not included in the processor affinity set of the task.  It is also not
1073    an error if the processor affinity set contains processors that are not
1074    part of the system.
Note: See TracBrowser for help on using the repository browser.