Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_pool_multithreaded.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Framework Multithreaded pool implementation.
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
14 #include "afw_internal.h"
15 
16 
17 
18 #ifdef AFW_POOL_DEBUG
19 #undef afw_pool_create_multithreaded
20 #endif
21 
22 
23 #define AFW_IMPLEMENTATION_ID "afw_pool_multithreaded"
24 #include "afw_pool_impl_declares.h"
25 
26 /* multithreaded pool lock begin */
27 #define IMPL_MULTITHREADED_LOCK_BEGIN(xctx) \
28 AFW_LOCK_BEGIN((xctx)->env->multithreaded_pool_lock)
29 
30 /* multithreaded pool lock end */
31 #define IMPL_MULTITHREADED_LOCK_END \
32 AFW_LOCK_END;
33 
34 
36 #define IMPL_DEBUG_LEVEL_detail flag_index_debug_pool_detail
37 #define IMPL_DEBUG_LEVEL_minimal flag_index_debug_pool
38 
39 #define IMPL_PRINT_DEBUG_INFO_Z(level,info_z) \
40 do { \
41  const afw_utf8_t *trace; \
42  if (afw_flag_is_active(xctx->env->IMPL_DEBUG_LEVEL_##level, xctx)) \
43  { \
44  trace = afw_os_backtrace(0, -1, xctx); \
45  afw_debug_write_fz(NULL, source_z, xctx, \
46  "pool %" AFW_INTEGER_FMT " " \
47  info_z \
48  ": before %" AFW_SIZE_T_FMT \
49  " refs %" AFW_INTEGER_FMT \
50  " parent %" AFW_INTEGER_FMT \
51  " multi" \
52  "%s" \
53  "%" AFW_UTF8_FMT, \
54  self->pool_number, \
55  (self->bytes_allocated), \
56  (self->reference_count), \
57  (afw_integer_t)((self->parent) ? self->parent->pool_number : 0), \
58  (char *)((trace) ? "\n" : ""), \
59  (int)((trace) ? (int)trace->len : 0), \
60  (const char *)((trace) ? (const char *)trace->s : "") \
61  ); \
62  } \
63 } while (0) \
64 
65 
66 #define IMPL_PRINT_DEBUG_INFO_FZ(level,format_z,...) \
67 do { \
68  const afw_utf8_t *trace; \
69  if (afw_flag_is_active(xctx->env->IMPL_DEBUG_LEVEL_##level, xctx)) \
70  { \
71  trace = afw_os_backtrace(0, -1, xctx); \
72  afw_debug_write_fz(NULL, source_z, xctx, \
73  "pool %" AFW_INTEGER_FMT " " \
74  format_z \
75  ": before %" AFW_SIZE_T_FMT \
76  " refs %" AFW_INTEGER_FMT \
77  " parent %" AFW_INTEGER_FMT \
78  " multi" \
79  "%s" \
80  "%" AFW_UTF8_FMT, \
81  self->pool_number, \
82  __VA_ARGS__, \
83  (self->bytes_allocated), \
84  (self->reference_count), \
85  (afw_integer_t)((self->parent) ? self->parent->pool_number : 0), \
86  (char *)((trace) ? "\n" : ""), \
87  (int)((trace) ? (int)trace->len : 0), \
88  (const char *)((trace) ? (const char *)trace->s : "") \
89  ); \
90  } \
91 } while (0) \
92 
93 
94 static void
95 impl_add_child(afw_pool_internal_multithreaded_self_t *parent,
97 {
98  afw_pool_add_reference(&parent->pub, xctx);
99 
100  child->next_sibling = parent->first_child;
101  parent->first_child = child;
102 }
103 
104 
105 static void
106 impl_remove_child(afw_pool_internal_multithreaded_self_t *parent,
108 {
111 
112  for (prev = NULL, sibling = parent->first_child;
113  sibling;
114  prev = sibling, sibling = sibling->next_sibling)
115  {
116  if (sibling == child) {
117  if (!prev) {
118  parent->first_child = sibling->next_sibling;
119  }
120  else {
121  prev->next_sibling = sibling->next_sibling;
122  }
123  break;
124  }
125  }
126 
127  if (!sibling) {
128  AFW_THROW_ERROR_Z(general, "Not a child of parent", xctx);
129  }
130 
131  afw_pool_release(&parent->pub, xctx);
132 }
133 
134 
135 /* Create skeleton pool struct. */
137 impl_pool_create(afw_pool_internal_multithreaded_self_t *parent, afw_xctx_t *xctx)
138 {
139  apr_pool_t *apr_p;
141 
142  apr_pool_create(&apr_p, (parent) ? parent->apr_p : NULL);
143  if (!apr_p) {
144  AFW_THROW_ERROR_Z(memory, "Unable to allocate pool", xctx);
145  }
146  self = apr_pcalloc(apr_p, sizeof(afw_pool_internal_multithreaded_self_t));
147  if (!self) {
148  AFW_THROW_ERROR_Z(memory, "Unable to allocate pool", xctx);
149  }
150  self->pub.inf = &impl_afw_pool_inf;
151  self->apr_p = apr_p;
152  self->reference_count = 1;
153  self->parent = parent;
155  &((afw_environment_t *)xctx->env)->pool_number);
156 
157  /* If parent, add this new child. */
158  if (parent) {
159  impl_add_child(parent, self, xctx);
160  }
161 
162  /* Return new pool. */
163  return self;
164 }
165 
166 
167 AFW_DEFINE(const afw_pool_t *)
168 afw_pool_internal_create_base_pool()
169 {
170  apr_pool_t *apr_p;
172 
173  /* Create new pool for environment and initial xctx. */
174  apr_pool_create(&apr_p, NULL);
175  if (!apr_p) {
176  return NULL;
177  };
178 
179  /* Allocate self. */
180  self = apr_pcalloc(apr_p,
182  if (!self) {
183  return NULL;
184  }
185  self->pub.inf = &impl_afw_pool_inf;
186  self->apr_p = apr_p;
187  self->name = &afw_s_base;
188  self->pool_number = 1;
189  self->reference_count = 1;
190 
191  return (const afw_pool_t *)self;
192 }
193 
194 
195 /* Create a new multithreaded pool. */
196 AFW_DEFINE(const afw_pool_t *)
198  const afw_pool_t *parent, afw_xctx_t *xctx)
199 {
201 
202  if (parent) {
203  if (parent != xctx->env->p &&
204  parent->inf != &impl_afw_pool_inf)
205  {
206  AFW_THROW_ERROR_Z(general,
207  "Parent pool must be base or multithreaded", xctx);
208  }
209  }
210  else {
211  parent = xctx->env->p;
212  }
213 
214  self = impl_pool_create((afw_pool_internal_multithreaded_self_t *)parent, xctx);
215 
216  return (const afw_pool_t *)self;
217 }
218 
219 
220 /* Create a new multithreaded pool. */
221 AFW_DEFINE(const afw_pool_t *)
223  const afw_pool_t *parent,
224  afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
225 {
228  afw_pool_create_multithreaded(parent, xctx);
229 
230  IMPL_PRINT_DEBUG_INFO_FZ(minimal,
231  "afw_pool_create_multithreaded %" AFW_INTEGER_FMT,
232  (self->parent) ? self->parent->pool_number : 0);
233 
234  return (const afw_pool_t *)self;
235 }
236 
237 
238 /*
239  * Implementation of method release for interface afw_pool.
240  */
241 void
243  const afw_pool_t * instance,
244  afw_xctx_t *xctx)
245 {
248 
249  /* If instance is NULL, just return. */
251  if (!instance) return;
252 
253  /* Decrement reference count and release pools resources if zero. */
254  if (afw_atomic_integer_decrement(&self->reference_count) == 0) {
255  afw_pool_destroy(instance, xctx);
256  }
257 }
258 
259 /*
260  * Implementation of method add_reference for interface afw_pool.
261  */
262 void
263 impl_afw_pool_add_reference(
264  const afw_pool_t * instance,
265  afw_xctx_t *xctx)
266 {
268 
269  /* If instance is NULL, just return. */
270  if (!instance) return;
271 
272  /* Decrement reference count. */
273  self = (afw_pool_internal_multithreaded_self_t *)instance;
274  afw_atomic_integer_increment(&self->reference_count);
275 }
276 
277 /*
278  * Implementation of method destroy for interface afw_pool.
279  */
280 void
281 impl_afw_pool_destroy(
282  const afw_pool_t * instance,
283  afw_xctx_t *xctx)
284 {
289 
290  /* If instance is NULL, just return. */
291  if (!instance) return;
292 
293  /*
294  * Call all of the cleanup routines for this pool before destroying
295  * children.
296  */
297  for (e = self->first_cleanup; e; e = e->next_cleanup) {
298  e->cleanup(e->data, e->data2, instance, xctx);
299  }
300 
301  /*
302  * Destroy children.
303  *
304  * Release of child sets self->first_child to its next sibling.
305  */
306  for (child = self->first_child;
307  child;
308  child = self->first_child)
309  {
310  afw_pool_destroy((const afw_pool_t *)child, xctx);
311  }
312 
313  /* If parent, removed self as child. */
314  if (self->parent) {
315  impl_remove_child(self->parent, self, xctx);
316  }
317 
318  /* Destroy apr pool. */
319  apr_pool_destroy(self->apr_p);
320 }
321 
322 /*
323  * Implementation of method get_apr_pool for interface afw_pool.
324  */
325 apr_pool_t *
327  const afw_pool_t * instance)
328 {
331  int rv;
332 
333  if (!self->apr_p) {
334  rv = apr_pool_create(&self->apr_p,
335  (self->parent) ? self->parent->apr_p : NULL);
336  if (rv != APR_SUCCESS) {
338  //rv = 0/0;
339  }
340  }
341 
342  return self->apr_p;
343 }
344 
345 /*
346  * Implementation of method calloc for interface afw_pool.
347  */
348 void *
349 impl_afw_pool_calloc(
350  const afw_pool_t * instance,
351  afw_size_t size,
352  afw_xctx_t *xctx)
353 {
356  void *result;
357 
358  /* Don't allow allocate for a size of 0. */
359  if (size == 0) {
360  AFW_THROW_ERROR_Z(general,
361  "Attempt to allocate memory for a size of 0",
362  xctx);
363  }
364 
365  IMPL_MULTITHREADED_LOCK_BEGIN(xctx) {
366  result = apr_pcalloc(self->apr_p, size);
367  self->bytes_allocated += size;
368  }
369  IMPL_MULTITHREADED_LOCK_END;
370 
371  if (!result) {
372  AFW_THROW_ERROR_Z(memory, "Allocate memory error.", xctx);
373  }
374 
375  return result;
376 }
377 
378 /*
379  * Implementation of method malloc for interface afw_pool.
380  */
381 void *
382 impl_afw_pool_malloc(
383  const afw_pool_t * instance,
384  afw_size_t size,
385  afw_xctx_t *xctx)
386 {
389  void *result;
390 
391  /* Don't allow allocate for a size of 0. */
392  if (size == 0) {
393  AFW_THROW_ERROR_Z(general,
394  "Attempt to allocate memory for a size of 0",
395  xctx);
396  }
397 
398  IMPL_MULTITHREADED_LOCK_BEGIN(xctx) {
399  result = apr_palloc(self->apr_p, size);
400  self->bytes_allocated += size;
401  }
402  IMPL_MULTITHREADED_LOCK_END;
403 
404  if (!result) {
405  AFW_THROW_ERROR_Z(memory, "Allocate memory error.", xctx);
406  }
407 
408  return result;
409 }
410 
411 /*
412  * Implementation of method free for interface afw_pool.
413  */
414 void
416  const afw_pool_t * instance,
417  void * address,
418  afw_size_t size,
419  afw_xctx_t *xctx)
420 {
422  AFW_THROW_ERROR_Z(general, "Method not implemented.", xctx);
423 
424 }
425 
426 /*
427  * Implementation of method register_cleanup_before for interface afw_pool.
428  */
429 void
430 impl_afw_pool_register_cleanup_before(
431  const afw_pool_t * instance,
432  void * data,
433  void * data2,
435  afw_xctx_t *xctx)
436 {
440 
441  /* Allocate entry which will also make sure its ok to use pool. */
442  e = afw_pool_calloc_type(instance, afw_pool_cleanup_t, xctx);
443 
444  /* Add entry to front of list of cleanup functions. */
445  e->data = data;
446  e->data2 = data2;
447  e->cleanup = cleanup;
448  e->next_cleanup = self->first_cleanup;
449  self->first_cleanup = e;
450 }
451 
452 /*
453  * Implementation of method deregister_cleanup for interface afw_pool.
454  */
455 void
456 impl_afw_pool_deregister_cleanup(
457  const afw_pool_t * instance,
458  void * data,
459  void * data2,
461  afw_xctx_t *xctx)
462 {
464  afw_pool_cleanup_t *e, *prev;
465 
466  /* Search for entry and remove. */
467  for (prev = (afw_pool_cleanup_t *)& self->first_cleanup,
468  e = self->first_cleanup;
469  e; prev = e, e = e->next_cleanup)
470  {
471  if (e->data == data && e->data2 == data2 && e->cleanup == cleanup) {
472  prev->next_cleanup = e->next_cleanup;
473  break;
474  }
475  }
476 }
477 
478 /*
479  * Implementation of method release_debug for interface afw_pool.
480  */
481 void
482 impl_afw_pool_release_debug(
483  const afw_pool_t * instance,
484  afw_xctx_t *xctx,
485  const afw_utf8_z_t * source_z)
486 {
489 
490  IMPL_PRINT_DEBUG_INFO_Z(minimal, "afw_pool_release");
491 
492  impl_afw_pool_release(instance, xctx);
493 }
494 
495 /*
496  * Implementation of method add_reference for interface afw_pool.
497  */
498 void
499 impl_afw_pool_add_reference_debug(
500  const afw_pool_t * instance,
501  afw_xctx_t *xctx,
502  const afw_utf8_z_t * source_z)
503 {
506 
507  IMPL_PRINT_DEBUG_INFO_Z(minimal, "afw_pool_add_reference");
508 
509  impl_afw_pool_add_reference(instance, xctx);
510 }
511 
512 /*
513  * Implementation of method destroy_debug for interface afw_pool.
514  */
515 void
516 impl_afw_pool_destroy_debug(
517  const afw_pool_t * instance,
518  afw_xctx_t *xctx,
519  const afw_utf8_z_t * source_z)
520 {
523 
524  IMPL_PRINT_DEBUG_INFO_Z(minimal, "afw_pool_destroy");
525 
526  impl_afw_pool_destroy(instance, xctx);
527 }
528 
529 
530 /*
531  * Implementation of method calloc_debug for interface afw_pool.
532  */
533 void *
534 impl_afw_pool_calloc_debug(
535  const afw_pool_t * instance,
536  afw_size_t size,
537  afw_xctx_t *xctx,
538  const afw_utf8_z_t * source_z)
539 {
542 
543  IMPL_PRINT_DEBUG_INFO_FZ(detail,
544  "afw_pool_calloc %" AFW_SIZE_T_FMT,
545  size);
546 
547  return impl_afw_pool_calloc(instance, size, xctx);
548 }
549 
550 /*
551  * Implementation of method malloc_debug for interface afw_pool.
552  */
553 void *
554 impl_afw_pool_malloc_debug(
555  const afw_pool_t * instance,
556  afw_size_t size,
557  afw_xctx_t *xctx,
558  const afw_utf8_z_t * source_z)
559 {
562 
563  IMPL_PRINT_DEBUG_INFO_FZ(detail,
564  "afw_pool_malloc %" AFW_SIZE_T_FMT,
565  size);
566 
567  return impl_afw_pool_malloc(instance, size, xctx);
568 }
569 
570 /*
571  * Implementation of method free_debug for interface afw_pool.
572  */
573 void
574 impl_afw_pool_free_debug(
575  const afw_pool_t * instance,
576  void * address,
577  afw_size_t size,
578  afw_xctx_t *xctx,
579  const afw_utf8_z_t * source_z)
580 {
583 
584  IMPL_PRINT_DEBUG_INFO_FZ(detail,
585  "afw_pool_free %" AFW_SIZE_T_FMT,
586  size);
587 
588  impl_afw_pool_free(instance, address, size, xctx);
589 }
590 
591 /*
592  * Implementation of method register_cleanup_before_debug for interface
593  * afw_pool.
594  */
595 void
596 impl_afw_pool_register_cleanup_before_debug(
597  const afw_pool_t * instance,
598  void * data,
599  void * data2,
601  afw_xctx_t *xctx,
602  const afw_utf8_z_t * source_z)
603 {
606 
607  IMPL_PRINT_DEBUG_INFO_FZ(minimal,
608  "afw_pool_register_cleanup_before %p %p",
609  data, cleanup);
610 
611  impl_afw_pool_register_cleanup_before(instance, data, data2, cleanup, xctx);
612 }
613 
614 /*
615  * Implementation of method deregister_cleanup_debug for interface afw_pool.
616  */
617 void
618 impl_afw_pool_deregister_cleanup_debug(
619  const afw_pool_t * instance,
620  void * data,
621  void * data2,
623  afw_xctx_t *xctx,
624  const afw_utf8_z_t * source_z)
625 {
628 
629  IMPL_PRINT_DEBUG_INFO_FZ(minimal,
630  "afw_pool_deregister_cleanup_debug %p %p",
631  data, cleanup);
632 
633  impl_afw_pool_deregister_cleanup(instance, data, data2, cleanup, xctx);
634 }
AFW_DEFINE(const afw_object_t *)
Adaptive Framework Core Internal.
Interface afw_interface implementation declares.
afw_integer_t afw_atomic_integer_decrement(AFW_ATOMIC afw_integer_t *mem)
Integer atomic decrement.
Definition: afw_atomic.h:96
afw_integer_t afw_atomic_integer_increment(AFW_ATOMIC afw_integer_t *mem)
Integer atomic increment.
Definition: afw_atomic.h:127
#define AFW_INTEGER_FMT
Format string specifier used for afw_integer_t.
Definition: afw_common.h:326
afw_utf8_octet_t afw_utf8_z_t
NFC normalized UTF-8 null terminated string.
Definition: afw_common.h:523
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
void(* afw_pool_cleanup_function_p_t)(void *data, void *data2, const afw_pool_t *p, afw_xctx_t *xctx)
Typedef for pool cleanup functions.
Definition: afw_common.h:954
#define AFW_SIZE_T_FMT
Format string specifier used for afw_size_t.
Definition: afw_common.h:341
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:283
void impl_afw_pool_release(const afw_pool_t *instance, afw_xctx_t *xctx)
void impl_afw_pool_free(const afw_pool_t *instance, void *address, afw_size_t size, afw_xctx_t *xctx)
apr_pool_t * impl_afw_pool_get_apr_pool(const afw_pool_t *instance)
#define afw_pool_destroy(instance, xctx)
Call method destroy of interface afw_pool.
#define afw_pool_add_reference(instance, xctx)
Call method add_reference of interface afw_pool.
#define afw_pool_release(instance, xctx)
Call method release 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_pool_create_multithreaded(const afw_pool_t *parent, afw_xctx_t *xctx)
Create a new multithreaded pool.
afw_pool_create_multithreaded_debug(const afw_pool_t *parent, afw_xctx_t *xctx, const afw_utf8_z_t *source_z)
Debug version of create a new multithreaded pool.
Struct for typedef afw_environment_t defined in afw_common.h.
Definition: afw_common.h:1383
Struct for registered cleanup functions.
Definition: afw_pool.h:35
afw_pool_cleanup_t * next_cleanup
Next cleanup function.
Definition: afw_pool.h:39
apr_pool_t * apr_p
Associated apr pool or NULL if it has not been created.
afw_integer_t pool_number
Unique number for pool.
Interface afw_pool public struct.
Interface afw_xctx public struct.