P99
p99_rwl.h
Go to the documentation of this file.
1 /* This may look like nonsense, but it really is -*- mode: C; coding: utf-8 -*- */
2 /* */
3 /* Except for parts copied from previous work and as explicitly stated below, */
4 /* the author and copyright holder for this work is */
5 /* (C) copyright 2014 Jens Gustedt, INRIA, France */
6 /* */
7 /* This file is free software; it is part of the P99 project. */
8 /* */
9 /* Licensed under the Apache License, Version 2.0 (the "License"); */
10 /* you may not use this file except in compliance with the License. */
11 /* You may obtain a copy of the License at */
12 /* */
13 /* http://www.apache.org/licenses/LICENSE-2.0 */
14 /* */
15 /* Unless required by applicable law or agreed to in writing, software */
16 /* distributed under the License is distributed on an "AS IS" BASIS, */
17 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
18 /* See the License for the specific language governing permissions and */
19 /* limitations under the License. */
20 /* */
21 #ifndef P99_RWL_H
22 #define P99_RWL_H
23 
24 #include "p99_futex.h"
25 
65 #ifdef P00_DOXYGEN
66 struct p99_rwl {};
67 #else
68 typedef struct p99_rwl p99_rwl;
69 struct p99_rwl {
70  p99_futex p00_f;
71  _Atomic(unsigned) p00_w;
72 };
73 #endif
74 
75 #define P00_RWL_EXCL UINT_MAX
76 
77 #ifndef P00_RWL_DIAG
78 # define P00_RWL_DIAG(...) P99_NOP
79 #endif
80 
84 # define P99_RWL_INITIALIZER \
85 { \
86  .p00_f = P99_FUTEX_INITIALIZER, \
87  .p00_w = ATOMIC_VAR_INIT(0), \
88 }
89 
95  if (p00_r) {
96  p99_futex_init(&p00_r->p00_f, 0u);
97  atomic_init(&p00_r->p00_w, 0u);
98  }
99  return p00_r;
100 }
101 
103 void p99_rwl_destroy(p99_rwl* p00_r) {
104  if (p00_r) {
105  p99_futex_destroy(&p00_r->p00_f);
106  }
107 }
108 
121 P00_FUTEX_INLINE(p99_rwl_rdlock)
122 int p99_rwl_rdlock(p99_rwl volatile* p00_r) {
123  uint p00_res = 0;
124  atomic_fetch_add_explicit(&(p00_r->p00_w), 1u, memory_order_acq_rel);
125  P99_FUTEX_COMPARE_EXCHANGE(&(p00_r->p00_f), p00_act,
126  /* block if there is an exclusive lock or
127  already too many readers */
128  (P00_RWL_DIAG(stderr, "rdlock found %u\n", p00_act),
129  (p00_act < P00_RWL_EXCL-1)),
130  /* as soon as there is no exclusive lock
131  and the number of waiters is not too
132  big add us to the count */
133  (p00_res = ((p00_act < P00_RWL_EXCL-1) ? p00_act + 1U : p00_act)),
134  /* never wakeup anybody */
135  0U, 0U);
136  atomic_fetch_add_explicit(&(p00_r->p00_w), -1u, memory_order_acq_rel);
137  P00_RWL_DIAG(stderr, "rdlock set to %u\n", p00_res);
138  /* Return EAGAIN if we couldn't increment because there were too
139  many waiters. */
140  return (p00_res <= P00_RWL_EXCL-1)
141  ? 0
142  : EAGAIN;
143 }
144 
156 P00_FUTEX_INLINE(p99_rwl_wrlock)
157 int p99_rwl_wrlock(p99_rwl volatile* p00_r) {
158  uint p00_res = 0;
159  atomic_fetch_add_explicit(&(p00_r->p00_w), 1u, memory_order_acq_rel);
160  P99_FUTEX_COMPARE_EXCHANGE(&(p00_r->p00_f), p00_act,
161  /* block if there is any lock */
162  (P00_RWL_DIAG(stderr, "wrlock found %u\n", p00_act), !p00_act),
163  /* as soon as there is no lock, reserve exclusively */
164  (p00_res = P00_RWL_EXCL),
165  /* never wakeup anybody */
166  0U, 0U);
167  atomic_fetch_add_explicit(&(p00_r->p00_w), -1u, memory_order_acq_rel);
168  P00_RWL_DIAG(stderr, "wrlock set to %u\n", p00_res);
169  return 0;
170 }
171 
178 P00_FUTEX_INLINE(p99_rwl_inc_conditionally)
179 int p99_rwl_unlock(p99_rwl volatile* p00_r) {
180  uint p00_res = 0;
181  P99_FUTEX_COMPARE_EXCHANGE(&(p00_r->p00_f), p00_act,
182  /* never block */
183  (P00_RWL_DIAG(stderr, "unlock found %u\n", p00_act), true),
184  /* decrement for shared locks, force to 0 for exclusives */
185  (p00_res = ((p00_act == P00_RWL_EXCL) ? 0U : p00_act - 1U)),
186  /* wakeup potential waiters if any and
187  the count fell to 0 */
188  0U, (p00_res ? 0U : atomic_load(&p00_r->p00_w)));
189  P00_RWL_DIAG(stderr, "unlock set to %u\n", p00_res);
190  return 0;
191 }
192 
200 p99_inline bool p99_rwl_islocked(p99_rwl volatile* p00_r) {
201  return p99_futex_load(&(p00_r->p00_f));
202 }
203 
211 p99_inline bool p99_rwl_haswaiters(p99_rwl volatile* p00_r) {
212  return atomic_load(&(p00_r->p00_w));
213 }
214 
215 # ifndef P99_SIMPLE_BLOCKS
216 
221 # define P99_RDLOCK(RWLOCK) \
222 P00_BLK_START \
223 P00_BLK_DECL(int, p00_errNo, 0) \
224 P99_GUARDED_BLOCK(p99_rwl*, \
225  P99_FILEID(rwlock), \
226  &(RWLOCK), \
227  (void)(P99_UNLIKELY(p00_errNo = p99_rwl_rdlock(P99_FILEID(rwlock))) \
228  && (fprintf(stderr, \
229  __FILE__ ":" \
230  P99_STRINGIFY(__LINE__) ": read lock error for " \
231  P99_STRINGIFY(RWLOCK) ", %s", \
232  strerror(p00_errNo)), 1) \
233  && (P99_FILEID(rwlock) = 0, 1) \
234  && (P99_UNWIND(-1), 1) \
235  ), \
236  (void)(P99_FILEID(rwlock) \
237  && p99_rwl_unlock(P99_FILEID(rwlock))))
238 
239 
245 # define P99_WRLOCK(RWLOCK) \
246 P00_BLK_START \
247 P00_BLK_DECL(int, p00_errNo, 0) \
248 P99_GUARDED_BLOCK(p99_rwl*, \
249  P99_FILEID(rwlock), \
250  &(RWLOCK), \
251  (void)(P99_UNLIKELY(p00_errNo = p99_rwl_wrlock(P99_FILEID(rwlock))) \
252  && (fprintf(stderr, \
253  __FILE__ ":" \
254  P99_STRINGIFY(__LINE__) ": write lock error for " \
255  P99_STRINGIFY(RWLOCK) ", %s", \
256  strerror(p00_errNo)), 1) \
257  && (P99_FILEID(rwlock) = 0, 1) \
258  && (P99_UNWIND(-1), 1) \
259  ), \
260  (void)(P99_FILEID(rwlock) \
261  && p99_rwl_unlock(P99_FILEID(rwlock))))
262 # else
263 # define P99_RDLOCK(RWLOCK) \
264 P99_GUARDED_BLOCK(p99_rwl*, \
265  P99_FILEID(rwlock), \
266  &(RWLOCK), \
267  p99_rwl_rdlock(P99_FILEID(rwlock)), \
268  p99_rwl_unlock(P99_FILEID(rwlock)))
269 
270 
271 # define P99_WRLOCK(RWLOCK) \
272 P99_GUARDED_BLOCK(p99_rwl*, \
273  P99_FILEID(rwlock), \
274  &(RWLOCK), \
275  p99_rwl_wrlock(P99_FILEID(rwlock)), \
276  p99_rwl_unlock(P99_FILEID(rwlock)))
277 # endif
278 
279 
285 #endif
p99_futex.h
p99_rwl::p99_rwl_wrlock
int p99_rwl_wrlock(p99_rwl volatile *p00_r)
establish an exclusive lock for rwlock p00_r.
Definition: p99_rwl.h:157
p99_futex::p99_futex_destroy
void p99_futex_destroy(p99_futex *p00_c)
Destroy an p99_futex object.
p99_futex
A counter similar to a conditional variable that allows atomic increment and decrement and to wait fo...
Definition: p99_futex.h:163
p99_rwl::p99_rwl_rdlock
int p99_rwl_rdlock(p99_rwl volatile *p00_r)
establish a shared lock for rwlock p00_c.
Definition: p99_rwl.h:122
uint
unsigned int uint
a ‘one token’ abreviation for unsigned int
Definition: p99_typenames.h:40
p99_inline
#define p99_inline
Try to force a function always to be inlined.
Definition: p99_compiler.h:496
p99_futex::P99_FUTEX_COMPARE_EXCHANGE
#define P99_FUTEX_COMPARE_EXCHANGE(FUTEX, ACT, EXPECTED, DESIRED, WAKEMIN, WAKEMAX)
a catch all macro to operate on p99_futex
Definition: p99_futex.h:563
p99_rwl_destroy
void p99_rwl_destroy(p99_rwl *p00_r)
Definition: p99_rwl.h:103
p99_futex::p99_futex_load
unsigned p99_futex_load(p99_futex volatile *p00_fut)
Obtain the value of futex p00_fut atomically.
p99_rwl::p99_rwl_unlock
int p99_rwl_unlock(p99_rwl volatile *p00_r)
release a lock on rwlock p00_r.
Definition: p99_rwl.h:179
p99_rwl::p99_rwl_islocked
bool p99_rwl_islocked(p99_rwl volatile *p00_r)
Tell if is locked.
Definition: p99_rwl.h:200
p99_rwl::p99_rwl_haswaiters
bool p99_rwl_haswaiters(p99_rwl volatile *p00_r)
Tell if has waiters.
Definition: p99_rwl.h:211
p99_futex::p99_futex_init
p99_futex * p99_futex_init(p99_futex *p00_c, unsigned p00_ini)
Initialize an p99_futex object.
p99_rwl_init
p99_rwl * p99_rwl_init(p99_rwl *p00_r)
Initialize an p99_rwl object.
Definition: p99_rwl.h:94
p99_rwl
A simple rwlock implementation.
Definition: p99_rwl.h:66