xref: /trueos/contrib/ofed/management/opensm/complib/cl_pool.c (revision 8fe640108653f13042f1b15213769e338aa524f6)
1 /*
2  * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35 
36 /*
37  * Abstract:
38  *	Implementation of the grow pools.  The grow pools manage a pool of objects.
39  *	The pools can grow to meet demand, limited only by system memory.
40  *
41  */
42 
43 #if HAVE_CONFIG_H
44 #  include <config.h>
45 #endif				/* HAVE_CONFIG_H */
46 
47 #include <stdlib.h>
48 #include <string.h>
49 #include <complib/cl_qcomppool.h>
50 #include <complib/cl_comppool.h>
51 #include <complib/cl_qpool.h>
52 #include <complib/cl_pool.h>
53 #include <complib/cl_math.h>
54 
55 /*
56  * IMPLEMENTATION OF QUICK COMPOSITE POOL
57  */
cl_qcpool_construct(IN cl_qcpool_t * const p_pool)58 void cl_qcpool_construct(IN cl_qcpool_t * const p_pool)
59 {
60 	CL_ASSERT(p_pool);
61 
62 	memset(p_pool, 0, sizeof(cl_qcpool_t));
63 
64 	p_pool->state = CL_UNINITIALIZED;
65 }
66 
67 cl_status_t
cl_qcpool_init(IN cl_qcpool_t * const p_pool,IN const size_t min_size,IN const size_t max_size,IN const size_t grow_size,IN const size_t * const component_sizes,IN const uint32_t num_components,IN cl_pfn_qcpool_init_t pfn_initializer OPTIONAL,IN cl_pfn_qcpool_dtor_t pfn_destructor OPTIONAL,IN const void * const context)68 cl_qcpool_init(IN cl_qcpool_t * const p_pool,
69 	       IN const size_t min_size,
70 	       IN const size_t max_size,
71 	       IN const size_t grow_size,
72 	       IN const size_t * const component_sizes,
73 	       IN const uint32_t num_components,
74 	       IN cl_pfn_qcpool_init_t pfn_initializer OPTIONAL,
75 	       IN cl_pfn_qcpool_dtor_t pfn_destructor OPTIONAL,
76 	       IN const void *const context)
77 {
78 	cl_status_t status;
79 	uint32_t i;
80 
81 	CL_ASSERT(p_pool);
82 	/* Must have a minimum of 1 component. */
83 	CL_ASSERT(num_components);
84 	/* A component size array is required. */
85 	CL_ASSERT(component_sizes);
86 	/*
87 	 * If no initializer is provided, the first component must be large
88 	 * enough to hold a pool item.
89 	 */
90 	CL_ASSERT(pfn_initializer ||
91 		  (component_sizes[0] >= sizeof(cl_pool_item_t)));
92 
93 	cl_qcpool_construct(p_pool);
94 
95 	if (num_components > 1 && !pfn_initializer)
96 		return (CL_INVALID_SETTING);
97 
98 	if (max_size && max_size < min_size)
99 		return (CL_INVALID_SETTING);
100 
101 	/*
102 	 * Allocate the array of component sizes and component pointers all
103 	 * in one allocation.
104 	 */
105 	p_pool->component_sizes = (size_t *) malloc((sizeof(size_t) +
106 						     sizeof(void *)) *
107 						    num_components);
108 
109 	if (!p_pool->component_sizes)
110 		return (CL_INSUFFICIENT_MEMORY);
111 	else
112 		memset(p_pool->component_sizes, 0,
113 		       (sizeof(size_t) + sizeof(void *)) * num_components);
114 
115 	/* Calculate the pointer to the array of pointers, used for callbacks. */
116 	p_pool->p_components =
117 	    (void **)(p_pool->component_sizes + num_components);
118 
119 	/* Copy the user's sizes into our array for future use. */
120 	memcpy(p_pool->component_sizes, component_sizes,
121 	       sizeof(component_sizes[0]) * num_components);
122 
123 	/* Store the number of components per object. */
124 	p_pool->num_components = num_components;
125 
126 	/* Round up and store the size of the components. */
127 	for (i = 0; i < num_components; i++) {
128 		/*
129 		 * We roundup each component size so that all components
130 		 * are aligned on a natural boundary.
131 		 */
132 		p_pool->component_sizes[i] =
133 		    ROUNDUP(p_pool->component_sizes[i], sizeof(uintn_t));
134 	}
135 
136 	p_pool->max_objects = max_size ? max_size : ~(size_t) 0;
137 	p_pool->grow_size = grow_size;
138 
139 	/* Store callback function pointers. */
140 	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
141 	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
142 	p_pool->context = context;
143 
144 	cl_qlist_init(&p_pool->alloc_list);
145 
146 	cl_qlist_init(&p_pool->free_list);
147 
148 	/*
149 	 * We are now initialized.  We change the initialized flag before
150 	 * growing since the grow function asserts that we are initialized.
151 	 */
152 	p_pool->state = CL_INITIALIZED;
153 
154 	/* Allocate the minimum number of objects as requested. */
155 	if (!min_size)
156 		return (CL_SUCCESS);
157 
158 	status = cl_qcpool_grow(p_pool, min_size);
159 	/* Trap for error and cleanup if necessary. */
160 	if (status != CL_SUCCESS)
161 		cl_qcpool_destroy(p_pool);
162 
163 	return (status);
164 }
165 
cl_qcpool_destroy(IN cl_qcpool_t * const p_pool)166 void cl_qcpool_destroy(IN cl_qcpool_t * const p_pool)
167 {
168 	/* CL_ASSERT that a non-NULL pointer was provided. */
169 	CL_ASSERT(p_pool);
170 	/* CL_ASSERT that we are in a valid state (not uninitialized memory). */
171 	CL_ASSERT(cl_is_state_valid(p_pool->state));
172 
173 	if (p_pool->state == CL_INITIALIZED) {
174 		/*
175 		 * Assert if the user hasn't put everything back in the pool
176 		 * before destroying it
177 		 * if they haven't, then most likely they are still using memory
178 		 * that will be freed, and the destructor will not be called!
179 		 */
180 #ifdef _DEBUG_
181 		/* but we do not want "free" version to assert on this one */
182 		CL_ASSERT(cl_qcpool_count(p_pool) == p_pool->num_objects);
183 #endif
184 		/* call the user's destructor for each object in the pool */
185 		if (p_pool->pfn_dtor) {
186 			while (!cl_is_qlist_empty(&p_pool->free_list)) {
187 				p_pool->pfn_dtor((cl_pool_item_t *)
188 						 cl_qlist_remove_head(&p_pool->
189 								      free_list),
190 						 (void *)p_pool->context);
191 			}
192 		} else {
193 			cl_qlist_remove_all(&p_pool->free_list);
194 		}
195 
196 		/* Free all allocated memory blocks. */
197 		while (!cl_is_qlist_empty(&p_pool->alloc_list))
198 			free(cl_qlist_remove_head(&p_pool->alloc_list));
199 
200 		if (p_pool->component_sizes) {
201 			free(p_pool->component_sizes);
202 			p_pool->component_sizes = NULL;
203 		}
204 	}
205 
206 	p_pool->state = CL_UNINITIALIZED;
207 }
208 
cl_qcpool_grow(IN cl_qcpool_t * const p_pool,IN size_t obj_count)209 cl_status_t cl_qcpool_grow(IN cl_qcpool_t * const p_pool, IN size_t obj_count)
210 {
211 	cl_status_t status = CL_SUCCESS;
212 	uint8_t *p_objects;
213 	cl_pool_item_t *p_pool_item;
214 	uint32_t i;
215 	size_t obj_size;
216 
217 	CL_ASSERT(p_pool);
218 	CL_ASSERT(p_pool->state == CL_INITIALIZED);
219 	CL_ASSERT(obj_count);
220 
221 	/* Validate that growth is possible. */
222 	if (p_pool->num_objects == p_pool->max_objects)
223 		return (CL_INSUFFICIENT_MEMORY);
224 
225 	/* Cap the growth to the desired maximum. */
226 	if (obj_count > (p_pool->max_objects - p_pool->num_objects))
227 		obj_count = p_pool->max_objects - p_pool->num_objects;
228 
229 	/* Calculate the size of an object. */
230 	obj_size = 0;
231 	for (i = 0; i < p_pool->num_components; i++)
232 		obj_size += p_pool->component_sizes[i];
233 
234 	/* Allocate the buffer for the new objects. */
235 	p_objects = (uint8_t *)
236 	    malloc(sizeof(cl_list_item_t) + (obj_size * obj_count));
237 
238 	/* Make sure the allocation succeeded. */
239 	if (!p_objects)
240 		return (CL_INSUFFICIENT_MEMORY);
241 	else
242 		memset(p_objects, 0,
243 		       sizeof(cl_list_item_t) + (obj_size * obj_count));
244 
245 	/* Insert the allocation in our list. */
246 	cl_qlist_insert_tail(&p_pool->alloc_list, (cl_list_item_t *) p_objects);
247 	p_objects += sizeof(cl_list_item_t);
248 
249 	/* initialize the new elements and add them to the free list */
250 	while (obj_count--) {
251 		/* Setup the array of components for the current object. */
252 		p_pool->p_components[0] = p_objects;
253 		for (i = 1; i < p_pool->num_components; i++) {
254 			/* Calculate the pointer to the next component. */
255 			p_pool->p_components[i] =
256 			    (uint8_t *) p_pool->p_components[i - 1] +
257 			    p_pool->component_sizes[i - 1];
258 		}
259 
260 		/*
261 		 * call the user's initializer
262 		 * this can fail!
263 		 */
264 		if (p_pool->pfn_init) {
265 			p_pool_item = NULL;
266 			status = p_pool->pfn_init(p_pool->p_components,
267 						  p_pool->num_components,
268 						  (void *)p_pool->context,
269 						  &p_pool_item);
270 			if (status != CL_SUCCESS) {
271 				/*
272 				 * User initialization failed
273 				 * we may have only grown the pool by some partial amount
274 				 * Invoke the destructor for the object that failed
275 				 * initialization.
276 				 */
277 				if (p_pool->pfn_dtor)
278 					p_pool->pfn_dtor(p_pool_item,
279 							 (void *)p_pool->
280 							 context);
281 
282 				/* Return the user's status. */
283 				return (status);
284 			}
285 			CL_ASSERT(p_pool_item);
286 		} else {
287 			/*
288 			 * If no initializer is provided, assume that the pool item
289 			 * is stored at the beginning of the first component.
290 			 */
291 			p_pool_item =
292 			    (cl_pool_item_t *) p_pool->p_components[0];
293 		}
294 
295 #ifdef _DEBUG_
296 		/*
297 		 * Set the pool item's pool pointer to this pool so that we can
298 		 * check that items get returned to the correct pool.
299 		 */
300 		p_pool_item->p_pool = p_pool;
301 #endif
302 
303 		/* Insert the new item in the free list, traping for failure. */
304 		cl_qlist_insert_head(&p_pool->free_list,
305 				     &p_pool_item->list_item);
306 
307 		p_pool->num_objects++;
308 
309 		/* move the pointer to the next item */
310 		p_objects += obj_size;
311 	}
312 
313 	return (status);
314 }
315 
cl_qcpool_get(IN cl_qcpool_t * const p_pool)316 cl_pool_item_t *cl_qcpool_get(IN cl_qcpool_t * const p_pool)
317 {
318 	cl_list_item_t *p_list_item;
319 
320 	CL_ASSERT(p_pool);
321 	CL_ASSERT(p_pool->state == CL_INITIALIZED);
322 
323 	if (cl_is_qlist_empty(&p_pool->free_list)) {
324 		/*
325 		 * No object is available.
326 		 * Return NULL if the user does not want automatic growth.
327 		 */
328 		if (!p_pool->grow_size)
329 			return (NULL);
330 
331 		/* We ran out of elements.  Get more */
332 		cl_qcpool_grow(p_pool, p_pool->grow_size);
333 		/*
334 		 * We may not have gotten everything we wanted but we might have
335 		 * gotten something.
336 		 */
337 		if (cl_is_qlist_empty(&p_pool->free_list))
338 			return (NULL);
339 	}
340 
341 	p_list_item = cl_qlist_remove_head(&p_pool->free_list);
342 	/* OK, at this point we have an object */
343 	CL_ASSERT(p_list_item != cl_qlist_end(&p_pool->free_list));
344 	return ((cl_pool_item_t *) p_list_item);
345 }
346 
cl_qcpool_get_tail(IN cl_qcpool_t * const p_pool)347 cl_pool_item_t *cl_qcpool_get_tail(IN cl_qcpool_t * const p_pool)
348 {
349 	cl_list_item_t *p_list_item;
350 
351 	CL_ASSERT(p_pool);
352 	CL_ASSERT(p_pool->state == CL_INITIALIZED);
353 
354 	if (cl_is_qlist_empty(&p_pool->free_list)) {
355 		/*
356 		 * No object is available.
357 		 * Return NULL if the user does not want automatic growth.
358 		 */
359 		if (!p_pool->grow_size)
360 			return (NULL);
361 
362 		/* We ran out of elements.  Get more */
363 		cl_qcpool_grow(p_pool, p_pool->grow_size);
364 		/*
365 		 * We may not have gotten everything we wanted but we might have
366 		 * gotten something.
367 		 */
368 		if (cl_is_qlist_empty(&p_pool->free_list))
369 			return (NULL);
370 	}
371 
372 	p_list_item = cl_qlist_remove_tail(&p_pool->free_list);
373 	/* OK, at this point we have an object */
374 	CL_ASSERT(p_list_item != cl_qlist_end(&p_pool->free_list));
375 	return ((cl_pool_item_t *) p_list_item);
376 }
377 
378 /*
379  * IMPLEMENTATION OF QUICK GROW POOL
380  */
381 
382 /*
383  * Callback to translate quick composite to quick grow pool
384  * initializer callback.
385  */
386 static cl_status_t
__cl_qpool_init_cb(IN void ** const p_comp_array,IN const uint32_t num_components,IN void * const context,OUT cl_pool_item_t ** const pp_pool_item)387 __cl_qpool_init_cb(IN void **const p_comp_array,
388 		   IN const uint32_t num_components,
389 		   IN void *const context,
390 		   OUT cl_pool_item_t ** const pp_pool_item)
391 {
392 	cl_qpool_t *p_pool = (cl_qpool_t *) context;
393 
394 	CL_ASSERT(p_pool);
395 	CL_ASSERT(p_pool->pfn_init);
396 	CL_ASSERT(num_components == 1);
397 
398 	UNUSED_PARAM(num_components);
399 
400 	return (p_pool->pfn_init(p_comp_array[0], (void *)p_pool->context,
401 				 pp_pool_item));
402 }
403 
404 /*
405  * Callback to translate quick composite to quick grow pool
406  * destructor callback.
407  */
408 static void
__cl_qpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,IN void * const context)409 __cl_qpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
410 		   IN void *const context)
411 {
412 	cl_qpool_t *p_pool = (cl_qpool_t *) context;
413 
414 	CL_ASSERT(p_pool);
415 	CL_ASSERT(p_pool->pfn_dtor);
416 
417 	p_pool->pfn_dtor(p_pool_item, (void *)p_pool->context);
418 }
419 
cl_qpool_construct(IN cl_qpool_t * const p_pool)420 void cl_qpool_construct(IN cl_qpool_t * const p_pool)
421 {
422 	memset(p_pool, 0, sizeof(cl_qpool_t));
423 
424 	cl_qcpool_construct(&p_pool->qcpool);
425 }
426 
427 cl_status_t
cl_qpool_init(IN cl_qpool_t * const p_pool,IN const size_t min_size,IN const size_t max_size,IN const size_t grow_size,IN const size_t object_size,IN cl_pfn_qpool_init_t pfn_initializer OPTIONAL,IN cl_pfn_qpool_dtor_t pfn_destructor OPTIONAL,IN const void * const context)428 cl_qpool_init(IN cl_qpool_t * const p_pool,
429 	      IN const size_t min_size,
430 	      IN const size_t max_size,
431 	      IN const size_t grow_size,
432 	      IN const size_t object_size,
433 	      IN cl_pfn_qpool_init_t pfn_initializer OPTIONAL,
434 	      IN cl_pfn_qpool_dtor_t pfn_destructor OPTIONAL,
435 	      IN const void *const context)
436 {
437 	cl_status_t status;
438 
439 	CL_ASSERT(p_pool);
440 
441 	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
442 	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
443 	p_pool->context = context;
444 
445 	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
446 				&object_size, 1,
447 				pfn_initializer ? __cl_qpool_init_cb : NULL,
448 				pfn_destructor ? __cl_qpool_dtor_cb : NULL,
449 				p_pool);
450 
451 	return (status);
452 }
453 
454 /*
455  * IMPLEMENTATION OF COMPOSITE POOL
456  */
457 
458 /*
459  * Callback to translate quick composite to compsite pool
460  * initializer callback.
461  */
462 static cl_status_t
__cl_cpool_init_cb(IN void ** const p_comp_array,IN const uint32_t num_components,IN void * const context,OUT cl_pool_item_t ** const pp_pool_item)463 __cl_cpool_init_cb(IN void **const p_comp_array,
464 		   IN const uint32_t num_components,
465 		   IN void *const context,
466 		   OUT cl_pool_item_t ** const pp_pool_item)
467 {
468 	cl_cpool_t *p_pool = (cl_cpool_t *) context;
469 	cl_pool_obj_t *p_pool_obj;
470 	cl_status_t status = CL_SUCCESS;
471 
472 	CL_ASSERT(p_pool);
473 
474 	/*
475 	 * Set our pointer to the list item, which is stored at the beginning of
476 	 * the first component.
477 	 */
478 	p_pool_obj = (cl_pool_obj_t *) p_comp_array[0];
479 	/* Set the pool item pointer for the caller. */
480 	*pp_pool_item = &p_pool_obj->pool_item;
481 
482 	/* Calculate the pointer to the user's first component. */
483 	p_comp_array[0] = ((uint8_t *) p_comp_array[0]) + sizeof(cl_pool_obj_t);
484 
485 	/*
486 	 * Set the object pointer in the pool object to point to the first of the
487 	 * user's components.
488 	 */
489 	p_pool_obj->p_object = p_comp_array[0];
490 
491 	/* Invoke the user's constructor callback. */
492 	if (p_pool->pfn_init) {
493 		status = p_pool->pfn_init(p_comp_array, num_components,
494 					  (void *)p_pool->context);
495 	}
496 
497 	return (status);
498 }
499 
500 /*
501  * Callback to translate quick composite to composite pool
502  * destructor callback.
503  */
504 static void
__cl_cpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,IN void * const context)505 __cl_cpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
506 		   IN void *const context)
507 {
508 	cl_cpool_t *p_pool = (cl_cpool_t *) context;
509 
510 	CL_ASSERT(p_pool);
511 	CL_ASSERT(p_pool->pfn_dtor);
512 	CL_ASSERT(((cl_pool_obj_t *) p_pool_item)->p_object);
513 
514 	/* Invoke the user's destructor callback. */
515 	p_pool->pfn_dtor((void *)((cl_pool_obj_t *) p_pool_item)->p_object,
516 			 (void *)p_pool->context);
517 }
518 
cl_cpool_construct(IN cl_cpool_t * const p_pool)519 void cl_cpool_construct(IN cl_cpool_t * const p_pool)
520 {
521 	CL_ASSERT(p_pool);
522 
523 	memset(p_pool, 0, sizeof(cl_cpool_t));
524 
525 	cl_qcpool_construct(&p_pool->qcpool);
526 }
527 
528 cl_status_t
cl_cpool_init(IN cl_cpool_t * const p_pool,IN const size_t min_size,IN const size_t max_size,IN const size_t grow_size,IN size_t * const component_sizes,IN const uint32_t num_components,IN cl_pfn_cpool_init_t pfn_initializer OPTIONAL,IN cl_pfn_cpool_dtor_t pfn_destructor OPTIONAL,IN const void * const context)529 cl_cpool_init(IN cl_cpool_t * const p_pool,
530 	      IN const size_t min_size,
531 	      IN const size_t max_size,
532 	      IN const size_t grow_size,
533 	      IN size_t * const component_sizes,
534 	      IN const uint32_t num_components,
535 	      IN cl_pfn_cpool_init_t pfn_initializer OPTIONAL,
536 	      IN cl_pfn_cpool_dtor_t pfn_destructor OPTIONAL,
537 	      IN const void *const context)
538 {
539 	cl_status_t status;
540 
541 	CL_ASSERT(p_pool);
542 	CL_ASSERT(num_components);
543 	CL_ASSERT(component_sizes);
544 
545 	/* Add the size of the pool object to the first component. */
546 	component_sizes[0] += sizeof(cl_pool_obj_t);
547 
548 	/* Store callback function pointers. */
549 	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
550 	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
551 	p_pool->context = context;
552 
553 	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
554 				component_sizes, num_components,
555 				__cl_cpool_init_cb,
556 				pfn_destructor ? __cl_cpool_dtor_cb : NULL,
557 				p_pool);
558 
559 	/* Restore the original value of the first component. */
560 	component_sizes[0] -= sizeof(cl_pool_obj_t);
561 
562 	return (status);
563 }
564 
565 /*
566  * IMPLEMENTATION OF GROW POOL
567  */
568 
569 /*
570  * Callback to translate quick composite to grow pool constructor callback.
571  */
572 static cl_status_t
__cl_pool_init_cb(IN void ** const pp_obj,IN const uint32_t count,IN void * const context,OUT cl_pool_item_t ** const pp_pool_item)573 __cl_pool_init_cb(IN void **const pp_obj,
574 		  IN const uint32_t count,
575 		  IN void *const context,
576 		  OUT cl_pool_item_t ** const pp_pool_item)
577 {
578 	cl_pool_t *p_pool = (cl_pool_t *) context;
579 	cl_pool_obj_t *p_pool_obj;
580 	cl_status_t status = CL_SUCCESS;
581 
582 	CL_ASSERT(p_pool);
583 	CL_ASSERT(pp_obj);
584 	CL_ASSERT(count == 1);
585 
586 	UNUSED_PARAM(count);
587 
588 	/*
589 	 * Set our pointer to the list item, which is stored at the beginning of
590 	 * the first component.
591 	 */
592 	p_pool_obj = (cl_pool_obj_t *) * pp_obj;
593 	*pp_pool_item = &p_pool_obj->pool_item;
594 
595 	/* Calculate the pointer to the user's first component. */
596 	*pp_obj = ((uint8_t *) * pp_obj) + sizeof(cl_pool_obj_t);
597 
598 	/*
599 	 * Set the object pointer in the pool item to point to the first of the
600 	 * user's components.
601 	 */
602 	p_pool_obj->p_object = *pp_obj;
603 
604 	/* Invoke the user's constructor callback. */
605 	if (p_pool->pfn_init)
606 		status = p_pool->pfn_init(*pp_obj, (void *)p_pool->context);
607 
608 	return (status);
609 }
610 
611 /*
612  * Callback to translate quick composite to grow pool destructor callback.
613  */
614 static void
__cl_pool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,IN void * const context)615 __cl_pool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
616 		  IN void *const context)
617 {
618 	cl_pool_t *p_pool = (cl_pool_t *) context;
619 
620 	CL_ASSERT(p_pool);
621 	CL_ASSERT(p_pool->pfn_dtor);
622 	CL_ASSERT(((cl_pool_obj_t *) p_pool_item)->p_object);
623 
624 	/* Invoke the user's destructor callback. */
625 	p_pool->pfn_dtor((void *)((cl_pool_obj_t *) p_pool_item)->p_object,
626 			 (void *)p_pool->context);
627 }
628 
cl_pool_construct(IN cl_pool_t * const p_pool)629 void cl_pool_construct(IN cl_pool_t * const p_pool)
630 {
631 	CL_ASSERT(p_pool);
632 
633 	memset(p_pool, 0, sizeof(cl_pool_t));
634 
635 	cl_qcpool_construct(&p_pool->qcpool);
636 }
637 
638 cl_status_t
cl_pool_init(IN cl_pool_t * const p_pool,IN const size_t min_size,IN const size_t max_size,IN const size_t grow_size,IN const size_t object_size,IN cl_pfn_pool_init_t pfn_initializer OPTIONAL,IN cl_pfn_pool_dtor_t pfn_destructor OPTIONAL,IN const void * const context)639 cl_pool_init(IN cl_pool_t * const p_pool,
640 	     IN const size_t min_size,
641 	     IN const size_t max_size,
642 	     IN const size_t grow_size,
643 	     IN const size_t object_size,
644 	     IN cl_pfn_pool_init_t pfn_initializer OPTIONAL,
645 	     IN cl_pfn_pool_dtor_t pfn_destructor OPTIONAL,
646 	     IN const void *const context)
647 {
648 	cl_status_t status;
649 	size_t total_size;
650 
651 	CL_ASSERT(p_pool);
652 
653 	/* Add the size of the list item to the first component. */
654 	total_size = object_size + sizeof(cl_pool_obj_t);
655 
656 	/* Store callback function pointers. */
657 	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
658 	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
659 	p_pool->context = context;
660 
661 	/*
662 	 * We need an initializer in all cases for quick composite pool, since
663 	 * the user pointer must be manipulated to hide the prefixed cl_pool_obj_t.
664 	 */
665 	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
666 				&total_size, 1, __cl_pool_init_cb,
667 				pfn_destructor ? __cl_pool_dtor_cb : NULL,
668 				p_pool);
669 
670 	return (status);
671 }
672