20 #ifndef _RTEMS_SCORE_SMPLOCK_H 21 #define _RTEMS_SCORE_SMPLOCK_H 23 #include <rtems/score/cpuopts.h> 25 #if defined( RTEMS_SMP ) 30 #if defined( RTEMS_PROFILING ) 35 #if defined( RTEMS_PROFILING ) 36 #define RTEMS_SMP_LOCK_DO_NOT_INLINE 61 #if defined( RTEMS_PROFILING ) 66 #define SMP_LOCK_STATS_CONTENTION_COUNTS 4 95 CPU_Counter_ticks max_acquire_time;
100 CPU_Counter_ticks max_section_time;
107 uint64_t usage_count;
118 uint64_t total_acquire_time;
130 uint64_t contention_counts[SMP_LOCK_STATS_CONTENTION_COUNTS];
140 uint64_t total_section_time;
157 CPU_Counter_ticks acquire_instant;
162 SMP_lock_Stats *stats;
163 } SMP_lock_Stats_context;
168 #define SMP_LOCK_STATS_INITIALIZER( name ) \ 169 { { NULL, NULL }, 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, name } 178 static inline void _SMP_lock_Stats_initialize(
179 SMP_lock_Stats *stats,
183 SMP_lock_Stats init = SMP_LOCK_STATS_INITIALIZER( name );
193 static inline void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats );
200 static inline void _SMP_lock_Stats_release_update(
201 const SMP_lock_Stats_context *stats_context
206 #define _SMP_lock_Stats_initialize( stats, name ) do { } while ( 0 ) 208 #define _SMP_lock_Stats_destroy( stats ) do { } while ( 0 ) 216 Atomic_Uint next_ticket;
217 Atomic_Uint now_serving;
218 } SMP_ticket_lock_Control;
223 #define SMP_TICKET_LOCK_INITIALIZER \ 225 ATOMIC_INITIALIZER_UINT( 0U ), \ 226 ATOMIC_INITIALIZER_UINT( 0U ) \ 238 static inline void _SMP_ticket_lock_Initialize(
239 SMP_ticket_lock_Control *lock
242 _Atomic_Init_uint( &lock->next_ticket, 0U );
243 _Atomic_Init_uint( &lock->now_serving, 0U );
253 static inline void _SMP_ticket_lock_Destroy( SMP_ticket_lock_Control *lock )
258 static inline void _SMP_ticket_lock_Do_acquire(
259 SMP_ticket_lock_Control *lock
260 #
if defined( RTEMS_PROFILING )
262 SMP_lock_Stats *stats,
263 SMP_lock_Stats_context *stats_context
267 unsigned int my_ticket;
268 unsigned int now_serving;
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;
276 first = _CPU_Counter_read();
280 _Atomic_Fetch_add_uint( &lock->next_ticket, 1U, ATOMIC_ORDER_ACQ_REL );
282 #if defined( RTEMS_PROFILING ) 284 _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_ACQUIRE );
285 initial_queue_length = my_ticket - now_serving;
287 if ( initial_queue_length > 0 ) {
292 _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_ACQUIRE );
293 }
while ( now_serving != my_ticket );
295 #if defined( RTEMS_PROFILING ) 298 second = _CPU_Counter_read();
299 stats_context->acquire_instant = second;
302 ++stats->usage_count;
304 stats->total_acquire_time += delta;
306 if ( stats->max_acquire_time < delta ) {
307 stats->max_acquire_time = delta;
310 if ( initial_queue_length >= SMP_LOCK_STATS_CONTENTION_COUNTS ) {
311 initial_queue_length = SMP_LOCK_STATS_CONTENTION_COUNTS - 1;
313 ++stats->contention_counts[initial_queue_length];
315 stats_context->stats = stats;
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 ) 334 #define _SMP_ticket_lock_Acquire( lock, stats, stats_context ) \ 335 _SMP_ticket_lock_Do_acquire( lock ) 338 static inline void _SMP_ticket_lock_Do_release(
339 SMP_ticket_lock_Control *lock
340 #
if defined( RTEMS_PROFILING )
342 const SMP_lock_Stats_context *stats_context
346 unsigned int current_ticket =
347 _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_RELAXED );
348 unsigned int next_ticket = current_ticket + 1U;
350 #if defined( RTEMS_PROFILING ) 351 _SMP_lock_Stats_release_update( stats_context );
354 _Atomic_Store_uint( &lock->now_serving, next_ticket, ATOMIC_ORDER_RELEASE );
363 #if defined( RTEMS_PROFILING ) 364 #define _SMP_ticket_lock_Release( lock, stats_context ) \ 365 _SMP_ticket_lock_Do_release( lock, stats_context ) 367 #define _SMP_ticket_lock_Release( lock, stats_context ) \ 368 _SMP_ticket_lock_Do_release( lock ) 375 SMP_ticket_lock_Control Ticket_lock;
376 #if defined( RTEMS_PROFILING ) 377 SMP_lock_Stats Stats;
386 #if defined( RTEMS_PROFILING ) 387 SMP_lock_Stats_context Stats_context;
394 #if defined( RTEMS_PROFILING ) 395 #define SMP_LOCK_INITIALIZER( name ) \ 396 { SMP_TICKET_LOCK_INITIALIZER, SMP_LOCK_STATS_INITIALIZER( name ) } 398 #define SMP_LOCK_INITIALIZER( name ) { SMP_TICKET_LOCK_INITIALIZER } 410 #if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE ) 411 void _SMP_lock_Initialize(
412 SMP_lock_Control *lock,
416 static inline void _SMP_lock_Initialize_body(
418 static inline void _SMP_lock_Initialize(
420 SMP_lock_Control *lock,
424 _SMP_ticket_lock_Initialize( &lock->Ticket_lock );
425 #if defined( RTEMS_PROFILING ) 426 _SMP_lock_Stats_initialize( &lock->Stats, name );
439 #if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE ) 440 void _SMP_lock_Destroy( SMP_lock_Control *lock );
442 static inline void _SMP_lock_Destroy_body( SMP_lock_Control *lock )
444 static inline void _SMP_lock_Destroy( SMP_lock_Control *lock )
447 _SMP_ticket_lock_Destroy( &lock->Ticket_lock );
448 _SMP_lock_Stats_destroy( &lock->Stats );
462 #if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE ) 463 void _SMP_lock_Acquire(
464 SMP_lock_Control *lock,
465 SMP_lock_Context *context
468 static inline void _SMP_lock_Acquire_body(
470 static inline void _SMP_lock_Acquire(
472 SMP_lock_Control *lock,
473 SMP_lock_Context *context
477 _SMP_ticket_lock_Acquire(
480 &context->Stats_context
491 #if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE ) 492 void _SMP_lock_Release(
493 SMP_lock_Control *lock,
494 SMP_lock_Context *context
497 static inline void _SMP_lock_Release_body(
499 static inline void _SMP_lock_Release(
501 SMP_lock_Control *lock,
502 SMP_lock_Context *context
506 _SMP_ticket_lock_Release(
508 &context->Stats_context
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
525 static inline void _SMP_lock_ISR_disable_and_acquire_body(
527 static inline void _SMP_lock_ISR_disable_and_acquire(
529 SMP_lock_Control *lock,
530 SMP_lock_Context *context
533 _ISR_Disable_without_giant( context->isr_level );
534 _SMP_lock_Acquire( lock, context );
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
550 static inline void _SMP_lock_Release_and_ISR_enable_body(
552 static inline void _SMP_lock_Release_and_ISR_enable(
554 SMP_lock_Control *lock,
555 SMP_lock_Context *context
558 _SMP_lock_Release( lock, context );
559 _ISR_Enable_without_giant( context->isr_level );
562 #if defined( RTEMS_PROFILING ) 565 SMP_lock_Control Lock;
568 } SMP_lock_Stats_control;
572 SMP_lock_Stats *current;
573 } SMP_lock_Stats_iteration_context;
575 extern SMP_lock_Stats_control _SMP_lock_Stats_control;
577 static inline void _SMP_lock_Stats_iteration_start(
578 SMP_lock_Stats_iteration_context *iteration_context
581 SMP_lock_Stats_control *control = &_SMP_lock_Stats_control;
582 SMP_lock_Context lock_context;
584 _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context );
587 &control->Iterator_chain,
588 &iteration_context->Node
590 iteration_context->current =
591 (SMP_lock_Stats *)
_Chain_First( &control->Stats_chain );
593 _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context );
596 static inline bool _SMP_lock_Stats_iteration_next(
597 SMP_lock_Stats_iteration_context *iteration_context,
598 SMP_lock_Stats *snapshot,
603 SMP_lock_Stats_control *control = &_SMP_lock_Stats_control;
604 SMP_lock_Context lock_context;
605 SMP_lock_Stats *current;
608 _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context );
610 current = iteration_context->current;
612 size_t name_len = current->name != NULL ? strlen(current->name) : 0;
616 iteration_context->current = (SMP_lock_Stats *)
619 *snapshot = *current;
620 snapshot->name = name;
622 if ( name_len >= name_size ) {
623 name_len = name_size - 1;
626 name[name_len] =
'\0';
627 memcpy(name, current->name, name_len);
632 _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context );
637 static inline void _SMP_lock_Stats_iteration_stop(
638 SMP_lock_Stats_iteration_context *iteration_context
641 SMP_lock_Stats_control *control = &_SMP_lock_Stats_control;
642 SMP_lock_Context lock_context;
644 _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context );
646 _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context );
649 static inline void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats )
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;
658 _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context );
660 next_stats = (SMP_lock_Stats *)
_Chain_Next( &stats->Node );
663 iteration_context = (SMP_lock_Stats_iteration_context *)
665 iteration_context_tail = (SMP_lock_Stats_iteration_context *)
668 while ( iteration_context != iteration_context_tail ) {
669 if ( iteration_context->current == stats ) {
670 iteration_context->current = next_stats;
673 iteration_context = (SMP_lock_Stats_iteration_context *)
677 _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context );
681 static inline void _SMP_lock_Stats_release_update(
682 const SMP_lock_Stats_context *stats_context
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();
690 stats->total_section_time += delta;
692 if ( stats->max_section_time < delta ) {
693 stats->max_section_time = delta;
696 SMP_lock_Stats_control *control = &_SMP_lock_Stats_control;
697 SMP_lock_Context lock_context;
699 _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context );
701 _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context );
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
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
RTEMS_INLINE_ROUTINE Chain_Node * _Chain_First(Chain_Control *the_chain)
Return pointer to chain's first node.
Definition: chainimpl.h:366
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