Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_lock.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Framework lock support
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
9 
15 #include "afw_internal.h"
16 
17 #ifdef AFW_LOCK_DEBUG
18 #undef afw_lock_obtain
19 #undef afw_lock_release
20 #undef afw_lock_read_obtain
21 #undef afw_lock_read_release
22 #undef afw_lock_write_obtain
23 #undef afw_lock_write_release
24 #endif
25 
26 
27 static void
28 impl_lock_destroy(
29  void *data, void *data2, const afw_pool_t *p, afw_xctx_t *xctx)
30 {
31  afw_lock_t *self = (afw_lock_t *)data;
32 
33  /* Ignore errors. */
34  apr_thread_mutex_destroy(self->mutex);
35 }
36 
37 
38 /* Create a lock. */
39 AFW_DEFINE(const afw_lock_t *)
40 afw_lock_create_environment_lock(
41  const afw_utf8_t *lock_id,
42  const afw_pool_t *p,
43  afw_xctx_t *xctx)
44 {
45  afw_lock_t *self;
46  apr_status_t rv;
47 
48  /*
49  * Create environment lock instance. Use apr_pcalloc since
50  * afw_pool is not ready.
51  */
52  self = apr_pcalloc(afw_pool_get_apr_pool(p), sizeof(afw_lock_t));
53  self->lock_id = (lock_id)
54  ? lock_id
55  : &afw_s_a_empty_string;
56  rv = apr_thread_mutex_create(&self->mutex,
57  APR_THREAD_MUTEX_UNNESTED, afw_pool_get_apr_pool(p));
58  if (rv != APR_SUCCESS) {
59  AFW_THROW_ERROR_RV_FZ(general, apr, rv, xctx,
60  "%" AFW_UTF8_FMT
61  " apr_thread_mutex_create() failed",
62  AFW_UTF8_FMT_ARG(self->lock_id));
63  }
64 
65  /* Return new instance. */
66  return self;
67 }
68 
69 
70 
71 /* Create a lock and register in environment. */
72 AFW_DEFINE(const afw_lock_t *)
74  const afw_utf8_t *lock_id,
75  const afw_utf8_t *brief,
76  const afw_utf8_t *description,
77  afw_boolean_t insure_recursive_lock,
78  afw_xctx_t *xctx)
79 {
80  const afw_lock_t *lock;
81 
82  lock = afw_lock_create(lock_id, brief, description,
83  insure_recursive_lock, xctx->env->p, xctx);
84  afw_environment_register_lock(lock->lock_id, lock, xctx);
85  return lock;
86 }
87 
88 
89 
90 /* Create a lock. */
91 AFW_DEFINE(const afw_lock_t *)
93  const afw_utf8_t *lock_id,
94  const afw_utf8_t *brief,
95  const afw_utf8_t *description,
96  afw_boolean_t insure_recursive_lock,
97  const afw_pool_t *p,
98  afw_xctx_t *xctx)
99 {
100  afw_lock_t *self;
101  apr_status_t rv;
102 
103 #ifdef AFW_LOCK_DEBUG
104  const afw_flag_t *flag;
105 #endif
106 
107  /*
108  * Create new instance. Use apr_pcalloc if env->environment_lock
109  * is NULL. This only happens during environment create.
110  */
111  self = afw_pool_calloc_type(p, afw_lock_t, xctx);
112  self->lock_id = (lock_id)
113  ? lock_id
114  : afw_uuid_create_utf8(p, xctx);
115  self->lock_type = (insure_recursive_lock)
116  ? afw_lock_type_thread_recursive_mutex
117  : afw_lock_type_thread_mutex;
118  self->brief = brief;
119  self->description = description;
120 
121 #ifdef AFW_LOCK_DEBUG
122  self->flag_id_debug = afw_utf8_printf(p, xctx,
123  "debug:lock:%" AFW_UTF8_FMT,
124  AFW_UTF8_FMT_ARG(lock_id));
125  flag = afw_environment_get_flag(self->flag_id_debug, xctx);
126  if (!flag) {
127  brief = afw_utf8_printf(p, xctx,
128  "Debug lock %" AFW_UTF8_FMT,
129  AFW_UTF8_FMT_ARG(lock_id));
130  description = afw_utf8_printf(p, xctx,
131  "Debug lock %" AFW_UTF8_FMT ".",
132  AFW_UTF8_FMT_ARG(lock_id));
134  self->flag_id_debug, brief, description,
135  &afw_s_a_flag_debug_lock, xctx);
136  flag = afw_environment_get_flag(self->flag_id_debug, xctx);
137  }
138  self->flag_index_debug = flag->flag_index;
139 #endif
140 
141  rv = apr_thread_mutex_create(&self->mutex,
142  ((insure_recursive_lock)
143  ? APR_THREAD_MUTEX_NESTED
144  : APR_THREAD_MUTEX_DEFAULT),
146  if (rv != APR_SUCCESS) {
147  AFW_THROW_ERROR_RV_FZ(general, apr, rv, xctx,
148  "%" AFW_UTF8_FMT
149  " apr_thread_mutex_create() failed",
150  AFW_UTF8_FMT_ARG(self->lock_id));
151  }
152 
153  /* Destroy instance before pool is destroyed. */
155  self, NULL, impl_lock_destroy, xctx);
156 
157  /* Return new instance. */
158  return self;
159 }
160 
161 
162 static void
163 impl_lock_destroy_rw(
164  void *data, void *data2, const afw_pool_t *p, afw_xctx_t *xctx)
165 {
166  afw_lock_rw_t *self = (afw_lock_rw_t *)data;
167 
168  /* Ignore errors. */
169  apr_thread_rwlock_destroy(self->lock.rwlock);
170 }
171 
172 
173 /* Create a read/write lock and register in environment. */
174 AFW_DEFINE(const afw_lock_rw_t *)
176  const afw_utf8_t *lock_id,
177  const afw_utf8_t *brief,
178  const afw_utf8_t *description,
179  afw_xctx_t *xctx)
180 {
181  const afw_lock_rw_t *rw;
182 
183  rw = afw_lock_create_rw(lock_id, brief, description,
184  xctx->env->p, xctx);
185  afw_environment_register_lock(rw->lock.lock_id, &rw->lock, xctx);
186  return rw;
187 }
188 
189 
190 /* Create a read/write lock. */
191 AFW_DEFINE(const afw_lock_rw_t *)
193  const afw_utf8_t *lock_id,
194  const afw_utf8_t *brief,
195  const afw_utf8_t *description,
196  const afw_pool_t *p,
197  afw_xctx_t *xctx)
198 {
199  afw_lock_rw_t *self;
200  apr_status_t rv;
201 
202 #ifdef AFW_LOCK_DEBUG
203  const afw_flag_t *flag;
204 #endif
205 
206  /* Create new instance. */
207  self = afw_pool_calloc_type(p, afw_lock_rw_t, xctx);
208  self->lock.lock_id = (lock_id)
209  ? lock_id
210  : afw_uuid_create_utf8(p, xctx);
211  self->lock.brief = brief;
212  self->lock.description = description;
213 
214 #ifdef AFW_LOCK_DEBUG
215  self->lock.flag_id_debug = afw_utf8_printf(p, xctx,
216  "debug:lock:%" AFW_UTF8_FMT,
217  AFW_UTF8_FMT_ARG(lock_id));
218  flag = afw_environment_get_flag(self->lock.flag_id_debug, xctx);
219  if (!flag) {
220  brief = afw_utf8_printf(p, xctx,
221  "Debug lock %" AFW_UTF8_FMT,
222  AFW_UTF8_FMT_ARG(lock_id));
223  description = afw_utf8_printf(p, xctx,
224  "Debug lock %" AFW_UTF8_FMT ".",
225  AFW_UTF8_FMT_ARG(lock_id));
227  self->lock.flag_id_debug, brief, description,
228  &afw_s_a_flag_debug_lock, xctx);
229  flag = afw_environment_get_flag(self->lock.flag_id_debug, xctx);
230  }
231  self->lock.flag_index_debug = flag->flag_index;
232 #endif
233 
234  rv = apr_thread_rwlock_create(&self->lock.rwlock, afw_pool_get_apr_pool(p));
235  if (rv != APR_SUCCESS) {
236  AFW_THROW_ERROR_RV_FZ(general, apr, rv, xctx,
237  "%" AFW_UTF8_FMT
238  " apr_thread_rwlock_create() failed",
239  AFW_UTF8_FMT_ARG(self->lock.lock_id));
240  }
241 
242  /* Destroy instance before pool is destroyed. */
244  self, NULL, impl_lock_destroy_rw, xctx);
245 
246  /* Return new instance. */
247  return self;
248 }
249 
250 
251 
252 /* Obtain lock. */
253 AFW_DEFINE(void)
254 afw_lock_obtain(const afw_lock_t *instance, afw_xctx_t *xctx)
255 {
256  afw_lock_t *self = (afw_lock_t *)instance;
257  apr_status_t rv;
258 
259  if (!instance) return;
260 
261  rv = apr_thread_mutex_lock(self->mutex);
262  if (rv != APR_SUCCESS) {
263  AFW_THROW_ERROR_RV_FZ(general, apr, rv, xctx,
264  "%" AFW_UTF8_FMT
265  " apr_thread_mutex_lock() failed",
266  AFW_UTF8_FMT_ARG(self->lock_id));
267  }
268 }
269 
270 
271 /* Debug version of obtain lock. */
272 AFW_DEFINE(void)
274  afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
275 {
276  if (!instance) return;
277 
278  if (afw_flag_is_active(instance->flag_index_debug, xctx)) {
279  afw_debug_write_fz(NULL, source_z, xctx,
280  "lock %" AFW_UTF8_FMT ": afw_lock_obtain",
281  AFW_UTF8_FMT_ARG(instance->lock_id));
282  }
283 
284  /* Call non-debug function. */
285  afw_lock_obtain(instance, xctx);
286 }
287 
288 
289 /* Release lock. */
290 AFW_DEFINE(void)
291 afw_lock_release(const afw_lock_t *instance, afw_xctx_t *xctx)
292 {
293  afw_lock_t *self = (afw_lock_t *)instance;
294  apr_status_t rv;
295 
296  if (!instance) return;
297 
298  rv = apr_thread_mutex_unlock(self->mutex);
299  if (rv != APR_SUCCESS) {
300  AFW_THROW_ERROR_RV_FZ(general, apr, rv, xctx,
301  "%" AFW_UTF8_FMT
302  " apr_thread_mutex_unlock() failed",
303  AFW_UTF8_FMT_ARG(self->lock_id));
304  }
305 }
306 
307 
308 /* Debug version of release lock. */
309 AFW_DEFINE(void)
311  afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
312 {
313  if (!instance) return;
314 
315  if (afw_flag_is_active(instance->flag_index_debug, xctx)) {
316  afw_debug_write_fz(NULL, source_z, xctx,
317  "lock %" AFW_UTF8_FMT ": afw_lock_release",
318  AFW_UTF8_FMT_ARG(instance->lock_id));
319  }
320 
321  /* Call non-debug function. */
322  afw_lock_release(instance, xctx);
323 }
324 
325 
326 /* Obtain read lock. */
327 AFW_DEFINE(void)
329 {
330  afw_lock_rw_t *self = (afw_lock_rw_t *)instance;
331  apr_status_t rv;
332 
333  if (!instance) return;
334 
335  rv = apr_thread_rwlock_rdlock(self->lock.rwlock);
336  if (rv != APR_SUCCESS) {
337  AFW_THROW_ERROR_RV_FZ(general, apr, rv, xctx,
338  "%" AFW_UTF8_FMT
339  " apr_thread_rwlock_rdlock() failed",
340  AFW_UTF8_FMT_ARG(self->lock.lock_id));
341  }
342 }
343 
344 
345 /* Debug version of obtain read lock. */
346 AFW_DEFINE(void)
348  afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
349 {
350  if (!instance) return;
351 
352  if (afw_flag_is_active(instance->lock.flag_index_debug, xctx))
353  {
354  afw_debug_write_fz(NULL, source_z, xctx,
355  "lock %" AFW_UTF8_FMT ": afw_lock_read_obtain",
356  AFW_UTF8_FMT_ARG(instance->lock.lock_id));
357  }
358 
359  /* Call non-debug function. */
360  afw_lock_read_obtain(instance, xctx);
361 }
362 
363 
364 /* Release read lock. */
365 AFW_DEFINE(void)
367 {
368  afw_lock_rw_t *self = (afw_lock_rw_t *)instance;
369  apr_status_t rv;
370 
371  if (!instance) return;
372 
373  rv = apr_thread_rwlock_unlock(self->lock.rwlock);
374  if (rv != APR_SUCCESS) {
375  AFW_THROW_ERROR_RV_FZ(general, apr, rv, xctx,
376  "%" AFW_UTF8_FMT
377  " apr_thread_rwlock_unlock() failed",
378  AFW_UTF8_FMT_ARG(self->lock.lock_id));
379  }
380 }
381 
382 
383 /* Debug version of release read lock. */
384 AFW_DEFINE(void)
386  afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
387 {
388  if (!instance) return;
389 
390  if (afw_flag_is_active(instance->lock.flag_index_debug, xctx)) {
391  afw_debug_write_fz(NULL, source_z, xctx,
392  "lock %" AFW_UTF8_FMT ": afw_lock_read_release",
393  AFW_UTF8_FMT_ARG(instance->lock.lock_id));
394  }
395 
396  /* Call non-debug function. */
397  afw_lock_read_release(instance, xctx);
398 }
399 
400 
401 /* Obtain write lock. */
402 AFW_DEFINE(void)
404 {
405  afw_lock_rw_t *self = (afw_lock_rw_t *)instance;
406  apr_status_t rv;
407 
408  if (!instance) return;
409 
410  rv = apr_thread_rwlock_wrlock(self->lock.rwlock);
411  if (rv != APR_SUCCESS) {
412  AFW_THROW_ERROR_RV_FZ(general, apr, rv, xctx,
413  "%" AFW_UTF8_FMT
414  " apr_thread_rwlock_wrlock() failed",
415  AFW_UTF8_FMT_ARG(self->lock.lock_id));
416  }
417 }
418 
419 
420 /* Debug version of obtain write lock. */
421 AFW_DEFINE(void)
423  afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
424 {
425  if (!instance) return;
426 
427  if (afw_flag_is_active(instance->lock.flag_index_debug, xctx)) {
428  afw_debug_write_fz(NULL, source_z, xctx,
429  "lock %" AFW_UTF8_FMT ": afw_lock_write_obtain",
430  AFW_UTF8_FMT_ARG(instance->lock.lock_id));
431  }
432 
433  afw_lock_write_obtain(instance, xctx);
434 }
435 
436 /* Release write lock. */
437 AFW_DEFINE(void)
439 {
440  afw_lock_rw_t *self = (afw_lock_rw_t *)instance;
441  apr_status_t rv;
442 
443  if (!instance) return;
444 
445  rv = apr_thread_rwlock_unlock(self->lock.rwlock);
446  if (rv != APR_SUCCESS) {
447  AFW_THROW_ERROR_RV_FZ(general, apr, rv, xctx,
448  "%" AFW_UTF8_FMT
449  " apr_thread_rwlock_unlock() failed",
450  AFW_UTF8_FMT_ARG(self->lock.lock_id));
451  }
452 }
453 
454 
455 /* Debug version of release write lock. */
456 AFW_DEFINE(void)
458  afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
459 {
460  if (!instance) return;
461 
462  if (afw_flag_is_active(instance->lock.flag_index_debug, xctx)) {
463  afw_debug_write_fz(NULL, source_z, xctx,
464  "lock %" AFW_UTF8_FMT ": afw_lock_write_release",
465  AFW_UTF8_FMT_ARG(instance->lock.lock_id));
466  }
467 
468  afw_lock_write_release(instance, xctx);
469 }
AFW_DEFINE(const afw_object_t *)
Adaptive Framework Core Internal.
#define AFW_UTF8_FMT_ARG(A_STRING)
Convenience Macro for use with AFW_UTF8_FMT to specify arg.
Definition: afw_common.h:605
_Bool afw_boolean_t
Definition: afw_common.h:373
#define AFW_UTF8_FMT
Format string specifier used for afw_utf8_t.
Definition: afw_common.h:588
afw_utf8_octet_t afw_utf8_z_t
NFC normalized UTF-8 null terminated string.
Definition: afw_common.h:523
afw_debug_write_fz(const afw_interface_implementation_rti_t *rti, const afw_utf8_z_t *source_z, afw_xctx_t *xctx, const afw_utf8_z_t *format_z,...)
Write debug using a printf style format.
Definition: afw_debug.c:46
void afw_environment_register_lock(const afw_utf8_t *lock_id, const afw_lock_t *lock, afw_xctx_t *xctx)
Register an lock.
#define afw_environment_register_flag(flag_id, brief, description, included_by_flag_id, xctx)
Register a flag.
const afw_flag_t * afw_environment_get_flag(const afw_utf8_t *flag_id, afw_xctx_t *xctx)
Get the flag instance associated with flag_id.
#define AFW_THROW_ERROR_RV_FZ(code, rv_source_id, rv, xctx, format_z,...)
Macro used to set error and rv in xctx and throw it.
Definition: afw_error.h:338
#define afw_flag_is_active(flag_index, xctx)
Determine if flag for flag index is set in xctx.
Definition: afw_flag.h:84
afw_lock_write_obtain_debug(const afw_lock_rw_t *instance, afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
Debug version of obtain write lock.
Definition: afw_lock.c:422
afw_lock_create_rw_and_register(const afw_utf8_t *lock_id, const afw_utf8_t *brief, const afw_utf8_t *description, afw_xctx_t *xctx)
Create a read/write lock and register in environment.
Definition: afw_lock.c:175
afw_lock_release(const afw_lock_t *instance, afw_xctx_t *xctx)
Release lock.
Definition: afw_lock.c:291
afw_lock_create_and_register(const afw_utf8_t *lock_id, const afw_utf8_t *brief, const afw_utf8_t *description, afw_boolean_t insure_recursive_lock, afw_xctx_t *xctx)
Create a lock and register in environment.
Definition: afw_lock.c:73
afw_lock_release_debug(const afw_lock_t *instance, afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
Debug version of release lock.
Definition: afw_lock.c:310
afw_lock_read_release(const afw_lock_rw_t *instance, afw_xctx_t *xctx)
Release read lock.
Definition: afw_lock.c:366
afw_lock_write_release(const afw_lock_rw_t *instance, afw_xctx_t *xctx)
Release write lock.
Definition: afw_lock.c:438
afw_lock_write_obtain(const afw_lock_rw_t *instance, afw_xctx_t *xctx)
Obtain write lock.
Definition: afw_lock.c:403
afw_lock_create_rw(const afw_utf8_t *lock_id, const afw_utf8_t *brief, const afw_utf8_t *description, const afw_pool_t *p, afw_xctx_t *xctx)
Create a read/write lock that will last for life of pool.
Definition: afw_lock.c:192
afw_lock_read_obtain_debug(const afw_lock_rw_t *instance, afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
Debug version of obtain read lock.
Definition: afw_lock.c:347
afw_lock_obtain(const afw_lock_t *instance, afw_xctx_t *xctx)
Obtain lock.
Definition: afw_lock.c:254
afw_lock_write_release_debug(const afw_lock_rw_t *instance, afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
Debug version of release write lock.
Definition: afw_lock.c:457
afw_lock_read_obtain(const afw_lock_rw_t *instance, afw_xctx_t *xctx)
Obtain read lock.
Definition: afw_lock.c:328
afw_lock_read_release_debug(const afw_lock_rw_t *instance, afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
Debug version of release read lock.
Definition: afw_lock.c:385
afw_lock_obtain_debug(const afw_lock_t *instance, afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
Debug version of obtain lock.
Definition: afw_lock.c:273
afw_lock_create(const afw_utf8_t *lock_id, const afw_utf8_t *brief, const afw_utf8_t *description, afw_boolean_t insure_recursive_lock, const afw_pool_t *p, afw_xctx_t *xctx)
Create a lock that will last for life of pool.
Definition: afw_lock.c:92
#define afw_pool_get_apr_pool(instance)
Call method get_apr_pool of interface afw_pool.
#define afw_pool_register_cleanup_before(instance, data, data2, cleanup, xctx)
Call method register_cleanup_before of interface afw_pool.
#define afw_pool_calloc_type(instance, type, xctx)
Macro to allocate cleared memory to hold type in pool.
Definition: afw_pool.h:167
afw_utf8_printf(const afw_pool_t *p, afw_xctx_t *xctx, const afw_utf8_z_t *format,...)
Create a utf-8 string using a c format string in specified pool.
Definition: afw_utf8.c:459
afw_uuid_create_utf8(const afw_pool_t *p, afw_xctx_t *xctx)
Create a UUID as a standard format UUID utf-8 string.
Definition: afw_uuid.c:62
Struct used for a registered flag.
Definition: afw_flag.h:32
afw_size_t flag_index
Index of this flag in flags array.
Definition: afw_flag.h:51
Interface afw_pool public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Interface afw_xctx public struct.