source: rtems-docs/c_user/symmetric_multiprocessing_services.rst @ fd6dc8c8

4.115
Last change on this file since fd6dc8c8 was fd6dc8c8, checked in by Amar Takhar <amar@…>, on 01/18/16 at 00:19:43

Split document into seperate files by section.

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