Lumiera  0.pre.03
»edityourfreedom«
condition.h
Go to the documentation of this file.
1 /*
2  condition.h - condition variables
3 
4  Copyright (C) Lumiera.org
5  2008, 2010, Christian Thaeter <ct@pipapo.org>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 
22 #ifndef LUMIERA_CONDITION_H
23 #define LUMIERA_CONDITION_H
24 
25 #include "lib/error.h"
26 #include "lib/sectionlock.h"
27 #include "lib/lockerror.h"
28 
29 #include <pthread.h>
30 #include <time.h>
31 #include <errno.h>
32 #include <nobug.h>
33 
49 #define LUMIERA_CONDITION_SECTION(nobugflag, cnd) \
50  for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \
51  lumiera_lock_section_ = { \
52  cnd, (lumiera_sectionlock_unlock_fn) lumiera_condition_unlock \
53  NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \
54  ({ \
55  if (lumiera_lock_section_.lock) \
56  lumiera_lock_section_.lock = \
57  lumiera_condition_lock (cnd, &NOBUG_FLAG(nobugflag), \
58  &lumiera_lock_section_.rh, NOBUG_CONTEXT); \
59  lumiera_lock_section_.lock; \
60  }); \
61  ({ \
62  LUMIERA_CONDITION_SECTION_UNLOCK; \
63  }))
64 
65 
66 #define LUMIERA_CONDITION_SECTION_CHAIN(nobugflag, cnd) \
67  for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \
68  NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \
69  cnd, (lumiera_sectionlock_unlock_fn) lumiera_condition_unlock \
70  NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \
71  ({ \
72  if (lumiera_lock_section_.lock) \
73  { \
74  REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \
75  lumiera_lock_section_.lock = \
76  lumiera_condition_lock (cnd, &NOBUG_FLAG(nobugflag), \
77  &lumiera_lock_section_.rh, NOBUG_CONTEXT); \
78  LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \
79  } \
80  lumiera_lock_section_.lock; \
81  }); \
82  ({ \
83  LUMIERA_CONDITION_SECTION_UNLOCK; \
84  }))
85 
86 
87 #define LUMIERA_CONDITION_SECTION_UNLOCK \
88  LUMIERA_SECTION_UNLOCK_(&lumiera_lock_section_)
89 
90 
96 #define LUMIERA_CONDITION_WAIT(expr) \
97  while (!(expr)) { \
98  REQUIRE (lumiera_lock_section_.lock, "Condition mutex not locked"); \
99  lumiera_condition_wait (lumiera_lock_section_.lock, \
100  lumiera_lock_section_.flag, \
101  &lumiera_lock_section_.rh, \
102  NOBUG_CONTEXT); \
103  } while (!(expr))
104 
105 
113 #define LUMIERA_CONDITION_TIMEDWAIT(expr, timeout) \
114  while (!(expr)) { \
115  REQUIRE (lumiera_lock_section_.lock, "Condition mutex not locked"); \
116  if (!lumiera_condition_timedwait (lumiera_lock_section_.lock, \
117  timeout, \
118  lumiera_lock_section_.flag, \
119  &lumiera_lock_section_.rh, \
120  NOBUG_CONTEXT)) \
121  break; \
122  }
123 
129 #define LUMIERA_CONDITION_SIGNAL \
130  do { \
131  REQUIRE (lumiera_lock_section_.lock, "Condition mutex not locked"); \
132  lumiera_condition_signal (lumiera_lock_section_.lock, \
133  lumiera_lock_section_.flag, \
134  NOBUG_CONTEXT); \
135  } while (0)
136 
137 
143 #define LUMIERA_CONDITION_BROADCAST \
144  do { \
145  REQUIRE (lumiera_lock_section_.lock, "Condition mutex not locked"); \
146  lumiera_condition_broadcast (lumiera_lock_section_.lock, \
147  lumiera_lock_section_.flag, \
148  NOBUG_CONTEXT); \
149  } while (0)
150 
151 
157 {
158  pthread_cond_t cond;
159  pthread_mutex_t cndmutex;
160  RESOURCE_HANDLE (rh);
161 };
162 typedef struct lumiera_condition_struct lumiera_condition;
163 typedef lumiera_condition* LumieraCondition;
164 
165 
173  const char* purpose,
174  struct nobug_flag* flag,
175  const struct nobug_context ctx);
176 
177 
185  struct nobug_flag* flag,
186  const struct nobug_context ctx);
187 
188 
189 static inline LumieraCondition
191  struct nobug_flag* flag,
192  struct nobug_resource_user** handle,
193  const struct nobug_context ctx)
194 {
195  if (self)
196  {
197  NOBUG_RESOURCE_WAIT_CTX (NOBUG_FLAG_RAW(flag), self->rh, "acquire condvar", *handle, ctx)
198  {
199  if (pthread_mutex_lock (&self->cndmutex))
200  LUMIERA_DIE (LOCK_ACQUIRE); /* never reached (in a correct program) */
201 
202  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_EXCLUSIVE, *handle, ctx) /*{}*/;
203  }
204  }
205 
206  return self;
207 }
208 
209 
210 static inline LumieraCondition
212  struct nobug_flag* flag,
213  struct nobug_resource_user** handle,
214  const struct nobug_context ctx)
215 {
216  if (self)
217  {
218  NOBUG_RESOURCE_TRY_CTX (NOBUG_FLAG_RAW(flag), self->rh, "try acquire condvar", *handle, ctx)
219  {
220  int err = pthread_mutex_trylock (&self->cndmutex);
221 
222  if (!err)
223  {
224  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_EXCLUSIVE, *handle, ctx) /*{}*/;
225  }
226  else
227  {
228  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx) /*{}*/;
229  lumiera_lockerror_set (err, flag, ctx);
230  self = NULL;
231  }
232  }
233  }
234 
235  return self;
236 }
237 
238 
239 static inline LumieraCondition
241  const struct timespec* timeout,
242  struct nobug_flag* flag,
243  struct nobug_resource_user** handle,
244  const struct nobug_context ctx)
245 {
246  if (self)
247  {
248  NOBUG_RESOURCE_TRY_CTX (NOBUG_FLAG_RAW(flag), self->rh, "timed acquire condvar", *handle, ctx)
249  {
250  int err = pthread_mutex_timedlock (&self->cndmutex, timeout);
251 
252  if (!err)
253  {
254  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_EXCLUSIVE, *handle, ctx) /*{}*/;
255  }
256  else
257  {
258  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx) /*{}*/;
259  lumiera_lockerror_set (err, flag, ctx);
260  self = NULL;
261  }
262  }
263  }
264 
265  return self;
266 }
267 
268 
269 static inline LumieraCondition
271  struct nobug_flag* flag,
272  struct nobug_resource_user** handle,
273  const struct nobug_context ctx)
274 {
275  if (self)
276  {
277  NOBUG_RESOURCE_STATE_RAW_CTX (flag, NOBUG_RESOURCE_WAITING, *handle, ctx)
278  {
279  pthread_cond_wait (&self->cond, &self->cndmutex);
280 
281  NOBUG_RESOURCE_STATE_RAW_CTX (flag, NOBUG_RESOURCE_EXCLUSIVE, *handle, ctx) /*{}*/;
282  }
283  }
284  return self;
285 }
286 
287 
288 static inline LumieraCondition
290  const struct timespec* timeout,
291  struct nobug_flag* flag,
292  struct nobug_resource_user** handle,
293  const struct nobug_context ctx)
294 {
295  if (self)
296  {
297  NOBUG_RESOURCE_STATE_RAW_CTX (flag, NOBUG_RESOURCE_WAITING, *handle, ctx)
298  {
299  int err;
300  do {
301  err = pthread_cond_timedwait (&self->cond, &self->cndmutex, timeout);
302  } while(err == EINTR);
303 
304  NOBUG_RESOURCE_STATE_RAW_CTX (flag, NOBUG_RESOURCE_EXCLUSIVE, *handle, ctx) /*{}*/;
305 
306  if (err)
307  {
308  lumiera_lockerror_set (err, flag, ctx);
309  self = NULL;
310  }
311  }
312  }
313 
314  return self;
315 }
316 
317 
318 
319 static inline void
321  struct nobug_flag* flag,
322  const struct nobug_context ctx)
323 {
324  NOBUG_TRACE_CTX (NOBUG_FLAG_RAW(flag), ctx, "Signal %p", self);
325  pthread_cond_signal (&self->cond);
326 }
327 
328 
329 static inline void
331  struct nobug_flag* flag,
332  const struct nobug_context ctx)
333 {
334  NOBUG_TRACE_CTX(NOBUG_FLAG_RAW(flag), ctx, "Broadcast %p", self);
335  pthread_cond_broadcast (&self->cond);
336 }
337 
338 
339 static inline void
341  struct nobug_flag* flag,
342  struct nobug_resource_user** handle,
343  const struct nobug_context ctx)
344 {
345  NOBUG_REQUIRE_CTX (self, ctx);
346 
347  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx)
348  {
349  if (pthread_mutex_unlock (&self->cndmutex))
350  LUMIERA_DIE (LOCK_RELEASE); /* never reached (in a correct program) */
351  }
352 }
353 
354 
355 #endif
356 /*
357 // Local Variables:
358 // mode: C
359 // c-file-style: "gnu"
360 // indent-tabs-mode: nil
361 // End:
362 */
static void lumiera_condition_broadcast(LumieraCondition self, struct nobug_flag *flag, const struct nobug_context ctx)
Definition: condition.h:330
lumiera_condition * LumieraCondition
Definition: condition.h:163
Common functions for handling of time values.
definitions and declarations for error-handling on low-level locking
static void lumiera_condition_signal(LumieraCondition self, struct nobug_flag *flag, const struct nobug_context ctx)
Definition: condition.h:320
pthread_mutex_t cndmutex
Definition: condition.h:159
Condition variables.
Definition: condition.h:156
static LumieraCondition lumiera_condition_wait(LumieraCondition self, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Definition: condition.h:270
Lumiera error handling (C interface).
pthread_cond_t cond
Definition: condition.h:158
LumieraCondition lumiera_condition_destroy(LumieraCondition self, struct nobug_flag *flag, const struct nobug_context ctx)
Destroy a condition variable.
Definition: condition.c:50
LumieraCondition lumiera_condition_init(LumieraCondition self, const char *purpose, struct nobug_flag *flag, const struct nobug_context ctx)
Initialise a condition variable.
Definition: condition.c:31
return NULL
Definition: llist.h:596
#define LUMIERA_DIE(err)
Abort unconditionally with a &#39;Fatal Error!&#39; message.
Definition: error.h:63
static LumieraCondition lumiera_condition_timedlock(LumieraCondition self, const struct timespec *timeout, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Definition: condition.h:240
static LumieraCondition lumiera_condition_trylock(LumieraCondition self, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Definition: condition.h:211
static LumieraCondition lumiera_condition_lock(LumieraCondition self, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Definition: condition.h:190
static LumieraCondition lumiera_condition_timedwait(LumieraCondition self, const struct timespec *timeout, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Definition: condition.h:289
static void lumiera_condition_unlock(LumieraCondition self, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Definition: condition.h:340
void lumiera_lockerror_set(int err, struct nobug_flag *flag, const struct nobug_context ctx)
Translate pthread error code into lumiera error.
Definition: lockerror.c:49
Mutex state handle for locked code sections.