source: rtems/cpukit/score/include/rtems/score/smplockseq.h @ 64ed0bb3

5
Last change on this file since 64ed0bb3 was 64ed0bb3, checked in by Sebastian Huber <sebastian.huber@…>, on Jul 14, 2016 at 12:55:49 PM

score: Assert proper seqlock writer state

Helps to detect invalid concurrent writes.

  • Property mode set to 100644
File size: 4.2 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreSMPLock
5 *
6 * @brief SMP Lock API
7 */
8
9/*
10 * Copyright (c) 2016 embedded brains GmbH
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_SCORE_SMPLOCKSEQ_H
18#define _RTEMS_SCORE_SMPLOCKSEQ_H
19
20#include <rtems/score/cpuopts.h>
21
22#if defined(RTEMS_SMP)
23
24#include <rtems/score/assert.h>
25#include <rtems/score/atomic.h>
26
27#ifdef __cplusplus
28extern "C" {
29#endif /* __cplusplus */
30
31/**
32 * @addtogroup ScoreSMPLock
33 *
34 * @{
35 */
36
37/**
38 * @brief SMP sequence lock control.
39 *
40 * The sequence lock offers a consistent data set for readers in the presence
41 * of at most one concurrent writer.  Due to the read-modify-write operation in
42 * _SMP_sequence_lock_Read_retry() the data corresponding to the last written
43 * sequence number is observed.  To allow multiple writers an additional SMP
44 * lock is necessary to serialize writes.
45 *
46 * See also Hans-J. Boehm, HP Laboratories,
47 * "Can Seqlocks Get Along With Programming Language Memory Models?",
48 * http://www.hpl.hp.com/techreports/2012/HPL-2012-68.pdf
49 */
50typedef struct {
51  /**
52   * @brief The sequence number.
53   *
54   * An odd value indicates that a write is in progress.
55   */
56  Atomic_Uint sequence;
57} SMP_sequence_lock_Control;
58
59/**
60 * @brief SMP sequence lock control initializer for static initialization.
61 */
62#define SMP_SEQUENCE_LOCK_INITIALIZER { ATOMIC_INITIALIZER_UINT( 0 ) }
63
64/**
65 * @brief Initializes an SMP sequence lock.
66 *
67 * Concurrent initialization leads to unpredictable results.
68 *
69 * @param lock The SMP sequence lock control.
70 */
71static inline void _SMP_sequence_lock_Initialize( SMP_sequence_lock_Control *lock )
72{
73  _Atomic_Init_uint( &lock->sequence, 0 );
74}
75
76/**
77 * @brief Destroys an SMP sequence lock.
78 *
79 * Concurrent destruction leads to unpredictable results.
80 *
81 * @param lock The SMP sequence lock control.
82 */
83static inline void _SMP_sequence_lock_Destroy( SMP_sequence_lock_Control *lock )
84{
85  (void) lock;
86}
87
88/**
89 * @brief Begins an SMP sequence lock write operation.
90 *
91 * This function will not disable interrupts.  The caller must ensure that the
92 * current thread of execution is not interrupted indefinite since this would
93 * starve readers.
94 *
95 * @param lock The SMP sequence lock control.
96 *
97 * @return The current sequence number.
98 */
99static inline unsigned int _SMP_sequence_lock_Write_begin(
100  SMP_sequence_lock_Control *lock
101)
102{
103  unsigned int seq;
104
105  seq = _Atomic_Load_uint( &lock->sequence, ATOMIC_ORDER_RELAXED );
106  _Assert( seq % 2 == 0 );
107
108  _Atomic_Store_uint( &lock->sequence, seq + 1, ATOMIC_ORDER_RELAXED );
109
110  /* There is no atomic store with acquire/release semantics */
111  _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
112
113  return seq;
114}
115
116/**
117 * @brief Ends an SMP sequence lock write operation.
118 *
119 * @param lock The SMP sequence lock control.
120 * @param seq The sequence number returned by _SMP_sequence_lock_Write_begin().
121 */
122static inline void _SMP_sequence_lock_Write_end(
123  SMP_sequence_lock_Control *lock,
124  unsigned int               seq
125)
126{
127  _Atomic_Store_uint( &lock->sequence, seq + 2, ATOMIC_ORDER_RELEASE );
128}
129
130/**
131 * @brief Begins an SMP sequence lock read operation.
132 *
133 * This function will not disable interrupts.
134 *
135 * @param lock The SMP sequence lock control.
136 *
137 * @return The current sequence number.
138 */
139static inline unsigned int _SMP_sequence_lock_Read_begin(
140  const SMP_sequence_lock_Control *lock
141)
142{
143  return _Atomic_Load_uint( &lock->sequence, ATOMIC_ORDER_ACQUIRE );
144}
145
146/**
147 * @brief Ends an SMP sequence lock read operation and indicates if a retry is
148 * necessary.
149 *
150 * @param lock The SMP sequence lock control.
151 * @param seq The sequence number returned by _SMP_sequence_lock_Read_begin().
152 *
153 * @retval true The read operation must be retried with a call to
154 *   _SMP_sequence_lock_Read_begin().
155 * @retval false Otherwise.
156 */
157static inline bool _SMP_sequence_lock_Read_retry(
158  SMP_sequence_lock_Control *lock,
159  unsigned int               seq
160)
161{
162  unsigned int seq2;
163
164  seq2 = _Atomic_Fetch_add_uint( &lock->sequence, 0, ATOMIC_ORDER_RELEASE );
165  return seq != seq2 || seq % 2 != 0;
166}
167
168/**@}*/
169
170#ifdef __cplusplus
171}
172#endif /* __cplusplus */
173
174#endif /* RTEMS_SMP */
175
176#endif /* _RTEMS_SCORE_SMPLOCKSEQ_H */
Note: See TracBrowser for help on using the repository browser.