DPDK  22.11.5
rte_rwlock.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #ifndef _RTE_RWLOCK_H_
6 #define _RTE_RWLOCK_H_
7 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 #include <errno.h>
30 
31 #include <rte_branch_prediction.h>
32 #include <rte_common.h>
33 #include <rte_pause.h>
34 
52 #define RTE_RWLOCK_WAIT 0x1 /* Writer is waiting */
53 #define RTE_RWLOCK_WRITE 0x2 /* Writer has the lock */
54 #define RTE_RWLOCK_MASK (RTE_RWLOCK_WAIT | RTE_RWLOCK_WRITE)
55  /* Writer is waiting or has lock */
56 #define RTE_RWLOCK_READ 0x4 /* Reader increment */
57 
58 typedef struct {
59  int32_t cnt;
60 } rte_rwlock_t;
61 
65 #define RTE_RWLOCK_INITIALIZER { 0 }
66 
73 static inline void
74 rte_rwlock_init(rte_rwlock_t *rwl)
75 {
76  rwl->cnt = 0;
77 }
78 
89 static inline void
90 rte_rwlock_read_lock(rte_rwlock_t *rwl)
91 {
92  int32_t x;
93 
94  while (1) {
95  /* Wait while writer is present or pending */
96  while (__atomic_load_n(&rwl->cnt, __ATOMIC_RELAXED)
97  & RTE_RWLOCK_MASK)
98  rte_pause();
99 
100  /* Try to get read lock */
101  x = __atomic_add_fetch(&rwl->cnt, RTE_RWLOCK_READ,
102  __ATOMIC_ACQUIRE);
103 
104  /* If no writer, then acquire was successful */
105  if (likely(!(x & RTE_RWLOCK_MASK)))
106  return;
107 
108  /* Lost race with writer, backout the change. */
109  __atomic_fetch_sub(&rwl->cnt, RTE_RWLOCK_READ,
110  __ATOMIC_RELAXED);
111  }
112 }
113 
124 static inline int
125 rte_rwlock_read_trylock(rte_rwlock_t *rwl)
126 {
127  int32_t x;
128 
129  x = __atomic_load_n(&rwl->cnt, __ATOMIC_RELAXED);
130 
131  /* fail if write lock is held or writer is pending */
132  if (x & RTE_RWLOCK_MASK)
133  return -EBUSY;
134 
135  /* Try to get read lock */
136  x = __atomic_add_fetch(&rwl->cnt, RTE_RWLOCK_READ,
137  __ATOMIC_ACQUIRE);
138 
139  /* Back out if writer raced in */
140  if (unlikely(x & RTE_RWLOCK_MASK)) {
141  __atomic_fetch_sub(&rwl->cnt, RTE_RWLOCK_READ,
142  __ATOMIC_RELEASE);
143 
144  return -EBUSY;
145  }
146  return 0;
147 }
148 
155 static inline void
156 rte_rwlock_read_unlock(rte_rwlock_t *rwl)
157 {
158  __atomic_fetch_sub(&rwl->cnt, RTE_RWLOCK_READ, __ATOMIC_RELEASE);
159 }
160 
171 static inline int
172 rte_rwlock_write_trylock(rte_rwlock_t *rwl)
173 {
174  int32_t x;
175 
176  x = __atomic_load_n(&rwl->cnt, __ATOMIC_RELAXED);
177  if (x < RTE_RWLOCK_WRITE &&
178  __atomic_compare_exchange_n(&rwl->cnt, &x, x + RTE_RWLOCK_WRITE,
179  1, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
180  return 0;
181  else
182  return -EBUSY;
183 }
184 
191 static inline void
192 rte_rwlock_write_lock(rte_rwlock_t *rwl)
193 {
194  int32_t x;
195 
196  while (1) {
197  x = __atomic_load_n(&rwl->cnt, __ATOMIC_RELAXED);
198 
199  /* No readers or writers? */
200  if (likely(x < RTE_RWLOCK_WRITE)) {
201  /* Turn off RTE_RWLOCK_WAIT, turn on RTE_RWLOCK_WRITE */
202  if (__atomic_compare_exchange_n(&rwl->cnt, &x, RTE_RWLOCK_WRITE, 1,
203  __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
204  return;
205  }
206 
207  /* Turn on writer wait bit */
208  if (!(x & RTE_RWLOCK_WAIT))
209  __atomic_fetch_or(&rwl->cnt, RTE_RWLOCK_WAIT, __ATOMIC_RELAXED);
210 
211  /* Wait until no readers before trying again */
212  while (__atomic_load_n(&rwl->cnt, __ATOMIC_RELAXED) > RTE_RWLOCK_WAIT)
213  rte_pause();
214 
215  }
216 }
217 
224 static inline void
225 rte_rwlock_write_unlock(rte_rwlock_t *rwl)
226 {
227  __atomic_fetch_sub(&rwl->cnt, RTE_RWLOCK_WRITE, __ATOMIC_RELEASE);
228 }
229 
243 static inline void
244 rte_rwlock_read_lock_tm(rte_rwlock_t *rwl);
245 
252 static inline void
253 rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl);
254 
268 static inline void
269 rte_rwlock_write_lock_tm(rte_rwlock_t *rwl);
270 
277 static inline void
278 rte_rwlock_write_unlock_tm(rte_rwlock_t *rwl);
279 
280 #ifdef __cplusplus
281 }
282 #endif
283 
284 #endif /* _RTE_RWLOCK_H_ */
#define likely(x)
static void rte_rwlock_write_lock_tm(rte_rwlock_t *rwl)
static void rte_rwlock_read_lock(rte_rwlock_t *rwl)
Definition: rte_rwlock.h:90
static int rte_rwlock_read_trylock(rte_rwlock_t *rwl)
Definition: rte_rwlock.h:125
#define unlikely(x)
static void rte_rwlock_read_lock_tm(rte_rwlock_t *rwl)
static void rte_rwlock_read_unlock(rte_rwlock_t *rwl)
Definition: rte_rwlock.h:156
static void rte_pause(void)
#define RTE_RWLOCK_WAIT
Definition: rte_rwlock.h:52
static void rte_rwlock_write_unlock(rte_rwlock_t *rwl)
Definition: rte_rwlock.h:225
static void rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl)
static void rte_rwlock_write_lock(rte_rwlock_t *rwl)
Definition: rte_rwlock.h:192
static void rte_rwlock_init(rte_rwlock_t *rwl)
Definition: rte_rwlock.h:74
static void rte_rwlock_write_unlock_tm(rte_rwlock_t *rwl)
static int rte_rwlock_write_trylock(rte_rwlock_t *rwl)
Definition: rte_rwlock.h:172