first public release
[dpdk.git] / lib / librte_eal / common / include / rte_rwlock.h
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  * 
7  *   Redistribution and use in source and binary forms, with or without 
8  *   modification, are permitted provided that the following conditions 
9  *   are met:
10  * 
11  *     * Redistributions of source code must retain the above copyright 
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright 
14  *       notice, this list of conditions and the following disclaimer in 
15  *       the documentation and/or other materials provided with the 
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its 
18  *       contributors may be used to endorse or promote products derived 
19  *       from this software without specific prior written permission.
20  * 
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  * 
33  *  version: DPDK.L.1.2.3-3
34  */
35
36 #ifndef _RTE_RWLOCK_H_
37 #define _RTE_RWLOCK_H_
38
39 /**
40  * @file
41  *
42  * RTE Read-Write Locks
43  *
44  * This file defines an API for read-write locks. The lock is used to
45  * protect data that allows multiple readers in parallel, but only
46  * one writer. All readers are blocked until the writer is finished
47  * writing.
48  *
49  */
50
51 #ifdef __cplusplus
52 extern "C" {
53 #endif
54
55 #include <rte_common.h>
56 #include <rte_atomic.h>
57
58 /**
59  * The rte_rwlock_t type.
60  *
61  * cnt is -1 when write lock is held, and > 0 when read locks are held.
62  */
63 typedef struct {
64         volatile int32_t cnt; /**< -1 when W lock held, > 0 when R locks held. */
65 } rte_rwlock_t;
66
67 /**
68  * A static rwlock initializer.
69  */
70 #define RTE_RWLOCK_INITIALIZER { 0 }
71
72 /**
73  * Initialize the rwlock to an unlocked state.
74  *
75  * @param rwl
76  *   A pointer to the rwlock structure.
77  */
78 static inline void
79 rte_rwlock_init(rte_rwlock_t *rwl)
80 {
81         rwl->cnt = 0;
82 }
83
84 /**
85  * Take a read lock. Loop until the lock is held.
86  *
87  * @param rwl
88  *   A pointer to a rwlock structure.
89  */
90 static inline void
91 rte_rwlock_read_lock(rte_rwlock_t *rwl)
92 {
93         int32_t x;
94         int success = 0;
95
96         while (success == 0) {
97                 x = rwl->cnt;
98                 /* write lock is held */
99                 if (x < 0) {
100                         rte_pause();
101                         continue;
102                 }
103                 success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt,
104                                               x, x + 1);
105         }
106 }
107
108 /**
109  * Release a read lock.
110  *
111  * @param rwl
112  *   A pointer to the rwlock structure.
113  */
114 static inline void
115 rte_rwlock_read_unlock(rte_rwlock_t *rwl)
116 {
117         /* in debug mode, we should check that rwl->cnt is > 0 */
118
119         /* same than atomic32_dec */
120         asm volatile(MPLOCKED
121                      "decl %[cnt]"
122                      : [cnt] "=m" (rwl->cnt) /* output (0) */
123                      : "m" (rwl->cnt)        /* input (1) */
124                      );                      /* no clobber-list */
125 }
126
127 /**
128  * Take a write lock. Loop until the lock is held.
129  *
130  * @param rwl
131  *   A pointer to a rwlock structure.
132  */
133 static inline void
134 rte_rwlock_write_lock(rte_rwlock_t *rwl)
135 {
136         int32_t x;
137         int success = 0;
138
139         while (success == 0) {
140                 x = rwl->cnt;
141                 /* a lock is held */
142                 if (x != 0) {
143                         rte_pause();
144                         continue;
145                 }
146                 success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt,
147                                               0, -1);
148         }
149 }
150
151 /**
152  * Release a write lock.
153  *
154  * @param rwl
155  *   A pointer to a rwlock structure.
156  */
157 static inline void
158 rte_rwlock_write_unlock(rte_rwlock_t *rwl)
159 {
160         /* in debug mode, we should check that rwl->cnt is < 0 */
161
162         /* same than atomic32_inc */
163         asm volatile(MPLOCKED
164                      "incl %[cnt]"
165                      : [cnt] "=m" (rwl->cnt) /* output (0) */
166                      : "m" (rwl->cnt)        /* input (1) */
167                      );                      /* no clobber-list */
168 }
169
170 #ifdef __cplusplus
171 }
172 #endif
173
174 #endif /* _RTE_RWLOCK_H_ */