P99
p99_cm.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 2016 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_CM_H
22 #define P99_CM_H
23 
24 #include "p99_futex.h"
25 #include "p99_enum.h"
26 
64 
65 struct p99_cm {
66  p99_futex p00_c;
67  p99_futex p00_m;
68  size_t waiters;
69 };
70 
72 bool p00_cm_islocked(unsigned p00_act) {
73  return p00_act & 1u;
74 }
75 
77 bool p00_cm_isntlocked(unsigned p00_act) {
78  return ~p00_act & 1u;
79 }
80 
87  if (p00_cm) {
88  *p00_cm = (p99_cm) { .waiters = 0, };
89  p99_futex_init(&p00_cm->p00_c, 0u);
90  p99_futex_init(&p00_cm->p00_m, 0u);
91  }
92  return p00_cm;
93 }
94 
100 void p99_cm_destroy(p99_cm* p00_cm) {
101  p99_futex_destroy(&p00_cm->p00_c);
102  p99_futex_destroy(&p00_cm->p00_m);
103 }
104 
108 # define P99_CM_INITIALIZER P99_FUTEX_INITIALIZER(p99_cm_unlocked)
109 
110 enum { p00_cm_unlocked, p00_cm_locked, };
111 
112 /* This is only for internal use. Other than @c cnd_signal this
113  supposes that the corresponding mutex part of the condition-mutex
114  is locked. */
116 void p00_cm_signal(p99_cm volatile* p00_cm) {
117  if (p00_cm->waiters) {
118  /* In most of the cases the waiter will already be in the kernel
119  wait when we arrive here: this thread has acquired the lock,
120  done whatever processing and now is releasing the
121  lock. Nevertheless there is a small window, where we may have
122  doubled a waiter thread. Therefore we force a busy wait if
123  necessary, until we have woken up someone. */
124  p99_futex_wakeup(&p00_cm->p00_c, 1u, 1u);
125  --p00_cm->waiters;
126  }
127 }
128 
130 void p00_cm_unlock(p99_cm volatile* p00_cm) {
131  p99_futex_exchange(&p00_cm->p00_m, p00_cm_unlocked, p00_cm_unlocked, 1u, 0u, 1u);
132 }
133 
146 void p99_cm_unlock(p99_cm volatile* p00_cm) {
147  p00_cm_signal(p00_cm);
148  p00_cm_unlock(p00_cm);
149 }
150 
162 void p99_cm_lock(p99_cm volatile* p00_cm) {
163  P99_FUTEX_COMPARE_EXCHANGE(&p00_cm->p00_m, p00_act,
164  // wait while locked by another thread
165  p00_act == p00_cm_unlocked,
166  p00_cm_locked,
167  // never wake up anyone
168  0u, 0u);
169 }
170 
179 bool p99_cm_trylock(p99_cm volatile* p00_cm) {
180  return p99_futex_exchange(&p00_cm->p00_m, p00_cm_locked, 0u, 0u, 0u, 0u);
181 }
182 
189 P00_FUTEX_INLINE(p99_cm_wait)
190 void p99_cm_wait(p99_cm volatile* p00_cm) {
191  ++p00_cm->waiters;
192  p00_cm_unlock(p00_cm);
193  p99_futex_wait(&p00_cm->p00_c);
194  p99_cm_lock(p00_cm);
195 }
196 
213 #define P99_CM_EXCLUDE(CMP) P00_CM_EXCLUDE(CMP, P99_UNIQ(cm))
214 
215 #define P00_CM_EXCLUDE(CMP, ID) \
216 P00_BLK_START \
217 P00_BLK_DECL(register p99_cm volatile*const, ID, (CMP)) \
218 P00_BLK_BEFAFT(p99_cm_lock(ID), \
219  p99_cm_unlock(ID)) \
220 P00_BLK_END
221 
222 
223 
229 #endif
void
void void
Definition: p99_bitset.h:84
p99_futex.h
p99_cm::p99_cm_lock
void p99_cm_lock(p99_cm volatile *p00_cm)
Acquire p00_cm.
Definition: p99_cm.h:162
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_cm
struct p99_cm p99_cm
A simple condition-mutex data structure.
Definition: p99_cm.h:63
p99_cm
Definition: p99_cm.h:65
p99_cm::p99_cm_destroy
void p99_cm_destroy(p99_cm *p00_cm)
destroy a cm
Definition: p99_cm.h:100
p99_futex::p99_futex_exchange
unsigned p99_futex_exchange(p99_futex volatile *p00_fut, unsigned p00_desired, unsigned p00_cstart, unsigned p00_clen, unsigned p00_wmin, unsigned p00_wmax)
Unconditionally and atomically set the futex p00_fut to value p00_desired.
p99_cm::p99_cm_unlock
void p99_cm_unlock(p99_cm volatile *p00_cm)
Unconditionally unlock p00_cm and wake up a waiter, if any.
Definition: p99_cm.h:146
p99_inline
#define p99_inline
Try to force a function always to be inlined.
Definition: p99_compiler.h:496
p99_cm::p99_cm_wait
void p99_cm_wait(p99_cm volatile *p00_cm)
Wait until another thread successfully locks and unlocks p00_cm.
Definition: p99_cm.h:190
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_DECLARE_STRUCT
#define P99_DECLARE_STRUCT(NAME)
forward declaration of a struct NAME
Definition: p99_type.h:59
p99_enum.h
p99_futex::p99_futex_wakeup
void p99_futex_wakeup(p99_futex volatile *p00_fut, unsigned p00_wmin, unsigned p00_wmax)
Wake up threads that are waiting for a futex.
p99_futex::p99_futex_wait
void p99_futex_wait(p99_futex volatile *p00_fut)
Unconditionally wait for futex p00_fut.
p99_cm::p99_cm_init
p99_cm * p99_cm_init(p99_cm *p00_cm)
Initialize a cm.
Definition: p99_cm.h:86
p99_cm::p99_cm_trylock
bool p99_cm_trylock(p99_cm volatile *p00_cm)
Acquire p00_cm.
Definition: p99_cm.h:179
p99_futex::p99_futex_init
p99_futex * p99_futex_init(p99_futex *p00_c, unsigned p00_ini)
Initialize an p99_futex object.
p99_cm::waiters
size_t waiters
Definition: p99_cm.h:68