Lumiera  0.pre.03
»edit your freedom«
recmutex.h
Go to the documentation of this file.
1 /*
2  recmutex.h - recursive mutual exclusion locking
3 
4  Copyright (C)
5  2008, 2009, Christian Thaeter <ct@pipapo.org>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 */
12 
13 #ifndef LUMIERA_RECMUTEX_H
14 #define LUMIERA_RECMUTEX_H
15 
16 #include "lib/error.h"
17 #include "lib/sectionlock.h"
18 #include "lib/lockerror.h"
19 #include "lib/mutex.h"
20 
21 #include <pthread.h>
22 #include <nobug.h>
23 
32 #define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx) \
33  for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \
34  lumiera_lock_section_ = { \
35  mtx, (lumiera_sectionlock_unlock_fn) lumiera_mutex_unlock \
36  NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \
37  ({ \
38  if (lumiera_lock_section_.lock) \
39  lumiera_lock_section_.lock = \
40  lumiera_recmutex_lock (mtx, &NOBUG_FLAG(nobugflag), \
41  &lumiera_lock_section_.rh, NOBUG_CONTEXT); \
42  lumiera_lock_section_.lock; \
43  }); \
44  ({ \
45  LUMIERA_RECMUTEX_SECTION_UNLOCK; \
46  }))
47 
48 
49 #define LUMIERA_RECMUTEX_SECTION_CHAIN(nobugflag, mtx) \
50  for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \
51  NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \
52  mtx, (lumiera_sectionlock_unlock_fn) lumiera_mutex_unlock \
53  NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \
54  ({ \
55  if (lumiera_lock_section_.lock) \
56  { \
57  REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \
58  lumiera_lock_section_.lock = \
59  lumiera_recmutex_lock (mtx, &NOBUG_FLAG(nobugflag), \
60  lumiera_lock_section_.rh, NOBUG_CONTEXT); \
61  LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \
62  } \
63  lumiera_lock_section_.lock; \
64  }); \
65  ({ \
66  LUMIERA_RECMUTEX_SECTION_UNLOCK; \
67  }))
68 
69 
70 #define LUMIERA_RECMUTEX_SECTION_UNLOCK \
71  LUMIERA_SECTION_UNLOCK_(&lumiera_lock_section_)
72 
73 
74 
80 {
81  pthread_mutex_t recmutex;
82  RESOURCE_HANDLE (rh);
83 };
84 typedef struct lumiera_recmutex_struct lumiera_recmutex;
85 typedef lumiera_recmutex* LumieraRecmutex;
86 
93 LumieraRecmutex
94 lumiera_recmutex_init (LumieraRecmutex self,
95  const char* purpose,
96  struct nobug_flag* flag,
97  const struct nobug_context ctx);
98 
104 LumieraRecmutex
105 lumiera_recmutex_destroy (LumieraRecmutex self,
106  struct nobug_flag* flag,
107  const struct nobug_context ctx);
108 
109 
110 static inline LumieraRecmutex
111 lumiera_recmutex_lock (LumieraRecmutex self,
112  struct nobug_flag* flag,
113  struct nobug_resource_user** handle,
114  const struct nobug_context ctx)
115 {
116  if (self)
117  {
118  NOBUG_RESOURCE_WAIT_CTX (NOBUG_FLAG_RAW(flag), self->rh, "acquire mutex", *handle, ctx)
119  {
120  if (pthread_mutex_lock (&self->recmutex))
121  LUMIERA_DIE (LOCK_ACQUIRE); /* never reached (in a correct program) */
122 
123  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_RECURSIVE, *handle, ctx) /*{}*/;
124  }
125  }
126 
127  return self;
128 }
129 
130 
131 static inline LumieraRecmutex
132 lumiera_recmutex_trylock (LumieraRecmutex self,
133  struct nobug_flag* flag,
134  struct nobug_resource_user** handle,
135  const struct nobug_context ctx)
136 {
137  if (self)
138  {
139  NOBUG_RESOURCE_TRY_CTX (NOBUG_FLAG_RAW(flag), self->rh, "try acquire mutex", *handle, ctx)
140  {
141  int err = pthread_mutex_trylock (&self->recmutex);
142 
143  if (!err)
144  {
145  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_RECURSIVE, *handle, ctx) /*{}*/;
146  }
147  else
148  {
149  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx) /*{}*/;
150  lumiera_lockerror_set (err, flag, ctx);
151  self = NULL;
152  }
153  }
154  }
155 
156  return self;
157 }
158 
159 
160 static inline LumieraRecmutex
161 lumiera_recmutex_timedlock (LumieraRecmutex self,
162  const struct timespec* timeout,
163  struct nobug_flag* flag,
164  struct nobug_resource_user** handle,
165  const struct nobug_context ctx)
166 {
167  if (self)
168  {
169  NOBUG_RESOURCE_TRY_CTX (NOBUG_FLAG_RAW(flag), self->rh, "timed acquire mutex", *handle, ctx)
170  {
171  int err = pthread_mutex_timedlock (&self->recmutex, timeout);
172 
173  if (!err)
174  {
175  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_RECURSIVE, *handle, ctx) /*{}*/;
176  }
177  else
178  {
179  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx) /*{}*/;
180  lumiera_lockerror_set (err, flag, ctx);
181  self = NULL;
182  }
183  }
184  }
185 
186  return self;
187 }
188 
189 
190 static inline void
191 lumiera_recmutex_unlock (LumieraRecmutex self,
192  struct nobug_flag* flag,
193  struct nobug_resource_user** handle,
194  const struct nobug_context ctx)
195 {
196  NOBUG_REQUIRE_CTX (self, ctx);
197 
198  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx)
199  {
200  if (pthread_mutex_unlock (&self->recmutex))
201  LUMIERA_DIE (LOCK_RELEASE); /* never reached (in a correct program) */
202  }
203 }
204 
205 
206 #endif
207 /*
208 // Local Variables:
209 // mode: C
210 // c-file-style: "gnu"
211 // indent-tabs-mode: nil
212 // End:
213 */
definitions and declarations for error-handling on low-level locking
LumieraRecmutex lumiera_recmutex_destroy(LumieraRecmutex self, struct nobug_flag *flag, const struct nobug_context ctx)
Destroy a recursive mutex variable.
Definition: recmutex.c:53
Lumiera error handling (C interface).
Recursive Mutex.
Definition: recmutex.h:79
#define LUMIERA_DIE(err)
Abort unconditionally with a &#39;Fatal Error!&#39; message.
Definition: error.h:54
Mutual exclusion locking, header.
LumieraRecmutex lumiera_recmutex_init(LumieraRecmutex self, const char *purpose, struct nobug_flag *flag, const struct nobug_context ctx)
Initialise a recursive mutex variable Initialises a &#39;recursive&#39; mutex which might be locked by the sa...
Definition: recmutex.c:32
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:40
Mutex state handle for locked code sections.