Lumiera  0.pre.03
»edit your freedom«
recmutex.h
Go to the documentation of this file.
1 /*
2  recmutex.h - recursive 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_RECMUTEX_H
23 #define LUMIERA_RECMUTEX_H
24 
25 #include "lib/error.h"
26 #include "lib/sectionlock.h"
27 #include "lib/lockerror.h"
28 #include "lib/mutex.h"
29 
30 #include <pthread.h>
31 #include <nobug.h>
32 
41 #define LUMIERA_RECMUTEX_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_recmutex_lock (mtx, &NOBUG_FLAG(nobugflag), \
50  &lumiera_lock_section_.rh, NOBUG_CONTEXT); \
51  lumiera_lock_section_.lock; \
52  }); \
53  ({ \
54  LUMIERA_RECMUTEX_SECTION_UNLOCK; \
55  }))
56 
57 
58 #define LUMIERA_RECMUTEX_SECTION_CHAIN(nobugflag, mtx) \
59  for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \
60  NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \
61  mtx, (lumiera_sectionlock_unlock_fn) lumiera_mutex_unlock \
62  NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \
63  ({ \
64  if (lumiera_lock_section_.lock) \
65  { \
66  REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \
67  lumiera_lock_section_.lock = \
68  lumiera_recmutex_lock (mtx, &NOBUG_FLAG(nobugflag), \
69  lumiera_lock_section_.rh, NOBUG_CONTEXT); \
70  LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \
71  } \
72  lumiera_lock_section_.lock; \
73  }); \
74  ({ \
75  LUMIERA_RECMUTEX_SECTION_UNLOCK; \
76  }))
77 
78 
79 #define LUMIERA_RECMUTEX_SECTION_UNLOCK \
80  LUMIERA_SECTION_UNLOCK_(&lumiera_lock_section_)
81 
82 
83 
89 {
90  pthread_mutex_t recmutex;
91  RESOURCE_HANDLE (rh);
92 };
93 typedef struct lumiera_recmutex_struct lumiera_recmutex;
94 typedef lumiera_recmutex* LumieraRecmutex;
95 
102 LumieraRecmutex
103 lumiera_recmutex_init (LumieraRecmutex self,
104  const char* purpose,
105  struct nobug_flag* flag,
106  const struct nobug_context ctx);
107 
113 LumieraRecmutex
114 lumiera_recmutex_destroy (LumieraRecmutex self,
115  struct nobug_flag* flag,
116  const struct nobug_context ctx);
117 
118 
119 static inline LumieraRecmutex
120 lumiera_recmutex_lock (LumieraRecmutex self,
121  struct nobug_flag* flag,
122  struct nobug_resource_user** handle,
123  const struct nobug_context ctx)
124 {
125  if (self)
126  {
127  NOBUG_RESOURCE_WAIT_CTX (NOBUG_FLAG_RAW(flag), self->rh, "acquire mutex", *handle, ctx)
128  {
129  if (pthread_mutex_lock (&self->recmutex))
130  LUMIERA_DIE (LOCK_ACQUIRE); /* never reached (in a correct program) */
131 
132  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_RECURSIVE, *handle, ctx) /*{}*/;
133  }
134  }
135 
136  return self;
137 }
138 
139 
140 static inline LumieraRecmutex
141 lumiera_recmutex_trylock (LumieraRecmutex self,
142  struct nobug_flag* flag,
143  struct nobug_resource_user** handle,
144  const struct nobug_context ctx)
145 {
146  if (self)
147  {
148  NOBUG_RESOURCE_TRY_CTX (NOBUG_FLAG_RAW(flag), self->rh, "try acquire mutex", *handle, ctx)
149  {
150  int err = pthread_mutex_trylock (&self->recmutex);
151 
152  if (!err)
153  {
154  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_RECURSIVE, *handle, ctx) /*{}*/;
155  }
156  else
157  {
158  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx) /*{}*/;
159  lumiera_lockerror_set (err, flag, ctx);
160  self = NULL;
161  }
162  }
163  }
164 
165  return self;
166 }
167 
168 
169 static inline LumieraRecmutex
170 lumiera_recmutex_timedlock (LumieraRecmutex self,
171  const struct timespec* timeout,
172  struct nobug_flag* flag,
173  struct nobug_resource_user** handle,
174  const struct nobug_context ctx)
175 {
176  if (self)
177  {
178  NOBUG_RESOURCE_TRY_CTX (NOBUG_FLAG_RAW(flag), self->rh, "timed acquire mutex", *handle, ctx)
179  {
180  int err = pthread_mutex_timedlock (&self->recmutex, timeout);
181 
182  if (!err)
183  {
184  NOBUG_RESOURCE_STATE_CTX (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_RECURSIVE, *handle, ctx) /*{}*/;
185  }
186  else
187  {
188  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx) /*{}*/;
189  lumiera_lockerror_set (err, flag, ctx);
190  self = NULL;
191  }
192  }
193  }
194 
195  return self;
196 }
197 
198 
199 static inline void
200 lumiera_recmutex_unlock (LumieraRecmutex self,
201  struct nobug_flag* flag,
202  struct nobug_resource_user** handle,
203  const struct nobug_context ctx)
204 {
205  NOBUG_REQUIRE_CTX (self, ctx);
206 
207  NOBUG_RESOURCE_LEAVE_RAW_CTX (flag, *handle, ctx)
208  {
209  if (pthread_mutex_unlock (&self->recmutex))
210  LUMIERA_DIE (LOCK_RELEASE); /* never reached (in a correct program) */
211  }
212 }
213 
214 
215 #endif
216 /*
217 // Local Variables:
218 // mode: C
219 // c-file-style: "gnu"
220 // indent-tabs-mode: nil
221 // End:
222 */
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:62
Lumiera error handling (C interface).
Recursive Mutex.
Definition: recmutex.h:88
#define LUMIERA_DIE(err)
Abort unconditionally with a &#39;Fatal Error!&#39; message.
Definition: error.h:63
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:41
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.