New upstream version 18.08
[deb_dpdk.git] / 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 = rwl->cnt;
68                 /* write lock is held */
69                 if (x < 0) {
70                         rte_pause();
71                         continue;
72                 }
73                 success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt,
74                                               (uint32_t)x, (uint32_t)(x + 1));
75         }
76 }
77
78 /**
79  * Release a read lock.
80  *
81  * @param rwl
82  *   A pointer to the rwlock structure.
83  */
84 static inline void
85 rte_rwlock_read_unlock(rte_rwlock_t *rwl)
86 {
87         rte_atomic32_dec((rte_atomic32_t *)(intptr_t)&rwl->cnt);
88 }
89
90 /**
91  * Take a write lock. Loop until the lock is held.
92  *
93  * @param rwl
94  *   A pointer to a rwlock structure.
95  */
96 static inline void
97 rte_rwlock_write_lock(rte_rwlock_t *rwl)
98 {
99         int32_t x;
100         int success = 0;
101
102         while (success == 0) {
103                 x = rwl->cnt;
104                 /* a lock is held */
105                 if (x != 0) {
106                         rte_pause();
107                         continue;
108                 }
109                 success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt,
110                                               0, (uint32_t)-1);
111         }
112 }
113
114 /**
115  * Release a write lock.
116  *
117  * @param rwl
118  *   A pointer to a rwlock structure.
119  */
120 static inline void
121 rte_rwlock_write_unlock(rte_rwlock_t *rwl)
122 {
123         rte_atomic32_inc((rte_atomic32_t *)(intptr_t)&rwl->cnt);
124 }
125
126 /**
127  * Try to execute critical section in a hardware memory transaction, if it
128  * fails or not available take a read lock
129  *
130  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
131  * transaction always aborts the transaction since the CPU is not able to
132  * roll-back should the transaction fail. Therefore, hardware transactional
133  * locks are not advised to be used around rte_eth_rx_burst() and
134  * rte_eth_tx_burst() calls.
135  *
136  * @param rwl
137  *   A pointer to a rwlock structure.
138  */
139 static inline void
140 rte_rwlock_read_lock_tm(rte_rwlock_t *rwl);
141
142 /**
143  * Commit hardware memory transaction or release the read lock if the lock is used as a fall-back
144  *
145  * @param rwl
146  *   A pointer to the rwlock structure.
147  */
148 static inline void
149 rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl);
150
151 /**
152  * Try to execute critical section in a hardware memory transaction, if it
153  * fails or not available take a write lock
154  *
155  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
156  * transaction always aborts the transaction since the CPU is not able to
157  * roll-back should the transaction fail. Therefore, hardware transactional
158  * locks are not advised to be used around rte_eth_rx_burst() and
159  * rte_eth_tx_burst() calls.
160  *
161  * @param rwl
162  *   A pointer to a rwlock structure.
163  */
164 static inline void
165 rte_rwlock_write_lock_tm(rte_rwlock_t *rwl);
166
167 /**
168  * Commit hardware memory transaction or release the write lock if the lock is used as a fall-back
169  *
170  * @param rwl
171  *   A pointer to a rwlock structure.
172  */
173 static inline void
174 rte_rwlock_write_unlock_tm(rte_rwlock_t *rwl);
175
176 #ifdef __cplusplus
177 }
178 #endif
179
180 #endif /* _RTE_RWLOCK_H_ */