RTEMS CPU Kit with SuperCore  4.11.2
smplock.h
Go to the documentation of this file.
1 
9 /*
10  * COPYRIGHT (c) 1989-2011.
11  * On-Line Applications Research Corporation (OAR).
12  *
13  * Copyright (c) 2013-2015 embedded brains GmbH
14  *
15  * The license and distribution terms for this file may be
16  * found in the file LICENSE in this distribution or at
17  * http://www.rtems.org/license/LICENSE.
18  */
19 
20 #ifndef _RTEMS_SCORE_SMPLOCK_H
21 #define _RTEMS_SCORE_SMPLOCK_H
22 
23 #include <rtems/score/cpuopts.h>
24 
25 #if defined( RTEMS_SMP )
26 
27 #include <rtems/score/atomic.h>
28 #include <rtems/score/isrlevel.h>
29 
30 #if defined( RTEMS_PROFILING )
31 #include <rtems/score/chainimpl.h>
32 #include <string.h>
33 #endif
34 
35 #if defined( RTEMS_PROFILING )
36 #define RTEMS_SMP_LOCK_DO_NOT_INLINE
37 #endif
38 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif /* __cplusplus */
42 
61 #if defined( RTEMS_PROFILING )
62 
66 #define SMP_LOCK_STATS_CONTENTION_COUNTS 4
67 
86 typedef struct {
90  Chain_Node Node;
91 
95  CPU_Counter_ticks max_acquire_time;
96 
100  CPU_Counter_ticks max_section_time;
101 
107  uint64_t usage_count;
108 
118  uint64_t total_acquire_time;
119 
130  uint64_t contention_counts[SMP_LOCK_STATS_CONTENTION_COUNTS];
131 
140  uint64_t total_section_time;
141 
145  const char *name;
146 } SMP_lock_Stats;
147 
151 typedef struct {
157  CPU_Counter_ticks acquire_instant;
158 
162  SMP_lock_Stats *stats;
163 } SMP_lock_Stats_context;
164 
168 #define SMP_LOCK_STATS_INITIALIZER( name ) \
169  { { NULL, NULL }, 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, name }
170 
178 static inline void _SMP_lock_Stats_initialize(
179  SMP_lock_Stats *stats,
180  const char *name
181 )
182 {
183  SMP_lock_Stats init = SMP_LOCK_STATS_INITIALIZER( name );
184 
185  *stats = init;
186 }
187 
193 static inline void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats );
194 
200 static inline void _SMP_lock_Stats_release_update(
201  const SMP_lock_Stats_context *stats_context
202 );
203 
204 #else /* RTEMS_PROFILING */
205 
206 #define _SMP_lock_Stats_initialize( stats, name ) do { } while ( 0 )
207 
208 #define _SMP_lock_Stats_destroy( stats ) do { } while ( 0 )
209 
210 #endif /* RTEMS_PROFILING */
211 
215 typedef struct {
216  Atomic_Uint next_ticket;
217  Atomic_Uint now_serving;
218 } SMP_ticket_lock_Control;
219 
223 #define SMP_TICKET_LOCK_INITIALIZER \
224  { \
225  ATOMIC_INITIALIZER_UINT( 0U ), \
226  ATOMIC_INITIALIZER_UINT( 0U ) \
227  }
228 
238 static inline void _SMP_ticket_lock_Initialize(
239  SMP_ticket_lock_Control *lock
240 )
241 {
242  _Atomic_Init_uint( &lock->next_ticket, 0U );
243  _Atomic_Init_uint( &lock->now_serving, 0U );
244 }
245 
253 static inline void _SMP_ticket_lock_Destroy( SMP_ticket_lock_Control *lock )
254 {
255  (void) lock;
256 }
257 
258 static inline void _SMP_ticket_lock_Do_acquire(
259  SMP_ticket_lock_Control *lock
260 #if defined( RTEMS_PROFILING )
261  ,
262  SMP_lock_Stats *stats,
263  SMP_lock_Stats_context *stats_context
264 #endif
265 )
266 {
267  unsigned int my_ticket;
268  unsigned int now_serving;
269 
270 #if defined( RTEMS_PROFILING )
271  CPU_Counter_ticks first;
272  CPU_Counter_ticks second;
273  CPU_Counter_ticks delta;
274  unsigned int initial_queue_length;
275 
276  first = _CPU_Counter_read();
277 #endif
278 
279  my_ticket =
280  _Atomic_Fetch_add_uint( &lock->next_ticket, 1U, ATOMIC_ORDER_ACQ_REL );
281 
282 #if defined( RTEMS_PROFILING )
283  now_serving =
284  _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_ACQUIRE );
285  initial_queue_length = my_ticket - now_serving;
286 
287  if ( initial_queue_length > 0 ) {
288 #endif
289 
290  do {
291  now_serving =
292  _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_ACQUIRE );
293  } while ( now_serving != my_ticket );
294 
295 #if defined( RTEMS_PROFILING )
296  }
297 
298  second = _CPU_Counter_read();
299  stats_context->acquire_instant = second;
300  delta = _CPU_Counter_difference( second, first );
301 
302  ++stats->usage_count;
303 
304  stats->total_acquire_time += delta;
305 
306  if ( stats->max_acquire_time < delta ) {
307  stats->max_acquire_time = delta;
308  }
309 
310  if ( initial_queue_length >= SMP_LOCK_STATS_CONTENTION_COUNTS ) {
311  initial_queue_length = SMP_LOCK_STATS_CONTENTION_COUNTS - 1;
312  }
313  ++stats->contention_counts[initial_queue_length];
314 
315  stats_context->stats = stats;
316 #endif
317 }
318 
330 #if defined( RTEMS_PROFILING )
331  #define _SMP_ticket_lock_Acquire( lock, stats, stats_context ) \
332  _SMP_ticket_lock_Do_acquire( lock, stats, stats_context )
333 #else
334  #define _SMP_ticket_lock_Acquire( lock, stats, stats_context ) \
335  _SMP_ticket_lock_Do_acquire( lock )
336 #endif
337 
338 static inline void _SMP_ticket_lock_Do_release(
339  SMP_ticket_lock_Control *lock
340 #if defined( RTEMS_PROFILING )
341  ,
342  const SMP_lock_Stats_context *stats_context
343 #endif
344 )
345 {
346  unsigned int current_ticket =
347  _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_RELAXED );
348  unsigned int next_ticket = current_ticket + 1U;
349 
350 #if defined( RTEMS_PROFILING )
351  _SMP_lock_Stats_release_update( stats_context );
352 #endif
353 
354  _Atomic_Store_uint( &lock->now_serving, next_ticket, ATOMIC_ORDER_RELEASE );
355 }
356 
363 #if defined( RTEMS_PROFILING )
364  #define _SMP_ticket_lock_Release( lock, stats_context ) \
365  _SMP_ticket_lock_Do_release( lock, stats_context )
366 #else
367  #define _SMP_ticket_lock_Release( lock, stats_context ) \
368  _SMP_ticket_lock_Do_release( lock )
369 #endif
370 
374 typedef struct {
375  SMP_ticket_lock_Control Ticket_lock;
376 #if defined( RTEMS_PROFILING )
377  SMP_lock_Stats Stats;
378 #endif
379 } SMP_lock_Control;
380 
384 typedef struct {
385  ISR_Level isr_level;
386 #if defined( RTEMS_PROFILING )
387  SMP_lock_Stats_context Stats_context;
388 #endif
389 } SMP_lock_Context;
390 
394 #if defined( RTEMS_PROFILING )
395  #define SMP_LOCK_INITIALIZER( name ) \
396  { SMP_TICKET_LOCK_INITIALIZER, SMP_LOCK_STATS_INITIALIZER( name ) }
397 #else
398  #define SMP_LOCK_INITIALIZER( name ) { SMP_TICKET_LOCK_INITIALIZER }
399 #endif
400 
410 #if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
411 void _SMP_lock_Initialize(
412  SMP_lock_Control *lock,
413  const char *name
414 );
415 
416 static inline void _SMP_lock_Initialize_body(
417 #else
418 static inline void _SMP_lock_Initialize(
419 #endif
420  SMP_lock_Control *lock,
421  const char *name
422 )
423 {
424  _SMP_ticket_lock_Initialize( &lock->Ticket_lock );
425 #if defined( RTEMS_PROFILING )
426  _SMP_lock_Stats_initialize( &lock->Stats, name );
427 #else
428  (void) name;
429 #endif
430 }
431 
439 #if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
440 void _SMP_lock_Destroy( SMP_lock_Control *lock );
441 
442 static inline void _SMP_lock_Destroy_body( SMP_lock_Control *lock )
443 #else
444 static inline void _SMP_lock_Destroy( SMP_lock_Control *lock )
445 #endif
446 {
447  _SMP_ticket_lock_Destroy( &lock->Ticket_lock );
448  _SMP_lock_Stats_destroy( &lock->Stats );
449 }
450 
462 #if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
463 void _SMP_lock_Acquire(
464  SMP_lock_Control *lock,
465  SMP_lock_Context *context
466 );
467 
468 static inline void _SMP_lock_Acquire_body(
469 #else
470 static inline void _SMP_lock_Acquire(
471 #endif
472  SMP_lock_Control *lock,
473  SMP_lock_Context *context
474 )
475 {
476  (void) context;
477  _SMP_ticket_lock_Acquire(
478  &lock->Ticket_lock,
479  &lock->Stats,
480  &context->Stats_context
481  );
482 }
483 
491 #if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
492 void _SMP_lock_Release(
493  SMP_lock_Control *lock,
494  SMP_lock_Context *context
495 );
496 
497 static inline void _SMP_lock_Release_body(
498 #else
499 static inline void _SMP_lock_Release(
500 #endif
501  SMP_lock_Control *lock,
502  SMP_lock_Context *context
503 )
504 {
505  (void) context;
506  _SMP_ticket_lock_Release(
507  &lock->Ticket_lock,
508  &context->Stats_context
509  );
510 }
511 
519 #if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
520 void _SMP_lock_ISR_disable_and_acquire(
521  SMP_lock_Control *lock,
522  SMP_lock_Context *context
523 );
524 
525 static inline void _SMP_lock_ISR_disable_and_acquire_body(
526 #else
527 static inline void _SMP_lock_ISR_disable_and_acquire(
528 #endif
529  SMP_lock_Control *lock,
530  SMP_lock_Context *context
531 )
532 {
533  _ISR_Disable_without_giant( context->isr_level );
534  _SMP_lock_Acquire( lock, context );
535 }
536 
544 #if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
545 void _SMP_lock_Release_and_ISR_enable(
546  SMP_lock_Control *lock,
547  SMP_lock_Context *context
548 );
549 
550 static inline void _SMP_lock_Release_and_ISR_enable_body(
551 #else
552 static inline void _SMP_lock_Release_and_ISR_enable(
553 #endif
554  SMP_lock_Control *lock,
555  SMP_lock_Context *context
556 )
557 {
558  _SMP_lock_Release( lock, context );
559  _ISR_Enable_without_giant( context->isr_level );
560 }
561 
562 #if defined( RTEMS_PROFILING )
563 
564 typedef struct {
565  SMP_lock_Control Lock;
566  Chain_Control Stats_chain;
567  Chain_Control Iterator_chain;
568 } SMP_lock_Stats_control;
569 
570 typedef struct {
571  Chain_Node Node;
572  SMP_lock_Stats *current;
573 } SMP_lock_Stats_iteration_context;
574 
575 extern SMP_lock_Stats_control _SMP_lock_Stats_control;
576 
577 static inline void _SMP_lock_Stats_iteration_start(
578  SMP_lock_Stats_iteration_context *iteration_context
579 )
580 {
581  SMP_lock_Stats_control *control = &_SMP_lock_Stats_control;
582  SMP_lock_Context lock_context;
583 
584  _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context );
585 
587  &control->Iterator_chain,
588  &iteration_context->Node
589  );
590  iteration_context->current =
591  (SMP_lock_Stats *) _Chain_First( &control->Stats_chain );
592 
593  _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context );
594 }
595 
596 static inline bool _SMP_lock_Stats_iteration_next(
597  SMP_lock_Stats_iteration_context *iteration_context,
598  SMP_lock_Stats *snapshot,
599  char *name,
600  size_t name_size
601 )
602 {
603  SMP_lock_Stats_control *control = &_SMP_lock_Stats_control;
604  SMP_lock_Context lock_context;
605  SMP_lock_Stats *current;
606  bool valid;
607 
608  _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context );
609 
610  current = iteration_context->current;
611  if ( !_Chain_Is_tail( &control->Stats_chain, &current->Node ) ) {
612  size_t name_len = current->name != NULL ? strlen(current->name) : 0;
613 
614  valid = true;
615 
616  iteration_context->current = (SMP_lock_Stats *)
617  _Chain_Next( &current->Node );
618 
619  *snapshot = *current;
620  snapshot->name = name;
621 
622  if ( name_len >= name_size ) {
623  name_len = name_size - 1;
624  }
625 
626  name[name_len] = '\0';
627  memcpy(name, current->name, name_len);
628  } else {
629  valid = false;
630  }
631 
632  _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context );
633 
634  return valid;
635 }
636 
637 static inline void _SMP_lock_Stats_iteration_stop(
638  SMP_lock_Stats_iteration_context *iteration_context
639 )
640 {
641  SMP_lock_Stats_control *control = &_SMP_lock_Stats_control;
642  SMP_lock_Context lock_context;
643 
644  _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context );
645  _Chain_Extract_unprotected( &iteration_context->Node );
646  _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context );
647 }
648 
649 static inline void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats )
650 {
651  if ( !_Chain_Is_node_off_chain( &stats->Node ) ) {
652  SMP_lock_Stats_control *control = &_SMP_lock_Stats_control;
653  SMP_lock_Context lock_context;
654  SMP_lock_Stats_iteration_context *iteration_context;
655  SMP_lock_Stats_iteration_context *iteration_context_tail;
656  SMP_lock_Stats *next_stats;
657 
658  _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context );
659 
660  next_stats = (SMP_lock_Stats *) _Chain_Next( &stats->Node );
661  _Chain_Extract_unprotected( &stats->Node );
662 
663  iteration_context = (SMP_lock_Stats_iteration_context *)
664  _Chain_First( &control->Iterator_chain );
665  iteration_context_tail = (SMP_lock_Stats_iteration_context *)
666  _Chain_Tail( &control->Iterator_chain );
667 
668  while ( iteration_context != iteration_context_tail ) {
669  if ( iteration_context->current == stats ) {
670  iteration_context->current = next_stats;
671  }
672 
673  iteration_context = (SMP_lock_Stats_iteration_context *)
674  _Chain_Next( &iteration_context->Node );
675  }
676 
677  _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context );
678  }
679 }
680 
681 static inline void _SMP_lock_Stats_release_update(
682  const SMP_lock_Stats_context *stats_context
683 )
684 {
685  SMP_lock_Stats *stats = stats_context->stats;
686  CPU_Counter_ticks first = stats_context->acquire_instant;
687  CPU_Counter_ticks second = _CPU_Counter_read();
688  CPU_Counter_ticks delta = _CPU_Counter_difference( second, first );
689 
690  stats->total_section_time += delta;
691 
692  if ( stats->max_section_time < delta ) {
693  stats->max_section_time = delta;
694 
695  if ( _Chain_Is_node_off_chain( &stats->Node ) ) {
696  SMP_lock_Stats_control *control = &_SMP_lock_Stats_control;
697  SMP_lock_Context lock_context;
698 
699  _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context );
700  _Chain_Append_unprotected( &control->Stats_chain, &stats->Node );
701  _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context );
702  }
703  }
704 }
705 
706 #endif /* RTEMS_PROFILING */
707 
710 #ifdef __cplusplus
711 }
712 #endif /* __cplusplus */
713 
714 #endif /* defined( RTEMS_SMP ) */
715 
716 #endif /* _RTEMS_SCORE_SMPLOCK_H */
RTEMS_INLINE_ROUTINE void _Chain_Append_unprotected(Chain_Control *the_chain, Chain_Node *the_node)
Append a node (unprotected).
Definition: chainimpl.h:743
This is used to manage each element (node) which is placed on a chain.
Definition: chain.h:65
RTEMS_INLINE_ROUTINE Chain_Node * _Chain_Next(Chain_Node *the_node)
Return pointer the next node from this node.
Definition: chainimpl.h:433
This is used to manage a chain.
Definition: chain.h:83
ISR Level Type.
RTEMS_INLINE_ROUTINE bool _Chain_Is_node_off_chain(const Chain_Node *node)
Is the node off chain.
Definition: chainimpl.h:248
RTEMS_INLINE_ROUTINE void _Chain_Extract_unprotected(Chain_Node *the_node)
Extract this node (unprotected).
Definition: chainimpl.h:639
uint32_t ISR_Level
The following type defines the control block used to manage the interrupt level portion of the status...
Definition: isrlevel.h:42
CPU_Counter_ticks _CPU_Counter_difference(CPU_Counter_ticks second, CPU_Counter_ticks first)
Returns the difference between the second and first CPU counter value.
Definition: cpu.h:1160
RTEMS_INLINE_ROUTINE Chain_Node * _Chain_Tail(Chain_Control *the_chain)
Return pointer to chain tail.
Definition: chainimpl.h:333
Chain Handler API.
RTEMS_INLINE_ROUTINE Chain_Node * _Chain_First(Chain_Control *the_chain)
Return pointer to chain&#39;s first node.
Definition: chainimpl.h:366
Atomic Operations API.
RTEMS_INLINE_ROUTINE bool _Chain_Is_tail(const Chain_Control *the_chain, const Chain_Node *the_node)
Is this node the chail tail.
Definition: chainimpl.h:598