source: rtems/cpukit/score/include/rtems/score/percpu.h @ 8e7db68c

4.115
Last change on this file since 8e7db68c was 38b59a6, checked in by Sebastian Huber <sebastian.huber@…>, on 05/02/14 at 08:31:09

score: Implement forced thread migration

The current implementation of task migration in RTEMS has some
implications with respect to the interrupt latency. It is crucial to
preserve the system invariant that a task can execute on at most one
processor in the system at a time. This is accomplished with a boolean
indicator in the task context. The processor architecture specific
low-level task context switch code will mark that a task context is no
longer executing and waits that the heir context stopped execution
before it restores the heir context and resumes execution of the heir
task. So there is one point in time in which a processor is without a
task. This is essential to avoid cyclic dependencies in case multiple
tasks migrate at once. Otherwise some supervising entity is necessary to
prevent life-locks. Such a global supervisor would lead to scalability
problems so this approach is not used. Currently the thread dispatch is
performed with interrupts disabled. So in case the heir task is
currently executing on another processor then this prolongs the time of
disabled interrupts since one processor has to wait for another
processor to make progress.

It is difficult to avoid this issue with the interrupt latency since
interrupts normally store the context of the interrupted task on its
stack. In case a task is marked as not executing we must not use its
task stack to store such an interrupt context. We cannot use the heir
stack before it stopped execution on another processor. So if we enable
interrupts during this transition we have to provide an alternative task
independent stack for this time frame. This issue needs further
investigation.

  • Property mode set to 100644
