From 05b7eec276a130cde39fed861ad4a9d1f01e876c Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 8 Jun 2016 15:18:14 +0200 Subject: score: Add an SMP sequence lock implementation --- cpukit/score/Makefile.am | 1 + cpukit/score/include/rtems/score/smplockseq.h | 173 ++++++++++++++++++++++++++ cpukit/score/preinstall.am | 4 + 3 files changed, 178 insertions(+) create mode 100644 cpukit/score/include/rtems/score/smplockseq.h (limited to 'cpukit/score') diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 29e822d47d..537cf60c1a 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -82,6 +82,7 @@ include_rtems_score_HEADERS += include/rtems/score/schedulersmpimpl.h include_rtems_score_HEADERS += include/rtems/score/smp.h include_rtems_score_HEADERS += include/rtems/score/smpbarrier.h include_rtems_score_HEADERS += include/rtems/score/smplock.h +include_rtems_score_HEADERS += include/rtems/score/smplockseq.h include_rtems_score_HEADERS += include/rtems/score/smpimpl.h include_rtems_score_HEADERS += include/rtems/score/stack.h include_rtems_score_HEADERS += include/rtems/score/stackimpl.h diff --git a/cpukit/score/include/rtems/score/smplockseq.h b/cpukit/score/include/rtems/score/smplockseq.h new file mode 100644 index 0000000000..6fe7b7afa3 --- /dev/null +++ b/cpukit/score/include/rtems/score/smplockseq.h @@ -0,0 +1,173 @@ +/** + * @file + * + * @ingroup ScoreSMPLock + * + * @brief SMP Lock API + */ + +/* + * Copyright (c) 2016 embedded brains GmbH + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _RTEMS_SCORE_SMPLOCKSEQ_H +#define _RTEMS_SCORE_SMPLOCKSEQ_H + +#include + +#if defined(RTEMS_SMP) + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @addtogroup ScoreSMPLock + * + * @{ + */ + +/** + * @brief SMP sequence lock control. + * + * The sequence lock offers a consistent data set for readers in the presence + * of at most one concurrent writer. Due to the read-modify-write operation in + * _SMP_sequence_lock_Read_retry() the data corresponding to the last written + * sequence number is observed. To allow multiple writers an additional SMP + * lock is necessary to serialize writes. + * + * See also Hans-J. Boehm, HP Laboratories, + * "Can Seqlocks Get Along With Programming Language Memory Models?", + * http://www.hpl.hp.com/techreports/2012/HPL-2012-68.pdf + */ +typedef struct { + /** + * @brief The sequence number. + * + * An odd value indicates that a write is in progress. + */ + Atomic_Uint sequence; +} SMP_sequence_lock_Control; + +/** + * @brief SMP sequence lock control initializer for static initialization. + */ +#define SMP_SEQUENCE_LOCK_INITIALIZER { ATOMIC_INITIALIZER_UINT( 0 ) } + +/** + * @brief Initializes an SMP sequence lock. + * + * Concurrent initialization leads to unpredictable results. + * + * @param lock The SMP sequence lock control. + */ +static inline void _SMP_sequence_lock_Initialize( SMP_sequence_lock_Control *lock ) +{ + _Atomic_Init_uint( &lock->sequence, 0 ); +} + +/** + * @brief Destroys an SMP sequence lock. + * + * Concurrent destruction leads to unpredictable results. + * + * @param lock The SMP sequence lock control. + */ +static inline void _SMP_sequence_lock_Destroy( SMP_sequence_lock_Control *lock ) +{ + (void) lock; +} + +/** + * @brief Begins an SMP sequence lock write operation. + * + * This function will not disable interrupts. The caller must ensure that the + * current thread of execution is not interrupted indefinite since this would + * starve readers. + * + * @param lock The SMP sequence lock control. + * + * @return The current sequence number. + */ +static inline unsigned int _SMP_sequence_lock_Write_begin( + SMP_sequence_lock_Control *lock +) +{ + unsigned int seq; + + seq = _Atomic_Load_uint( &lock->sequence, ATOMIC_ORDER_RELAXED ); + _Atomic_Store_uint( &lock->sequence, seq + 1, ATOMIC_ORDER_RELAXED ); + + /* There is no atomic store with acquire/release semantics */ + _Atomic_Fence( ATOMIC_ORDER_ACQ_REL ); + + return seq; +} + +/** + * @brief Ends an SMP sequence lock write operation. + * + * @param lock The SMP sequence lock control. + * @param seq The sequence number returned by _SMP_sequence_lock_Write_begin(). + */ +static inline void _SMP_sequence_lock_Write_end( + SMP_sequence_lock_Control *lock, + unsigned int seq +) +{ + _Atomic_Store_uint( &lock->sequence, seq + 2, ATOMIC_ORDER_RELEASE ); +} + +/** + * @brief Begins an SMP sequence lock read operation. + * + * This function will not disable interrupts. + * + * @param lock The SMP sequence lock control. + * + * @return The current sequence number. + */ +static inline unsigned int _SMP_sequence_lock_Read_begin( + const SMP_sequence_lock_Control *lock +) +{ + return _Atomic_Load_uint( &lock->sequence, ATOMIC_ORDER_ACQUIRE ); +} + +/** + * @brief Ends an SMP sequence lock read operation and indicates if a retry is + * necessary. + * + * @param lock The SMP sequence lock control. + * @param seq The sequence number returned by _SMP_sequence_lock_Read_begin(). + * + * @retval true The read operation must be retried with a call to + * _SMP_sequence_lock_Read_begin(). + * @retval false Otherwise. + */ +static inline bool _SMP_sequence_lock_Read_retry( + SMP_sequence_lock_Control *lock, + unsigned int seq +) +{ + unsigned int seq2; + + seq2 = _Atomic_Fetch_add_uint( &lock->sequence, 0, ATOMIC_ORDER_RELEASE ); + return seq != seq2 || seq % 2 != 0; +} + +/**@}*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* RTEMS_SMP */ + +#endif /* _RTEMS_SCORE_SMPLOCKSEQ_H */ diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index 2ed07b91e8..1ba332d098 100644 --- a/cpukit/score/preinstall.am +++ b/cpukit/score/preinstall.am @@ -296,6 +296,10 @@ $(PROJECT_INCLUDE)/rtems/score/smplock.h: include/rtems/score/smplock.h $(PROJEC $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/smplock.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/smplock.h +$(PROJECT_INCLUDE)/rtems/score/smplockseq.h: include/rtems/score/smplockseq.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/smplockseq.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/smplockseq.h + $(PROJECT_INCLUDE)/rtems/score/smpimpl.h: include/rtems/score/smpimpl.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/smpimpl.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/smpimpl.h -- cgit v1.2.3