1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff *
34219820Sjeff */
35219820Sjeff
36219820Sjeff/*
37219820Sjeff * Abstract:
38219820Sjeff *	Implementation of the grow pools.  The grow pools manage a pool of objects.
39219820Sjeff *	The pools can grow to meet demand, limited only by system memory.
40219820Sjeff *
41219820Sjeff */
42219820Sjeff
43219820Sjeff#if HAVE_CONFIG_H
44219820Sjeff#  include <config.h>
45219820Sjeff#endif				/* HAVE_CONFIG_H */
46219820Sjeff
47219820Sjeff#include <stdlib.h>
48219820Sjeff#include <string.h>
49219820Sjeff#include <complib/cl_qcomppool.h>
50219820Sjeff#include <complib/cl_comppool.h>
51219820Sjeff#include <complib/cl_qpool.h>
52219820Sjeff#include <complib/cl_pool.h>
53219820Sjeff#include <complib/cl_math.h>
54219820Sjeff
55219820Sjeff/*
56219820Sjeff * IMPLEMENTATION OF QUICK COMPOSITE POOL
57219820Sjeff */
58219820Sjeffvoid cl_qcpool_construct(IN cl_qcpool_t * const p_pool)
59219820Sjeff{
60219820Sjeff	CL_ASSERT(p_pool);
61219820Sjeff
62219820Sjeff	memset(p_pool, 0, sizeof(cl_qcpool_t));
63219820Sjeff
64219820Sjeff	p_pool->state = CL_UNINITIALIZED;
65219820Sjeff}
66219820Sjeff
67219820Sjeffcl_status_t
68219820Sjeffcl_qcpool_init(IN cl_qcpool_t * const p_pool,
69219820Sjeff	       IN const size_t min_size,
70219820Sjeff	       IN const size_t max_size,
71219820Sjeff	       IN const size_t grow_size,
72219820Sjeff	       IN const size_t * const component_sizes,
73219820Sjeff	       IN const uint32_t num_components,
74219820Sjeff	       IN cl_pfn_qcpool_init_t pfn_initializer OPTIONAL,
75219820Sjeff	       IN cl_pfn_qcpool_dtor_t pfn_destructor OPTIONAL,
76219820Sjeff	       IN const void *const context)
77219820Sjeff{
78219820Sjeff	cl_status_t status;
79219820Sjeff	uint32_t i;
80219820Sjeff
81219820Sjeff	CL_ASSERT(p_pool);
82219820Sjeff	/* Must have a minimum of 1 component. */
83219820Sjeff	CL_ASSERT(num_components);
84219820Sjeff	/* A component size array is required. */
85219820Sjeff	CL_ASSERT(component_sizes);
86219820Sjeff	/*
87219820Sjeff	 * If no initializer is provided, the first component must be large
88219820Sjeff	 * enough to hold a pool item.
89219820Sjeff	 */
90219820Sjeff	CL_ASSERT(pfn_initializer ||
91219820Sjeff		  (component_sizes[0] >= sizeof(cl_pool_item_t)));
92219820Sjeff
93219820Sjeff	cl_qcpool_construct(p_pool);
94219820Sjeff
95219820Sjeff	if (num_components > 1 && !pfn_initializer)
96219820Sjeff		return (CL_INVALID_SETTING);
97219820Sjeff
98219820Sjeff	if (max_size && max_size < min_size)
99219820Sjeff		return (CL_INVALID_SETTING);
100219820Sjeff
101219820Sjeff	/*
102219820Sjeff	 * Allocate the array of component sizes and component pointers all
103219820Sjeff	 * in one allocation.
104219820Sjeff	 */
105219820Sjeff	p_pool->component_sizes = (size_t *) malloc((sizeof(size_t) +
106219820Sjeff						     sizeof(void *)) *
107219820Sjeff						    num_components);
108219820Sjeff
109219820Sjeff	if (!p_pool->component_sizes)
110219820Sjeff		return (CL_INSUFFICIENT_MEMORY);
111219820Sjeff	else
112219820Sjeff		memset(p_pool->component_sizes, 0,
113219820Sjeff		       (sizeof(size_t) + sizeof(void *)) * num_components);
114219820Sjeff
115219820Sjeff	/* Calculate the pointer to the array of pointers, used for callbacks. */
116219820Sjeff	p_pool->p_components =
117219820Sjeff	    (void **)(p_pool->component_sizes + num_components);
118219820Sjeff
119219820Sjeff	/* Copy the user's sizes into our array for future use. */
120219820Sjeff	memcpy(p_pool->component_sizes, component_sizes,
121219820Sjeff	       sizeof(component_sizes[0]) * num_components);
122219820Sjeff
123219820Sjeff	/* Store the number of components per object. */
124219820Sjeff	p_pool->num_components = num_components;
125219820Sjeff
126219820Sjeff	/* Round up and store the size of the components. */
127219820Sjeff	for (i = 0; i < num_components; i++) {
128219820Sjeff		/*
129219820Sjeff		 * We roundup each component size so that all components
130219820Sjeff		 * are aligned on a natural boundary.
131219820Sjeff		 */
132219820Sjeff		p_pool->component_sizes[i] =
133219820Sjeff		    ROUNDUP(p_pool->component_sizes[i], sizeof(uintn_t));
134219820Sjeff	}
135219820Sjeff
136219820Sjeff	p_pool->max_objects = max_size ? max_size : ~(size_t) 0;
137219820Sjeff	p_pool->grow_size = grow_size;
138219820Sjeff
139219820Sjeff	/* Store callback function pointers. */
140219820Sjeff	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
141219820Sjeff	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
142219820Sjeff	p_pool->context = context;
143219820Sjeff
144219820Sjeff	cl_qlist_init(&p_pool->alloc_list);
145219820Sjeff
146219820Sjeff	cl_qlist_init(&p_pool->free_list);
147219820Sjeff
148219820Sjeff	/*
149219820Sjeff	 * We are now initialized.  We change the initialized flag before
150219820Sjeff	 * growing since the grow function asserts that we are initialized.
151219820Sjeff	 */
152219820Sjeff	p_pool->state = CL_INITIALIZED;
153219820Sjeff
154219820Sjeff	/* Allocate the minimum number of objects as requested. */
155219820Sjeff	if (!min_size)
156219820Sjeff		return (CL_SUCCESS);
157219820Sjeff
158219820Sjeff	status = cl_qcpool_grow(p_pool, min_size);
159219820Sjeff	/* Trap for error and cleanup if necessary. */
160219820Sjeff	if (status != CL_SUCCESS)
161219820Sjeff		cl_qcpool_destroy(p_pool);
162219820Sjeff
163219820Sjeff	return (status);
164219820Sjeff}
165219820Sjeff
166219820Sjeffvoid cl_qcpool_destroy(IN cl_qcpool_t * const p_pool)
167219820Sjeff{
168219820Sjeff	/* CL_ASSERT that a non-NULL pointer was provided. */
169219820Sjeff	CL_ASSERT(p_pool);
170219820Sjeff	/* CL_ASSERT that we are in a valid state (not uninitialized memory). */
171219820Sjeff	CL_ASSERT(cl_is_state_valid(p_pool->state));
172219820Sjeff
173219820Sjeff	if (p_pool->state == CL_INITIALIZED) {
174219820Sjeff		/*
175219820Sjeff		 * Assert if the user hasn't put everything back in the pool
176219820Sjeff		 * before destroying it
177219820Sjeff		 * if they haven't, then most likely they are still using memory
178219820Sjeff		 * that will be freed, and the destructor will not be called!
179219820Sjeff		 */
180219820Sjeff#ifdef _DEBUG_
181219820Sjeff		/* but we do not want "free" version to assert on this one */
182219820Sjeff		CL_ASSERT(cl_qcpool_count(p_pool) == p_pool->num_objects);
183219820Sjeff#endif
184219820Sjeff		/* call the user's destructor for each object in the pool */
185219820Sjeff		if (p_pool->pfn_dtor) {
186219820Sjeff			while (!cl_is_qlist_empty(&p_pool->free_list)) {
187219820Sjeff				p_pool->pfn_dtor((cl_pool_item_t *)
188219820Sjeff						 cl_qlist_remove_head(&p_pool->
189219820Sjeff								      free_list),
190219820Sjeff						 (void *)p_pool->context);
191219820Sjeff			}
192219820Sjeff		} else {
193219820Sjeff			cl_qlist_remove_all(&p_pool->free_list);
194219820Sjeff		}
195219820Sjeff
196219820Sjeff		/* Free all allocated memory blocks. */
197219820Sjeff		while (!cl_is_qlist_empty(&p_pool->alloc_list))
198219820Sjeff			free(cl_qlist_remove_head(&p_pool->alloc_list));
199219820Sjeff
200219820Sjeff		if (p_pool->component_sizes) {
201219820Sjeff			free(p_pool->component_sizes);
202219820Sjeff			p_pool->component_sizes = NULL;
203219820Sjeff		}
204219820Sjeff	}
205219820Sjeff
206219820Sjeff	p_pool->state = CL_UNINITIALIZED;
207219820Sjeff}
208219820Sjeff
209219820Sjeffcl_status_t cl_qcpool_grow(IN cl_qcpool_t * const p_pool, IN size_t obj_count)
210219820Sjeff{
211219820Sjeff	cl_status_t status = CL_SUCCESS;
212219820Sjeff	uint8_t *p_objects;
213219820Sjeff	cl_pool_item_t *p_pool_item;
214219820Sjeff	uint32_t i;
215219820Sjeff	size_t obj_size;
216219820Sjeff
217219820Sjeff	CL_ASSERT(p_pool);
218219820Sjeff	CL_ASSERT(p_pool->state == CL_INITIALIZED);
219219820Sjeff	CL_ASSERT(obj_count);
220219820Sjeff
221219820Sjeff	/* Validate that growth is possible. */
222219820Sjeff	if (p_pool->num_objects == p_pool->max_objects)
223219820Sjeff		return (CL_INSUFFICIENT_MEMORY);
224219820Sjeff
225219820Sjeff	/* Cap the growth to the desired maximum. */
226219820Sjeff	if (obj_count > (p_pool->max_objects - p_pool->num_objects))
227219820Sjeff		obj_count = p_pool->max_objects - p_pool->num_objects;
228219820Sjeff
229219820Sjeff	/* Calculate the size of an object. */
230219820Sjeff	obj_size = 0;
231219820Sjeff	for (i = 0; i < p_pool->num_components; i++)
232219820Sjeff		obj_size += p_pool->component_sizes[i];
233219820Sjeff
234219820Sjeff	/* Allocate the buffer for the new objects. */
235219820Sjeff	p_objects = (uint8_t *)
236219820Sjeff	    malloc(sizeof(cl_list_item_t) + (obj_size * obj_count));
237219820Sjeff
238219820Sjeff	/* Make sure the allocation succeeded. */
239219820Sjeff	if (!p_objects)
240219820Sjeff		return (CL_INSUFFICIENT_MEMORY);
241219820Sjeff	else
242219820Sjeff		memset(p_objects, 0,
243219820Sjeff		       sizeof(cl_list_item_t) + (obj_size * obj_count));
244219820Sjeff
245219820Sjeff	/* Insert the allocation in our list. */
246219820Sjeff	cl_qlist_insert_tail(&p_pool->alloc_list, (cl_list_item_t *) p_objects);
247219820Sjeff	p_objects += sizeof(cl_list_item_t);
248219820Sjeff
249219820Sjeff	/* initialize the new elements and add them to the free list */
250219820Sjeff	while (obj_count--) {
251219820Sjeff		/* Setup the array of components for the current object. */
252219820Sjeff		p_pool->p_components[0] = p_objects;
253219820Sjeff		for (i = 1; i < p_pool->num_components; i++) {
254219820Sjeff			/* Calculate the pointer to the next component. */
255219820Sjeff			p_pool->p_components[i] =
256219820Sjeff			    (uint8_t *) p_pool->p_components[i - 1] +
257219820Sjeff			    p_pool->component_sizes[i - 1];
258219820Sjeff		}
259219820Sjeff
260219820Sjeff		/*
261219820Sjeff		 * call the user's initializer
262219820Sjeff		 * this can fail!
263219820Sjeff		 */
264219820Sjeff		if (p_pool->pfn_init) {
265219820Sjeff			p_pool_item = NULL;
266219820Sjeff			status = p_pool->pfn_init(p_pool->p_components,
267219820Sjeff						  p_pool->num_components,
268219820Sjeff						  (void *)p_pool->context,
269219820Sjeff						  &p_pool_item);
270219820Sjeff			if (status != CL_SUCCESS) {
271219820Sjeff				/*
272219820Sjeff				 * User initialization failed
273219820Sjeff				 * we may have only grown the pool by some partial amount
274219820Sjeff				 * Invoke the destructor for the object that failed
275219820Sjeff				 * initialization.
276219820Sjeff				 */
277219820Sjeff				if (p_pool->pfn_dtor)
278219820Sjeff					p_pool->pfn_dtor(p_pool_item,
279219820Sjeff							 (void *)p_pool->
280219820Sjeff							 context);
281219820Sjeff
282219820Sjeff				/* Return the user's status. */
283219820Sjeff				return (status);
284219820Sjeff			}
285219820Sjeff			CL_ASSERT(p_pool_item);
286219820Sjeff		} else {
287219820Sjeff			/*
288219820Sjeff			 * If no initializer is provided, assume that the pool item
289219820Sjeff			 * is stored at the beginning of the first component.
290219820Sjeff			 */
291219820Sjeff			p_pool_item =
292219820Sjeff			    (cl_pool_item_t *) p_pool->p_components[0];
293219820Sjeff		}
294219820Sjeff
295219820Sjeff#ifdef _DEBUG_
296219820Sjeff		/*
297219820Sjeff		 * Set the pool item's pool pointer to this pool so that we can
298219820Sjeff		 * check that items get returned to the correct pool.
299219820Sjeff		 */
300219820Sjeff		p_pool_item->p_pool = p_pool;
301219820Sjeff#endif
302219820Sjeff
303219820Sjeff		/* Insert the new item in the free list, traping for failure. */
304219820Sjeff		cl_qlist_insert_head(&p_pool->free_list,
305219820Sjeff				     &p_pool_item->list_item);
306219820Sjeff
307219820Sjeff		p_pool->num_objects++;
308219820Sjeff
309219820Sjeff		/* move the pointer to the next item */
310219820Sjeff		p_objects += obj_size;
311219820Sjeff	}
312219820Sjeff
313219820Sjeff	return (status);
314219820Sjeff}
315219820Sjeff
316219820Sjeffcl_pool_item_t *cl_qcpool_get(IN cl_qcpool_t * const p_pool)
317219820Sjeff{
318219820Sjeff	cl_list_item_t *p_list_item;
319219820Sjeff
320219820Sjeff	CL_ASSERT(p_pool);
321219820Sjeff	CL_ASSERT(p_pool->state == CL_INITIALIZED);
322219820Sjeff
323219820Sjeff	if (cl_is_qlist_empty(&p_pool->free_list)) {
324219820Sjeff		/*
325219820Sjeff		 * No object is available.
326219820Sjeff		 * Return NULL if the user does not want automatic growth.
327219820Sjeff		 */
328219820Sjeff		if (!p_pool->grow_size)
329219820Sjeff			return (NULL);
330219820Sjeff
331219820Sjeff		/* We ran out of elements.  Get more */
332219820Sjeff		cl_qcpool_grow(p_pool, p_pool->grow_size);
333219820Sjeff		/*
334219820Sjeff		 * We may not have gotten everything we wanted but we might have
335219820Sjeff		 * gotten something.
336219820Sjeff		 */
337219820Sjeff		if (cl_is_qlist_empty(&p_pool->free_list))
338219820Sjeff			return (NULL);
339219820Sjeff	}
340219820Sjeff
341219820Sjeff	p_list_item = cl_qlist_remove_head(&p_pool->free_list);
342219820Sjeff	/* OK, at this point we have an object */
343219820Sjeff	CL_ASSERT(p_list_item != cl_qlist_end(&p_pool->free_list));
344219820Sjeff	return ((cl_pool_item_t *) p_list_item);
345219820Sjeff}
346219820Sjeff
347219820Sjeffcl_pool_item_t *cl_qcpool_get_tail(IN cl_qcpool_t * const p_pool)
348219820Sjeff{
349219820Sjeff	cl_list_item_t *p_list_item;
350219820Sjeff
351219820Sjeff	CL_ASSERT(p_pool);
352219820Sjeff	CL_ASSERT(p_pool->state == CL_INITIALIZED);
353219820Sjeff
354219820Sjeff	if (cl_is_qlist_empty(&p_pool->free_list)) {
355219820Sjeff		/*
356219820Sjeff		 * No object is available.
357219820Sjeff		 * Return NULL if the user does not want automatic growth.
358219820Sjeff		 */
359219820Sjeff		if (!p_pool->grow_size)
360219820Sjeff			return (NULL);
361219820Sjeff
362219820Sjeff		/* We ran out of elements.  Get more */
363219820Sjeff		cl_qcpool_grow(p_pool, p_pool->grow_size);
364219820Sjeff		/*
365219820Sjeff		 * We may not have gotten everything we wanted but we might have
366219820Sjeff		 * gotten something.
367219820Sjeff		 */
368219820Sjeff		if (cl_is_qlist_empty(&p_pool->free_list))
369219820Sjeff			return (NULL);
370219820Sjeff	}
371219820Sjeff
372219820Sjeff	p_list_item = cl_qlist_remove_tail(&p_pool->free_list);
373219820Sjeff	/* OK, at this point we have an object */
374219820Sjeff	CL_ASSERT(p_list_item != cl_qlist_end(&p_pool->free_list));
375219820Sjeff	return ((cl_pool_item_t *) p_list_item);
376219820Sjeff}
377219820Sjeff
378219820Sjeff/*
379219820Sjeff * IMPLEMENTATION OF QUICK GROW POOL
380219820Sjeff */
381219820Sjeff
382219820Sjeff/*
383219820Sjeff * Callback to translate quick composite to quick grow pool
384219820Sjeff * initializer callback.
385219820Sjeff */
386219820Sjeffstatic cl_status_t
387219820Sjeff__cl_qpool_init_cb(IN void **const p_comp_array,
388219820Sjeff		   IN const uint32_t num_components,
389219820Sjeff		   IN void *const context,
390219820Sjeff		   OUT cl_pool_item_t ** const pp_pool_item)
391219820Sjeff{
392219820Sjeff	cl_qpool_t *p_pool = (cl_qpool_t *) context;
393219820Sjeff
394219820Sjeff	CL_ASSERT(p_pool);
395219820Sjeff	CL_ASSERT(p_pool->pfn_init);
396219820Sjeff	CL_ASSERT(num_components == 1);
397219820Sjeff
398219820Sjeff	UNUSED_PARAM(num_components);
399219820Sjeff
400219820Sjeff	return (p_pool->pfn_init(p_comp_array[0], (void *)p_pool->context,
401219820Sjeff				 pp_pool_item));
402219820Sjeff}
403219820Sjeff
404219820Sjeff/*
405219820Sjeff * Callback to translate quick composite to quick grow pool
406219820Sjeff * destructor callback.
407219820Sjeff */
408219820Sjeffstatic void
409219820Sjeff__cl_qpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
410219820Sjeff		   IN void *const context)
411219820Sjeff{
412219820Sjeff	cl_qpool_t *p_pool = (cl_qpool_t *) context;
413219820Sjeff
414219820Sjeff	CL_ASSERT(p_pool);
415219820Sjeff	CL_ASSERT(p_pool->pfn_dtor);
416219820Sjeff
417219820Sjeff	p_pool->pfn_dtor(p_pool_item, (void *)p_pool->context);
418219820Sjeff}
419219820Sjeff
420219820Sjeffvoid cl_qpool_construct(IN cl_qpool_t * const p_pool)
421219820Sjeff{
422219820Sjeff	memset(p_pool, 0, sizeof(cl_qpool_t));
423219820Sjeff
424219820Sjeff	cl_qcpool_construct(&p_pool->qcpool);
425219820Sjeff}
426219820Sjeff
427219820Sjeffcl_status_t
428219820Sjeffcl_qpool_init(IN cl_qpool_t * const p_pool,
429219820Sjeff	      IN const size_t min_size,
430219820Sjeff	      IN const size_t max_size,
431219820Sjeff	      IN const size_t grow_size,
432219820Sjeff	      IN const size_t object_size,
433219820Sjeff	      IN cl_pfn_qpool_init_t pfn_initializer OPTIONAL,
434219820Sjeff	      IN cl_pfn_qpool_dtor_t pfn_destructor OPTIONAL,
435219820Sjeff	      IN const void *const context)
436219820Sjeff{
437219820Sjeff	cl_status_t status;
438219820Sjeff
439219820Sjeff	CL_ASSERT(p_pool);
440219820Sjeff
441219820Sjeff	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
442219820Sjeff	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
443219820Sjeff	p_pool->context = context;
444219820Sjeff
445219820Sjeff	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
446219820Sjeff				&object_size, 1,
447219820Sjeff				pfn_initializer ? __cl_qpool_init_cb : NULL,
448219820Sjeff				pfn_destructor ? __cl_qpool_dtor_cb : NULL,
449219820Sjeff				p_pool);
450219820Sjeff
451219820Sjeff	return (status);
452219820Sjeff}
453219820Sjeff
454219820Sjeff/*
455219820Sjeff * IMPLEMENTATION OF COMPOSITE POOL
456219820Sjeff */
457219820Sjeff
458219820Sjeff/*
459219820Sjeff * Callback to translate quick composite to compsite pool
460219820Sjeff * initializer callback.
461219820Sjeff */
462219820Sjeffstatic cl_status_t
463219820Sjeff__cl_cpool_init_cb(IN void **const p_comp_array,
464219820Sjeff		   IN const uint32_t num_components,
465219820Sjeff		   IN void *const context,
466219820Sjeff		   OUT cl_pool_item_t ** const pp_pool_item)
467219820Sjeff{
468219820Sjeff	cl_cpool_t *p_pool = (cl_cpool_t *) context;
469219820Sjeff	cl_pool_obj_t *p_pool_obj;
470219820Sjeff	cl_status_t status = CL_SUCCESS;
471219820Sjeff
472219820Sjeff	CL_ASSERT(p_pool);
473219820Sjeff
474219820Sjeff	/*
475219820Sjeff	 * Set our pointer to the list item, which is stored at the beginning of
476219820Sjeff	 * the first component.
477219820Sjeff	 */
478219820Sjeff	p_pool_obj = (cl_pool_obj_t *) p_comp_array[0];
479219820Sjeff	/* Set the pool item pointer for the caller. */
480219820Sjeff	*pp_pool_item = &p_pool_obj->pool_item;
481219820Sjeff
482219820Sjeff	/* Calculate the pointer to the user's first component. */
483219820Sjeff	p_comp_array[0] = ((uint8_t *) p_comp_array[0]) + sizeof(cl_pool_obj_t);
484219820Sjeff
485219820Sjeff	/*
486219820Sjeff	 * Set the object pointer in the pool object to point to the first of the
487219820Sjeff	 * user's components.
488219820Sjeff	 */
489219820Sjeff	p_pool_obj->p_object = p_comp_array[0];
490219820Sjeff
491219820Sjeff	/* Invoke the user's constructor callback. */
492219820Sjeff	if (p_pool->pfn_init) {
493219820Sjeff		status = p_pool->pfn_init(p_comp_array, num_components,
494219820Sjeff					  (void *)p_pool->context);
495219820Sjeff	}
496219820Sjeff
497219820Sjeff	return (status);
498219820Sjeff}
499219820Sjeff
500219820Sjeff/*
501219820Sjeff * Callback to translate quick composite to composite pool
502219820Sjeff * destructor callback.
503219820Sjeff */
504219820Sjeffstatic void
505219820Sjeff__cl_cpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
506219820Sjeff		   IN void *const context)
507219820Sjeff{
508219820Sjeff	cl_cpool_t *p_pool = (cl_cpool_t *) context;
509219820Sjeff
510219820Sjeff	CL_ASSERT(p_pool);
511219820Sjeff	CL_ASSERT(p_pool->pfn_dtor);
512219820Sjeff	CL_ASSERT(((cl_pool_obj_t *) p_pool_item)->p_object);
513219820Sjeff
514219820Sjeff	/* Invoke the user's destructor callback. */
515219820Sjeff	p_pool->pfn_dtor((void *)((cl_pool_obj_t *) p_pool_item)->p_object,
516219820Sjeff			 (void *)p_pool->context);
517219820Sjeff}
518219820Sjeff
519219820Sjeffvoid cl_cpool_construct(IN cl_cpool_t * const p_pool)
520219820Sjeff{
521219820Sjeff	CL_ASSERT(p_pool);
522219820Sjeff
523219820Sjeff	memset(p_pool, 0, sizeof(cl_cpool_t));
524219820Sjeff
525219820Sjeff	cl_qcpool_construct(&p_pool->qcpool);
526219820Sjeff}
527219820Sjeff
528219820Sjeffcl_status_t
529219820Sjeffcl_cpool_init(IN cl_cpool_t * const p_pool,
530219820Sjeff	      IN const size_t min_size,
531219820Sjeff	      IN const size_t max_size,
532219820Sjeff	      IN const size_t grow_size,
533219820Sjeff	      IN size_t * const component_sizes,
534219820Sjeff	      IN const uint32_t num_components,
535219820Sjeff	      IN cl_pfn_cpool_init_t pfn_initializer OPTIONAL,
536219820Sjeff	      IN cl_pfn_cpool_dtor_t pfn_destructor OPTIONAL,
537219820Sjeff	      IN const void *const context)
538219820Sjeff{
539219820Sjeff	cl_status_t status;
540219820Sjeff
541219820Sjeff	CL_ASSERT(p_pool);
542219820Sjeff	CL_ASSERT(num_components);
543219820Sjeff	CL_ASSERT(component_sizes);
544219820Sjeff
545219820Sjeff	/* Add the size of the pool object to the first component. */
546219820Sjeff	component_sizes[0] += sizeof(cl_pool_obj_t);
547219820Sjeff
548219820Sjeff	/* Store callback function pointers. */
549219820Sjeff	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
550219820Sjeff	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
551219820Sjeff	p_pool->context = context;
552219820Sjeff
553219820Sjeff	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
554219820Sjeff				component_sizes, num_components,
555219820Sjeff				__cl_cpool_init_cb,
556219820Sjeff				pfn_destructor ? __cl_cpool_dtor_cb : NULL,
557219820Sjeff				p_pool);
558219820Sjeff
559219820Sjeff	/* Restore the original value of the first component. */
560219820Sjeff	component_sizes[0] -= sizeof(cl_pool_obj_t);
561219820Sjeff
562219820Sjeff	return (status);
563219820Sjeff}
564219820Sjeff
565219820Sjeff/*
566219820Sjeff * IMPLEMENTATION OF GROW POOL
567219820Sjeff */
568219820Sjeff
569219820Sjeff/*
570219820Sjeff * Callback to translate quick composite to grow pool constructor callback.
571219820Sjeff */
572219820Sjeffstatic cl_status_t
573219820Sjeff__cl_pool_init_cb(IN void **const pp_obj,
574219820Sjeff		  IN const uint32_t count,
575219820Sjeff		  IN void *const context,
576219820Sjeff		  OUT cl_pool_item_t ** const pp_pool_item)
577219820Sjeff{
578219820Sjeff	cl_pool_t *p_pool = (cl_pool_t *) context;
579219820Sjeff	cl_pool_obj_t *p_pool_obj;
580219820Sjeff	cl_status_t status = CL_SUCCESS;
581219820Sjeff
582219820Sjeff	CL_ASSERT(p_pool);
583219820Sjeff	CL_ASSERT(pp_obj);
584219820Sjeff	CL_ASSERT(count == 1);
585219820Sjeff
586219820Sjeff	UNUSED_PARAM(count);
587219820Sjeff
588219820Sjeff	/*
589219820Sjeff	 * Set our pointer to the list item, which is stored at the beginning of
590219820Sjeff	 * the first component.
591219820Sjeff	 */
592219820Sjeff	p_pool_obj = (cl_pool_obj_t *) * pp_obj;
593219820Sjeff	*pp_pool_item = &p_pool_obj->pool_item;
594219820Sjeff
595219820Sjeff	/* Calculate the pointer to the user's first component. */
596219820Sjeff	*pp_obj = ((uint8_t *) * pp_obj) + sizeof(cl_pool_obj_t);
597219820Sjeff
598219820Sjeff	/*
599219820Sjeff	 * Set the object pointer in the pool item to point to the first of the
600219820Sjeff	 * user's components.
601219820Sjeff	 */
602219820Sjeff	p_pool_obj->p_object = *pp_obj;
603219820Sjeff
604219820Sjeff	/* Invoke the user's constructor callback. */
605219820Sjeff	if (p_pool->pfn_init)
606219820Sjeff		status = p_pool->pfn_init(*pp_obj, (void *)p_pool->context);
607219820Sjeff
608219820Sjeff	return (status);
609219820Sjeff}
610219820Sjeff
611219820Sjeff/*
612219820Sjeff * Callback to translate quick composite to grow pool destructor callback.
613219820Sjeff */
614219820Sjeffstatic void
615219820Sjeff__cl_pool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
616219820Sjeff		  IN void *const context)
617219820Sjeff{
618219820Sjeff	cl_pool_t *p_pool = (cl_pool_t *) context;
619219820Sjeff
620219820Sjeff	CL_ASSERT(p_pool);
621219820Sjeff	CL_ASSERT(p_pool->pfn_dtor);
622219820Sjeff	CL_ASSERT(((cl_pool_obj_t *) p_pool_item)->p_object);
623219820Sjeff
624219820Sjeff	/* Invoke the user's destructor callback. */
625219820Sjeff	p_pool->pfn_dtor((void *)((cl_pool_obj_t *) p_pool_item)->p_object,
626219820Sjeff			 (void *)p_pool->context);
627219820Sjeff}
628219820Sjeff
629219820Sjeffvoid cl_pool_construct(IN cl_pool_t * const p_pool)
630219820Sjeff{
631219820Sjeff	CL_ASSERT(p_pool);
632219820Sjeff
633219820Sjeff	memset(p_pool, 0, sizeof(cl_pool_t));
634219820Sjeff
635219820Sjeff	cl_qcpool_construct(&p_pool->qcpool);
636219820Sjeff}
637219820Sjeff
638219820Sjeffcl_status_t
639219820Sjeffcl_pool_init(IN cl_pool_t * const p_pool,
640219820Sjeff	     IN const size_t min_size,
641219820Sjeff	     IN const size_t max_size,
642219820Sjeff	     IN const size_t grow_size,
643219820Sjeff	     IN const size_t object_size,
644219820Sjeff	     IN cl_pfn_pool_init_t pfn_initializer OPTIONAL,
645219820Sjeff	     IN cl_pfn_pool_dtor_t pfn_destructor OPTIONAL,
646219820Sjeff	     IN const void *const context)
647219820Sjeff{
648219820Sjeff	cl_status_t status;
649219820Sjeff	size_t total_size;
650219820Sjeff
651219820Sjeff	CL_ASSERT(p_pool);
652219820Sjeff
653219820Sjeff	/* Add the size of the list item to the first component. */
654219820Sjeff	total_size = object_size + sizeof(cl_pool_obj_t);
655219820Sjeff
656219820Sjeff	/* Store callback function pointers. */
657219820Sjeff	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
658219820Sjeff	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
659219820Sjeff	p_pool->context = context;
660219820Sjeff
661219820Sjeff	/*
662219820Sjeff	 * We need an initializer in all cases for quick composite pool, since
663219820Sjeff	 * the user pointer must be manipulated to hide the prefixed cl_pool_obj_t.
664219820Sjeff	 */
665219820Sjeff	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
666219820Sjeff				&total_size, 1, __cl_pool_init_cb,
667219820Sjeff				pfn_destructor ? __cl_pool_dtor_cb : NULL,
668219820Sjeff				p_pool);
669219820Sjeff
670219820Sjeff	return (status);
671219820Sjeff}
672