]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/dpdk/lib/librte_eal/common/include/generic/rte_rwlock.h
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / dpdk / lib / librte_eal / common / include / generic / rte_rwlock.h
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
8 /**
9 * @file
10 *
11 * RTE Read-Write Locks
12 *
13 * This file defines an API for read-write locks. The lock is used to
14 * protect data that allows multiple readers in parallel, but only
15 * one writer. All readers are blocked until the writer is finished
16 * writing.
17 *
18 */
19
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23
24 #include <rte_common.h>
25 #include <rte_atomic.h>
26 #include <rte_pause.h>
27
28 /**
29 * The rte_rwlock_t type.
30 *
31 * cnt is -1 when write lock is held, and > 0 when read locks are held.
32 */
33 typedef struct {
34 volatile int32_t cnt; /**< -1 when W lock held, > 0 when R locks held. */
35 } rte_rwlock_t;
36
37 /**
38 * A static rwlock initializer.
39 */
40 #define RTE_RWLOCK_INITIALIZER { 0 }
41
42 /**
43 * Initialize the rwlock to an unlocked state.
44 *
45 * @param rwl
46 * A pointer to the rwlock structure.
47 */
48 static inline void
49 rte_rwlock_init(rte_rwlock_t *rwl)
50 {
51 rwl->cnt = 0;
52 }
53
54 /**
55 * Take a read lock. Loop until the lock is held.
56 *
57 * @param rwl
58 * A pointer to a rwlock structure.
59 */
60 static inline void
61 rte_rwlock_read_lock(rte_rwlock_t *rwl)
62 {
63 int32_t x;
64 int success = 0;
65
66 while (success == 0) {
67 x = __atomic_load_n(&rwl->cnt, __ATOMIC_RELAXED);
68 /* write lock is held */
69 if (x < 0) {
70 rte_pause();
71 continue;
72 }
73 success = __atomic_compare_exchange_n(&rwl->cnt, &x, x + 1, 1,
74 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
75 }
76 }
77
78 /**
79 * @warning
80 * @b EXPERIMENTAL: this API may change without prior notice.
81 *
82 * try to take a read lock.
83 *
84 * @param rwl
85 * A pointer to a rwlock structure.
86 * @return
87 * - zero if the lock is successfully taken
88 * - -EBUSY if lock could not be acquired for reading because a
89 * writer holds the lock
90 */
91 static inline __rte_experimental int
92 rte_rwlock_read_trylock(rte_rwlock_t *rwl)
93 {
94 int32_t x;
95 int success = 0;
96
97 while (success == 0) {
98 x = __atomic_load_n(&rwl->cnt, __ATOMIC_RELAXED);
99 /* write lock is held */
100 if (x < 0)
101 return -EBUSY;
102 success = __atomic_compare_exchange_n(&rwl->cnt, &x, x + 1, 1,
103 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
104 }
105
106 return 0;
107 }
108
109 /**
110 * Release a read lock.
111 *
112 * @param rwl
113 * A pointer to the rwlock structure.
114 */
115 static inline void
116 rte_rwlock_read_unlock(rte_rwlock_t *rwl)
117 {
118 __atomic_fetch_sub(&rwl->cnt, 1, __ATOMIC_RELEASE);
119 }
120
121 /**
122 * @warning
123 * @b EXPERIMENTAL: this API may change without prior notice.
124 *
125 * try to take a write lock.
126 *
127 * @param rwl
128 * A pointer to a rwlock structure.
129 * @return
130 * - zero if the lock is successfully taken
131 * - -EBUSY if lock could not be acquired for writing because
132 * it was already locked for reading or writing
133 */
134 static inline __rte_experimental int
135 rte_rwlock_write_trylock(rte_rwlock_t *rwl)
136 {
137 int32_t x;
138
139 x = __atomic_load_n(&rwl->cnt, __ATOMIC_RELAXED);
140 if (x != 0 || __atomic_compare_exchange_n(&rwl->cnt, &x, -1, 1,
141 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED) == 0)
142 return -EBUSY;
143
144 return 0;
145 }
146
147 /**
148 * Take a write lock. Loop until the lock is held.
149 *
150 * @param rwl
151 * A pointer to a rwlock structure.
152 */
153 static inline void
154 rte_rwlock_write_lock(rte_rwlock_t *rwl)
155 {
156 int32_t x;
157 int success = 0;
158
159 while (success == 0) {
160 x = __atomic_load_n(&rwl->cnt, __ATOMIC_RELAXED);
161 /* a lock is held */
162 if (x != 0) {
163 rte_pause();
164 continue;
165 }
166 success = __atomic_compare_exchange_n(&rwl->cnt, &x, -1, 1,
167 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
168 }
169 }
170
171 /**
172 * Release a write lock.
173 *
174 * @param rwl
175 * A pointer to a rwlock structure.
176 */
177 static inline void
178 rte_rwlock_write_unlock(rte_rwlock_t *rwl)
179 {
180 __atomic_store_n(&rwl->cnt, 0, __ATOMIC_RELEASE);
181 }
182
183 /**
184 * Try to execute critical section in a hardware memory transaction, if it
185 * fails or not available take a read lock
186 *
187 * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
188 * transaction always aborts the transaction since the CPU is not able to
189 * roll-back should the transaction fail. Therefore, hardware transactional
190 * locks are not advised to be used around rte_eth_rx_burst() and
191 * rte_eth_tx_burst() calls.
192 *
193 * @param rwl
194 * A pointer to a rwlock structure.
195 */
196 static inline void
197 rte_rwlock_read_lock_tm(rte_rwlock_t *rwl);
198
199 /**
200 * Commit hardware memory transaction or release the read lock if the lock is used as a fall-back
201 *
202 * @param rwl
203 * A pointer to the rwlock structure.
204 */
205 static inline void
206 rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl);
207
208 /**
209 * Try to execute critical section in a hardware memory transaction, if it
210 * fails or not available take a write lock
211 *
212 * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
213 * transaction always aborts the transaction since the CPU is not able to
214 * roll-back should the transaction fail. Therefore, hardware transactional
215 * locks are not advised to be used around rte_eth_rx_burst() and
216 * rte_eth_tx_burst() calls.
217 *
218 * @param rwl
219 * A pointer to a rwlock structure.
220 */
221 static inline void
222 rte_rwlock_write_lock_tm(rte_rwlock_t *rwl);
223
224 /**
225 * Commit hardware memory transaction or release the write lock if the lock is used as a fall-back
226 *
227 * @param rwl
228 * A pointer to a rwlock structure.
229 */
230 static inline void
231 rte_rwlock_write_unlock_tm(rte_rwlock_t *rwl);
232
233 #ifdef __cplusplus
234 }
235 #endif
236
237 #endif /* _RTE_RWLOCK_H_ */