File size: 18.6 KB
Line 
1/**
2 *  @file  rtems/score/percpu.h
3 *
4 *  This include file defines the per CPU information required
5 *  by RTEMS.
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2011.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#ifndef _RTEMS_PERCPU_H
18#define _RTEMS_PERCPU_H
19
20#include <rtems/score/cpu.h>
21
22#if defined( ASM )
23  #include <rtems/asm.h>
24#else
25  #include <rtems/score/assert.h>
26  #include <rtems/score/isrlevel.h>
27  #include <rtems/score/smp.h>
28  #include <rtems/score/smplock.h>
29  #include <rtems/score/timestamp.h>
30#endif
31
32#ifdef __cplusplus
33extern "C" {
34#endif
35
36#if defined( RTEMS_SMP )
37  /*
38   * This ensures that on SMP configurations the individual per-CPU controls
39   * are on different cache lines to prevent false sharing.  This define can be
40   * used in assembler code to easily get the per-CPU control for a particular
41   * processor.
42   */
43  #if defined( RTEMS_PROFILING )
44    #define PER_CPU_CONTROL_SIZE_LOG2 8
45  #else
46    #define PER_CPU_CONTROL_SIZE_LOG2 7
47  #endif
48
49  #define PER_CPU_CONTROL_SIZE ( 1 << PER_CPU_CONTROL_SIZE_LOG2 )
50#endif
51
52#if !defined( ASM )
53
54#ifndef __THREAD_CONTROL_DEFINED__
55#define __THREAD_CONTROL_DEFINED__
56typedef struct Thread_Control_struct Thread_Control;
57#endif
58
59struct Scheduler_Context;
60
61/**
62 *  @defgroup PerCPU RTEMS Per CPU Information
63 *
64 *  @ingroup Score
65 *
66 *  This defines the per CPU state information required by RTEMS
67 *  and the BSP.  In an SMP configuration, there will be multiple
68 *  instances of this data structure -- one per CPU -- and the
69 *  current CPU number will be used as the index.
70 */
71
72/**@{*/
73
74#if defined( RTEMS_SMP )
75
76#if CPU_USE_DEFERRED_FP_SWITCH == TRUE
77  #error "deferred FP switch not implemented for SMP"
78#endif
79
80/**
81 * @brief State of a processor.
82 *
83 * The processor state controls the life cycle of processors at the lowest
84 * level.  No multi-threading or other high-level concepts matter here.
85 *
86 * State changes must be initiated via _Per_CPU_State_change().  This function
87 * may not return in case someone requested a shutdown.  The
88 * _SMP_Send_message() function will be used to notify other processors about
89 * state changes if the other processor is in the up state.
90 *
91 * Due to the sequential nature of the basic system initialization one
92 * processor has a special role.  It is the processor executing the boot_card()
93 * function.  This processor is called the boot processor.  All other
94 * processors are called secondary.
95 *
96 * @dot
97 * digraph states {
98 *   i [label="PER_CPU_STATE_INITIAL"];
99 *   rdy [label="PER_CPU_STATE_READY_TO_START_MULTITASKING"];
100 *   reqsm [label="PER_CPU_STATE_REQUEST_START_MULTITASKING"];
101 *   u [label="PER_CPU_STATE_UP"];
102 *   s [label="PER_CPU_STATE_SHUTDOWN"];
103 *   i -> rdy [label="processor\ncompleted initialization"];
104 *   rdy -> reqsm [label="boot processor\ncompleted initialization"];
105 *   reqsm -> u [label="processor\nstarts multitasking"];
106 *   i -> s;
107 *   rdy -> s;
108 *   reqsm -> s;
109 *   u -> s;
110 * }
111 * @enddot
112 */
113typedef enum {
114  /**
115   * @brief The per CPU controls are initialized to zero.
116   *
117   * The boot processor executes the sequential boot code in this state.  The
118   * secondary processors should perform their basic initialization now and
119   * change into the PER_CPU_STATE_READY_TO_START_MULTITASKING state once this
120   * is complete.
121   */
122  PER_CPU_STATE_INITIAL,
123
124  /**
125   * @brief Processor is ready to start multitasking.
126   *
127   * The secondary processor performed its basic initialization and is ready to
128   * receive inter-processor interrupts.  Interrupt delivery must be disabled
129   * in this state, but requested inter-processor interrupts must be recorded
130   * and must be delivered once the secondary processor enables interrupts for
131   * the first time.  The boot processor will wait for all secondary processors
132   * to change into this state.  In case a secondary processor does not reach
133   * this state the system will not start.  The secondary processors wait now
134   * for a change into the PER_CPU_STATE_REQUEST_START_MULTITASKING state set
135   * by the boot processor once all secondary processors reached the
136   * PER_CPU_STATE_READY_TO_START_MULTITASKING state.
137   */
138  PER_CPU_STATE_READY_TO_START_MULTITASKING,
139
140  /**
141   * @brief Multitasking start of processor is requested.
142   *
143   * The boot processor completed system initialization and is about to perform
144   * a context switch to its heir thread.  Secondary processors should now
145   * issue a context switch to the heir thread.  This normally enables
146   * interrupts on the processor for the first time.
147   */
148  PER_CPU_STATE_REQUEST_START_MULTITASKING,
149
150  /**
151   * @brief Normal multitasking state.
152   */
153  PER_CPU_STATE_UP,
154
155  /**
156   * @brief This is the terminal state.
157   */
158  PER_CPU_STATE_SHUTDOWN
159} Per_CPU_State;
160
161#endif /* defined( RTEMS_SMP ) */
162
163/**
164 * @brief Per-CPU statistics.
165 */
166typedef struct {
167#if defined( RTEMS_PROFILING )
168  /**
169   * @brief The thread dispatch disabled begin instant in CPU counter ticks.
170   *
171   * This value is used to measure the time of disabled thread dispatching.
172   */
173  CPU_Counter_ticks thread_dispatch_disabled_instant;
174
175  /**
176   * @brief The maximum time of disabled thread dispatching in CPU counter
177   * ticks.
178   */
179  CPU_Counter_ticks max_thread_dispatch_disabled_time;
180
181  /**
182   * @brief The maximum time spent to process a single sequence of nested
183   * interrupts in CPU counter ticks.
184   *
185   * This is the time interval between the change of the interrupt nest level
186   * from zero to one and the change back from one to zero.
187   */
188  CPU_Counter_ticks max_interrupt_time;
189
190  /**
191   * @brief The maximum interrupt delay in CPU counter ticks if supported by
192   * the hardware.
193   */
194  CPU_Counter_ticks max_interrupt_delay;
195
196  /**
197   * @brief Count of times when the thread dispatch disable level changes from
198   * zero to one in thread context.
199   *
200   * This value may overflow.
201   */
202  uint64_t thread_dispatch_disabled_count;
203
204  /**
205   * @brief Total time of disabled thread dispatching in CPU counter ticks.
206   *
207   * The average time of disabled thread dispatching is the total time of
208   * disabled thread dispatching divided by the thread dispatch disabled
209   * count.
210   *
211   * This value may overflow.
212   */
213  uint64_t total_thread_dispatch_disabled_time;
214
215  /**
216   * @brief Count of times when the interrupt nest level changes from zero to
217   * one.
218   *
219   * This value may overflow.
220   */
221  uint64_t interrupt_count;
222
223  /**
224   * @brief Total time of interrupt processing in CPU counter ticks.
225   *
226   * The average time of interrupt processing is the total time of interrupt
227   * processing divided by the interrupt count.
228   *
229   * This value may overflow.
230   */
231  uint64_t total_interrupt_time;
232#endif /* defined( RTEMS_PROFILING ) */
233} Per_CPU_Stats;
234
235/**
236 *  @brief Per CPU Core Structure
237 *
238 *  This structure is used to hold per core state information.
239 */
240typedef struct Per_CPU_Control {
241  /**
242   * @brief CPU port specific control.
243   */
244  CPU_Per_CPU_control cpu_per_cpu;
245
246  #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) || \
247      (CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
248    /**
249     * This contains a pointer to the lower range of the interrupt stack for
250     * this CPU.  This is the address allocated and freed.
251     */
252    void  *interrupt_stack_low;
253
254    /**
255     * This contains a pointer to the interrupt stack pointer for this CPU.
256     * It will be loaded at the beginning on an ISR.
257     */
258    void  *interrupt_stack_high;
259  #endif
260
261  /**
262   *  This contains the current interrupt nesting level on this
263   *  CPU.
264   */
265  uint32_t isr_nest_level;
266
267  /**
268   * @brief The thread dispatch critical section nesting counter which is used
269   * to prevent context switches at inopportune moments.
270   */
271  volatile uint32_t thread_dispatch_disable_level;
272
273  /**
274   * @brief This is set to true when this processor needs to run the
275   * dispatcher.
276   *
277   * It is volatile since interrupts may alter this flag.
278   *
279   * This field is not protected by a lock.  There are two writers after
280   * multitasking start.  The scheduler owning this processor sets this
281   * indicator to true, after it updated the heir field.  This processor sets
282   * this indicator to false, before it reads the heir.  This field is used in
283   * combination with the heir field.
284   *
285   * @see _Thread_Get_heir_and_make_it_executing().
286   */
287  volatile bool dispatch_necessary;
288
289  /**
290   * @brief This is the thread executing on this processor.
291   *
292   * This field is not protected by a lock.  The only writer is this processor.
293   *
294   * On SMP configurations a thread may be registered as executing on more than
295   * one processor in case a thread migration is in progress.  On SMP
296   * configurations use _Thread_Is_executing_on_a_processor() to figure out if
297   * a thread context is executing on a processor.
298   */
299  Thread_Control *executing;
300
301  /**
302   * @brief This is the heir thread for this processor.
303   *
304   * This field is not protected by a lock.  The only writer after multitasking
305   * start is the scheduler owning this processor.  This processor will set the
306   * dispatch necessary indicator to false, before it reads the heir.  This
307   * field is used in combination with the dispatch necessary indicator.
308   *
309   * A thread can be a heir on at most one processor in the system.
310   *
311   * @see _Thread_Get_heir_and_make_it_executing().
312   */
313  Thread_Control *heir;
314
315  /** This is the time of the last context switch on this CPU. */
316  Timestamp_Control time_of_last_context_switch;
317
318  #if defined( RTEMS_SMP )
319    /**
320     * @brief This lock protects some parts of the low-level thread dispatching.
321     *
322     * We must use a ticket lock here since we cannot transport a local context
323     * through the context switch.
324     *
325     * @see _Thread_Dispatch().
326     */
327    SMP_ticket_lock_Control Lock;
328
329    /**
330     * @brief Lock statistics context for the per-CPU lock.
331     */
332    SMP_lock_Stats_context Lock_stats_context;
333
334    /**
335     * @brief Context for the Giant lock acquire and release pair of this
336     * processor.
337     */
338    SMP_lock_Context Giant_lock_context;
339
340    /**
341     * @brief Bit field for SMP messages.
342     *
343     * This bit field is not protected locks.  Atomic operations are used to
344     * set and get the message bits.
345     */
346    Atomic_Ulong message;
347
348    /**
349     * @brief The scheduler context of the scheduler owning this processor.
350     */
351    const struct Scheduler_Context *scheduler_context;
352
353    /**
354     * @brief Indicates the current state of the CPU.
355     *
356     * This field is protected by the _Per_CPU_State_lock lock.
357     *
358     * @see _Per_CPU_State_change().
359     */
360    Per_CPU_State state;
361
362    /**
363     * @brief Indicates if the processor has been successfully started via
364     * _CPU_SMP_Start_processor().
365     */
366    bool started;
367  #endif
368
369  Per_CPU_Stats Stats;
370} Per_CPU_Control;
371
372#if defined( RTEMS_SMP )
373typedef struct {
374  Per_CPU_Control per_cpu;
375  char unused_space_for_cache_line_alignment
376    [ PER_CPU_CONTROL_SIZE - sizeof( Per_CPU_Control ) ];
377} Per_CPU_Control_envelope;
378#else
379typedef struct {
380  Per_CPU_Control per_cpu;
381} Per_CPU_Control_envelope;
382#endif
383
384/**
385 *  @brief Set of Per CPU Core Information
386 *
387 *  This is an array of per CPU core information.
388 */
389extern Per_CPU_Control_envelope _Per_CPU_Information[] CPU_STRUCTURE_ALIGNMENT;
390
391#if defined( RTEMS_SMP )
392#define _Per_CPU_Acquire( cpu ) \
393  _SMP_ticket_lock_Acquire( \
394    &( cpu )->Lock, \
395    &( cpu )->Lock_stats_context \
396  )
397#else
398#define _Per_CPU_Acquire( cpu ) \
399  do { \
400    (void) ( cpu ); \
401  } while ( 0 )
402#endif
403
404#if defined( RTEMS_SMP )
405#define _Per_CPU_Release( cpu ) \
406  _SMP_ticket_lock_Release( \
407    &( cpu )->Lock, \
408    &( cpu )->Lock_stats_context \
409  )
410#else
411#define _Per_CPU_Release( cpu ) \
412  do { \
413    (void) ( cpu ); \
414  } while ( 0 )
415#endif
416
417#if defined( RTEMS_SMP )
418#define _Per_CPU_ISR_disable_and_acquire( cpu, isr_cookie ) \
419  do { \
420    _ISR_Disable_without_giant( isr_cookie ); \
421    _Per_CPU_Acquire( cpu ); \
422  } while ( 0 )
423#else
424#define _Per_CPU_ISR_disable_and_acquire( cpu, isr_cookie ) \
425  do { \
426    _ISR_Disable( isr_cookie ); \
427    (void) ( cpu ); \
428  } while ( 0 )
429#endif
430
431#if defined( RTEMS_SMP )
432#define _Per_CPU_Release_and_ISR_enable( cpu, isr_cookie ) \
433  do { \
434    _Per_CPU_Release( cpu ); \
435    _ISR_Enable_without_giant( isr_cookie ); \
436  } while ( 0 )
437#else
438#define _Per_CPU_Release_and_ISR_enable( cpu, isr_cookie ) \
439  do { \
440    (void) ( cpu ); \
441    _ISR_Enable( isr_cookie ); \
442  } while ( 0 )
443#endif
444
445#if defined( RTEMS_SMP )
446#define _Per_CPU_Acquire_all( isr_cookie ) \
447  do { \
448    uint32_t ncpus = _SMP_Get_processor_count(); \
449    uint32_t cpu; \
450    _ISR_Disable( isr_cookie ); \
451    for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { \
452      _Per_CPU_Acquire( _Per_CPU_Get_by_index( cpu ) ); \
453    } \
454  } while ( 0 )
455#else
456#define _Per_CPU_Acquire_all( isr_cookie ) \
457  _ISR_Disable( isr_cookie )
458#endif
459
460#if defined( RTEMS_SMP )
461#define _Per_CPU_Release_all( isr_cookie ) \
462  do { \
463    uint32_t ncpus = _SMP_Get_processor_count(); \
464    uint32_t cpu; \
465    for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { \
466      _Per_CPU_Release( _Per_CPU_Get_by_index( cpu ) ); \
467    } \
468    _ISR_Enable( isr_cookie ); \
469  } while ( 0 )
470#else
471#define _Per_CPU_Release_all( isr_cookie ) \
472  _ISR_Enable( isr_cookie )
473#endif
474
475/*
476 * If we get the current processor index in a context which allows thread
477 * dispatching, then we may already run on another processor right after the
478 * read instruction.  There are very few cases in which this makes sense (here
479 * we can use _Per_CPU_Get_snapshot()).  All other places must use
480 * _Per_CPU_Get() so that we can add checks for RTEMS_DEBUG.
481 */
482#if defined( _CPU_Get_current_per_CPU_control )
483  #define _Per_CPU_Get_snapshot() _CPU_Get_current_per_CPU_control()
484#else
485  #define _Per_CPU_Get_snapshot() \
486    ( &_Per_CPU_Information[ _SMP_Get_current_processor() ].per_cpu )
487#endif
488
489#if defined( RTEMS_SMP )
490static inline Per_CPU_Control *_Per_CPU_Get( void )
491{
492  Per_CPU_Control *cpu_self = _Per_CPU_Get_snapshot();
493
494  _Assert(
495    cpu_self->thread_dispatch_disable_level != 0 || _ISR_Get_level() != 0
496  );
497
498  return cpu_self;
499}
500#else
501#define _Per_CPU_Get() _Per_CPU_Get_snapshot()
502#endif
503
504static inline Per_CPU_Control *_Per_CPU_Get_by_index( uint32_t index )
505{
506  return &_Per_CPU_Information[ index ].per_cpu;
507}
508
509static inline uint32_t _Per_CPU_Get_index( const Per_CPU_Control *cpu )
510{
511  const Per_CPU_Control_envelope *per_cpu_envelope =
512    ( const Per_CPU_Control_envelope * ) cpu;
513
514  return ( uint32_t ) ( per_cpu_envelope - &_Per_CPU_Information[ 0 ] );
515}
516
517static inline bool _Per_CPU_Is_processor_started(
518  const Per_CPU_Control *cpu
519)
520{
521#if defined( RTEMS_SMP )
522  return cpu->started;
523#else
524  (void) cpu;
525
526  return true;
527#endif
528}
529
530#if defined( RTEMS_SMP )
531
532static inline void _Per_CPU_Send_interrupt( const Per_CPU_Control *cpu )
533{
534  _CPU_SMP_Send_interrupt( _Per_CPU_Get_index( cpu ) );
535}
536
537/**
538 *  @brief Allocate and Initialize Per CPU Structures
539 *
540 *  This method allocates and initialize the per CPU structure.
541 */
542void _Per_CPU_Initialize(void);
543
544void _Per_CPU_State_change(
545  Per_CPU_Control *cpu,
546  Per_CPU_State new_state
547);
548
549/**
550 * @brief Waits for all other processors to enter the ready to start
551 * multitasking state with a timeout in microseconds.
552 *
553 * In case one processor enters the shutdown state, this function does not
554 * return and terminates the system with the SMP_FATAL_SHUTDOWN_EARLY fatal SMP
555 * error.
556 *
557 * This function should be called only in _CPU_SMP_Initialize() if required by
558 * the CPU port or BSP.
559 *
560 * @code
561 * uint32_t _CPU_SMP_Initialize(uint32_t configured_cpu_count)
562 * {
563 *   uint32_t cnt = MIN(get_hardware_cpu_count(), configured_cpu_count);
564 *   uint32_t timeout = 123456;
565 *
566 *   do_some_stuff();
567 *
568 *   return _Per_CPU_State_wait_for_ready_to_start_multitasking(cnt, timeout);
569 * }
570 * @endcode
571 *
572 * In case the timeout expires the count of processors is reduced to reflect
573 * the set of processors which is actually available at this point in time.
574 *
575 * @param[in] processor_count The processor count is the minimum value of the
576 * configured count of processors and the processor count offered by the actual
577 * hardware.
578 * @param[in] timeout_in_us The timeout in microseconds.
579 *
580 * @return The count of processors available for the application in the system.
581 * This value is less than or equal to the processor count.
582 */
583uint32_t _Per_CPU_State_wait_for_ready_to_start_multitasking(
584  uint32_t processor_count,
585  uint32_t timeout_in_us
586);
587
588#endif /* defined( RTEMS_SMP ) */
589
590/*
591 * On a non SMP system, the _SMP_Get_current_processor() is defined to 0.
592 * Thus when built for non-SMP, there should be no performance penalty.
593 */
594#define _Thread_Dispatch_disable_level \
595  _Per_CPU_Get()->thread_dispatch_disable_level
596#define _Thread_Heir \
597  _Per_CPU_Get()->heir
598#define _Thread_Executing \
599  _Per_CPU_Get()->executing
600#define _ISR_Nest_level \
601  _Per_CPU_Get()->isr_nest_level
602#define _CPU_Interrupt_stack_low \
603  _Per_CPU_Get()->interrupt_stack_low
604#define _CPU_Interrupt_stack_high \
605  _Per_CPU_Get()->interrupt_stack_high
606#define _Thread_Dispatch_necessary \
607  _Per_CPU_Get()->dispatch_necessary
608#define _Thread_Time_of_last_context_switch \
609  _Per_CPU_Get()->time_of_last_context_switch
610
611/**@}*/
612
613#endif /* !defined( ASM ) */
614
615#if defined( ASM ) || defined( _RTEMS_PERCPU_DEFINE_OFFSETS )
616
617#if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) || \
618    (CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
619  /*
620   *  If this CPU target lets RTEMS allocates the interrupt stack, then
621   *  we need to have places in the per CPU table to hold them.
622   */
623  #define PER_CPU_INTERRUPT_STACK_LOW \
624    CPU_PER_CPU_CONTROL_SIZE
625  #define PER_CPU_INTERRUPT_STACK_HIGH \
626    PER_CPU_INTERRUPT_STACK_LOW + CPU_SIZEOF_POINTER
627  #define PER_CPU_END_STACK             \
628    PER_CPU_INTERRUPT_STACK_HIGH + CPU_SIZEOF_POINTER
629
630  #define INTERRUPT_STACK_LOW \
631    (SYM(_Per_CPU_Information) + PER_CPU_INTERRUPT_STACK_LOW)
632  #define INTERRUPT_STACK_HIGH \
633    (SYM(_Per_CPU_Information) + PER_CPU_INTERRUPT_STACK_HIGH)
634#else
635  #define PER_CPU_END_STACK \
636    CPU_PER_CPU_CONTROL_SIZE
637#endif
638
639/*
640 *  These are the offsets of the required elements in the per CPU table.
641 */
642#define PER_CPU_ISR_NEST_LEVEL \
643  PER_CPU_END_STACK
644#define PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL \
645  PER_CPU_ISR_NEST_LEVEL + 4
646#define PER_CPU_DISPATCH_NEEDED \
647  PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL + 4
648
649#define THREAD_DISPATCH_DISABLE_LEVEL \
650  (SYM(_Per_CPU_Information) + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)
651#define ISR_NEST_LEVEL \
652  (SYM(_Per_CPU_Information) + PER_CPU_ISR_NEST_LEVEL)
653#define DISPATCH_NEEDED \
654  (SYM(_Per_CPU_Information) + PER_CPU_DISPATCH_NEEDED)
655
656#endif /* defined( ASM ) || defined( _RTEMS_PERCPU_DEFINE_OFFSETS ) */
657
658#ifdef __cplusplus
659}
660#endif
661
662#endif
663/* end of include file */
Note: See TracBrowser for help on using the repository browser.