Lumiera  0.pre.03
»edit your freedom«
mutex.h
Go to the documentation of this file.
1 /*
2  mutex.h - mutal exclusion locking
3 
4  Copyright (C) Lumiera.org
5  2008, 2009, 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_MUTEX_H
23 #define LUMIERA_MUTEX_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 <nobug.h>
32 
41 #define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \
42  for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \
43  lumiera_lock_section_ = { \
44  mtx, (lumiera_sectionlock_unlock_fn) lumiera_mutex_unlock \
45  NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \
46  ({ \
47  if (lumiera_lock_section_.lock) \
48  lumiera_lock_section_.lock = \
49  lumiera_mutex_lock (mtx, &NOBUG_FLAG(nobugflag), \
50  &lumiera_lock_section_.rh, NOBUG_CONTEXT); \
51  lumiera_lock_section_.lock; \
52  }); \
53  ({ \
54  LUMIERA_MUTEX_SECTION_UNLOCK; \
55  }))
56 
57 
65 #define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \
66  for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \
67  NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \
68  mtx, (lumiera_sectionlock_unlock_fn) lumiera_mutex_unlock \
69  NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \
70  ({ \
71  if (lumiera_lock_section_.lock) \
72  { \
73  REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \
74  lumiera_lock_section_.lock = \
75  lumiera_mutex_lock (mtx, &NOBUG_FLAG(nobugflag), \
76  &lumiera_lock_section_.rh, NOBUG_CONTEXT); \
77  LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \
78  } \
79  lumiera_lock_section_.lock; \
80  }); \
81  ({ \
82  LUMIERA_MUTEX_SECTION_UNLOCK; \
83  }))
84 
85 
86 #define LUMIERA_MUTEX_SECTION_UNLOCK \
87  LUMIERA_SECTION_UNLOCK_(&lumiera_lock_section_)
88 
89 
95 {
96  pthread_mutex_t mutex;
97  RESOURCE_HANDLE (rh);
98 };
99 typedef struct lumiera_mutex_struct lumiera_mutex;
100 typedef lumiera_mutex* LumieraMutex;
101 
102 
111 LumieraMutex
112 lumiera_mutex_init (LumieraMutex self,
113  const char* purpose,
114  struct nobug_flag* flag,
115  const struct nobug_context ctx);
116 
123 LumieraMutex
124 lumiera_mutex_destroy (LumieraMutex self,
125  struct nobug_flag* flag,
126  const struct nobug_context ctx);
127 
128 
137 static inline LumieraMutex
138 lumiera_mutex_lock (LumieraMutex self,
139  struct nobug_flag* flag,
140  struct nobug_resource_user** handle,
141  const struct nobug_context ctx)
142 {
143  if (self)
144  {
145  NOBUG_RESOURCE_WAIT_CTX (NOBUG_FLAG_RAW(flag), self->rh, "acquire mutex", *handle, ctx)
146  {
147  if (pthread_mutex_lock (&self->mutex))
148  LUMIERA_DIE (LOCK_ACQUIRE); /* never reached (in a correct program) */
149 
150  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_EXCLUSIVE, *handle, ctx) /*{}*/;
151  }
152  }
153 
154  return self;
155 }
156 
157 
165 static inline LumieraMutex
166 lumiera_mutex_trylock (LumieraMutex self,
167  struct nobug_flag* flag,
168  struct nobug_resource_user** handle,
169  const struct nobug_context ctx)
170 {
171  if (self)
172  {
173  NOBUG_RESOURCE_TRY_CTX (NOBUG_FLAG_RAW(flag), self->rh, "try acquire mutex", *handle, ctx)
174  {
175  int err = pthread_mutex_trylock (&self->mutex);
176 
177  if (!err)
178  {
179  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_EXCLUSIVE, *handle, ctx) /*{}*/;
180  }
181  else
182  {
183  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx) /*{}*/;
184  lumiera_lockerror_set (err, flag, ctx);
185  self = NULL;
186  }
187  }
188  }
189 
190  return self;
191 }
192 
201 static inline LumieraMutex
202 lumiera_mutex_timedlock (LumieraMutex self,
203  const struct timespec* timeout,
204  struct nobug_flag* flag,
205  struct nobug_resource_user** handle,
206  const struct nobug_context ctx)
207 {
208  if (self)
209  {
210  NOBUG_RESOURCE_TRY_CTX (NOBUG_FLAG_RAW(flag), self->rh, "timed acquire mutex", *handle, ctx)
211  {
212  int err = pthread_mutex_timedlock (&self->mutex, timeout);
213 
214  if (!err)
215  {
216  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_EXCLUSIVE, *handle, ctx) /*{}*/;
217  }
218  else
219  {
220  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx) /*{}*/;
221  lumiera_lockerror_set (err, flag, ctx);
222  self = NULL;
223  }
224  }
225  }
226 
227  return self;
228 }
229 
230 
238 static inline void
239 lumiera_mutex_unlock (LumieraMutex self,
240  struct nobug_flag* flag,
241  struct nobug_resource_user** handle,
242  const struct nobug_context ctx)
243 {
244  NOBUG_REQUIRE_CTX (self, ctx);
245 
246  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx)
247  {
248  if (pthread_mutex_unlock (&self->mutex))
249  LUMIERA_DIE (LOCK_RELEASE); /* never reached (in a correct program) */
250  }
251 }
252 
253 
254 #endif
255 /*
256 // Local Variables:
257 // mode: C
258 // c-file-style: "gnu"
259 // indent-tabs-mode: nil
260 // End:
261 */
static LumieraMutex lumiera_mutex_trylock(LumieraMutex self, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Try to lock a mutex variable.
Definition: mutex.h:166
static void lumiera_mutex_unlock(LumieraMutex self, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
unlock a mutex variable Never fails
Definition: mutex.h:239
Common functions for handling of time values.
definitions and declarations for error-handling on low-level locking
Lumiera error handling (C interface).
static LumieraMutex lumiera_mutex_lock(LumieraMutex self, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Lock a mutex variable Never fails.
Definition: mutex.h:138
#define LUMIERA_DIE(err)
Abort unconditionally with a &#39;Fatal Error!&#39; message.
Definition: error.h:63
static LumieraMutex lumiera_mutex_timedlock(LumieraMutex self, const struct timespec *timeout, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Try to lock a mutex variable with a timeout.
Definition: mutex.h:202
LumieraMutex lumiera_mutex_init(LumieraMutex self, const char *purpose, struct nobug_flag *flag, const struct nobug_context ctx)
Initialise a mutex variable This initialises a &#39;fast&#39; default mutex which must not be locked recursiv...
Definition: mutex.c:30
LumieraMutex lumiera_mutex_destroy(LumieraMutex self, struct nobug_flag *flag, const struct nobug_context ctx)
Destroy a mutex variable.
Definition: mutex.c:48
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.