1321936Shselasky/*
2321936Shselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3321936Shselasky * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4321936Shselasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5321936Shselasky *
6321936Shselasky * This software is available to you under a choice of one of two
7321936Shselasky * licenses.  You may choose to be licensed under the terms of the GNU
8321936Shselasky * General Public License (GPL) Version 2, available from the file
9321936Shselasky * COPYING in the main directory of this source tree, or the
10321936Shselasky * OpenIB.org BSD license below:
11321936Shselasky *
12321936Shselasky *     Redistribution and use in source and binary forms, with or
13321936Shselasky *     without modification, are permitted provided that the following
14321936Shselasky *     conditions are met:
15321936Shselasky *
16321936Shselasky *      - Redistributions of source code must retain the above
17321936Shselasky *        copyright notice, this list of conditions and the following
18321936Shselasky *        disclaimer.
19321936Shselasky *
20321936Shselasky *      - Redistributions in binary form must reproduce the above
21321936Shselasky *        copyright notice, this list of conditions and the following
22321936Shselasky *        disclaimer in the documentation and/or other materials
23321936Shselasky *        provided with the distribution.
24321936Shselasky *
25321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32321936Shselasky * SOFTWARE.
33321936Shselasky *
34321936Shselasky */
35321936Shselasky
36321936Shselasky/*
37321936Shselasky * Abstract:
38321936Shselasky *	Implementation of the grow pools.  The grow pools manage a pool of objects.
39321936Shselasky *	The pools can grow to meet demand, limited only by system memory.
40321936Shselasky *
41321936Shselasky */
42321936Shselasky
43321936Shselasky#if HAVE_CONFIG_H
44321936Shselasky#  include <config.h>
45321936Shselasky#endif				/* HAVE_CONFIG_H */
46321936Shselasky
47321936Shselasky#include <stdlib.h>
48321936Shselasky#include <string.h>
49321936Shselasky#include <complib/cl_qcomppool.h>
50321936Shselasky#include <complib/cl_comppool.h>
51321936Shselasky#include <complib/cl_qpool.h>
52321936Shselasky#include <complib/cl_pool.h>
53321936Shselasky#include <complib/cl_math.h>
54321936Shselasky
55321936Shselasky/*
56321936Shselasky * IMPLEMENTATION OF QUICK COMPOSITE POOL
57321936Shselasky */
58321936Shselaskyvoid cl_qcpool_construct(IN cl_qcpool_t * const p_pool)
59321936Shselasky{
60321936Shselasky	CL_ASSERT(p_pool);
61321936Shselasky
62321936Shselasky	memset(p_pool, 0, sizeof(cl_qcpool_t));
63321936Shselasky
64321936Shselasky	p_pool->state = CL_UNINITIALIZED;
65321936Shselasky}
66321936Shselasky
67321936Shselaskycl_status_t cl_qcpool_init(IN cl_qcpool_t * const p_pool,
68321936Shselasky			   IN const size_t min_size, IN const size_t max_size,
69321936Shselasky			   IN const size_t grow_size,
70321936Shselasky			   IN const size_t * const component_sizes,
71321936Shselasky			   IN const uint32_t num_components,
72321936Shselasky			   IN cl_pfn_qcpool_init_t pfn_initializer OPTIONAL,
73321936Shselasky			   IN cl_pfn_qcpool_dtor_t pfn_destructor OPTIONAL,
74321936Shselasky			   IN const void *const context)
75321936Shselasky{
76321936Shselasky	cl_status_t status;
77321936Shselasky	uint32_t i;
78321936Shselasky
79321936Shselasky	CL_ASSERT(p_pool);
80321936Shselasky	/* Must have a minimum of 1 component. */
81321936Shselasky	CL_ASSERT(num_components);
82321936Shselasky	/* A component size array is required. */
83321936Shselasky	CL_ASSERT(component_sizes);
84321936Shselasky	/*
85321936Shselasky	 * If no initializer is provided, the first component must be large
86321936Shselasky	 * enough to hold a pool item.
87321936Shselasky	 */
88321936Shselasky	CL_ASSERT(pfn_initializer ||
89321936Shselasky		  (component_sizes[0] >= sizeof(cl_pool_item_t)));
90321936Shselasky
91321936Shselasky	cl_qcpool_construct(p_pool);
92321936Shselasky
93321936Shselasky	if (num_components > 1 && !pfn_initializer)
94321936Shselasky		return (CL_INVALID_SETTING);
95321936Shselasky
96321936Shselasky	if (max_size && max_size < min_size)
97321936Shselasky		return (CL_INVALID_SETTING);
98321936Shselasky
99321936Shselasky	/*
100321936Shselasky	 * Allocate the array of component sizes and component pointers all
101321936Shselasky	 * in one allocation.
102321936Shselasky	 */
103321936Shselasky	p_pool->component_sizes = (size_t *) malloc((sizeof(size_t) +
104321936Shselasky						     sizeof(void *)) *
105321936Shselasky						    num_components);
106321936Shselasky
107321936Shselasky	if (!p_pool->component_sizes)
108321936Shselasky		return (CL_INSUFFICIENT_MEMORY);
109321936Shselasky	else
110321936Shselasky		memset(p_pool->component_sizes, 0,
111321936Shselasky		       (sizeof(size_t) + sizeof(void *)) * num_components);
112321936Shselasky
113321936Shselasky	/* Calculate the pointer to the array of pointers, used for callbacks. */
114321936Shselasky	p_pool->p_components =
115321936Shselasky	    (void **)(p_pool->component_sizes + num_components);
116321936Shselasky
117321936Shselasky	/* Copy the user's sizes into our array for future use. */
118321936Shselasky	memcpy(p_pool->component_sizes, component_sizes,
119321936Shselasky	       sizeof(component_sizes[0]) * num_components);
120321936Shselasky
121321936Shselasky	/* Store the number of components per object. */
122321936Shselasky	p_pool->num_components = num_components;
123321936Shselasky
124321936Shselasky	/* Round up and store the size of the components. */
125321936Shselasky	for (i = 0; i < num_components; i++) {
126321936Shselasky		/*
127321936Shselasky		 * We roundup each component size so that all components
128321936Shselasky		 * are aligned on a natural boundary.
129321936Shselasky		 */
130321936Shselasky		p_pool->component_sizes[i] =
131321936Shselasky		    ROUNDUP(p_pool->component_sizes[i], sizeof(uintptr_t));
132321936Shselasky	}
133321936Shselasky
134321936Shselasky	p_pool->max_objects = max_size ? max_size : ~(size_t) 0;
135321936Shselasky	p_pool->grow_size = grow_size;
136321936Shselasky
137321936Shselasky	/* Store callback function pointers. */
138321936Shselasky	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
139321936Shselasky	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
140321936Shselasky	p_pool->context = context;
141321936Shselasky
142321936Shselasky	cl_qlist_init(&p_pool->alloc_list);
143321936Shselasky
144321936Shselasky	cl_qlist_init(&p_pool->free_list);
145321936Shselasky
146321936Shselasky	/*
147321936Shselasky	 * We are now initialized.  We change the initialized flag before
148321936Shselasky	 * growing since the grow function asserts that we are initialized.
149321936Shselasky	 */
150321936Shselasky	p_pool->state = CL_INITIALIZED;
151321936Shselasky
152321936Shselasky	/* Allocate the minimum number of objects as requested. */
153321936Shselasky	if (!min_size)
154321936Shselasky		return (CL_SUCCESS);
155321936Shselasky
156321936Shselasky	status = cl_qcpool_grow(p_pool, min_size);
157321936Shselasky	/* Trap for error and cleanup if necessary. */
158321936Shselasky	if (status != CL_SUCCESS)
159321936Shselasky		cl_qcpool_destroy(p_pool);
160321936Shselasky
161321936Shselasky	return (status);
162321936Shselasky}
163321936Shselasky
164321936Shselaskyvoid cl_qcpool_destroy(IN cl_qcpool_t * const p_pool)
165321936Shselasky{
166321936Shselasky	/* CL_ASSERT that a non-NULL pointer was provided. */
167321936Shselasky	CL_ASSERT(p_pool);
168321936Shselasky	/* CL_ASSERT that we are in a valid state (not uninitialized memory). */
169321936Shselasky	CL_ASSERT(cl_is_state_valid(p_pool->state));
170321936Shselasky
171321936Shselasky	if (p_pool->state == CL_INITIALIZED) {
172321936Shselasky		/*
173321936Shselasky		 * Assert if the user hasn't put everything back in the pool
174321936Shselasky		 * before destroying it
175321936Shselasky		 * if they haven't, then most likely they are still using memory
176321936Shselasky		 * that will be freed, and the destructor will not be called!
177321936Shselasky		 */
178321936Shselasky#ifdef _DEBUG_
179321936Shselasky		/* but we do not want "free" version to assert on this one */
180321936Shselasky		CL_ASSERT(cl_qcpool_count(p_pool) == p_pool->num_objects);
181321936Shselasky#endif
182321936Shselasky		/* call the user's destructor for each object in the pool */
183321936Shselasky		if (p_pool->pfn_dtor) {
184321936Shselasky			while (!cl_is_qlist_empty(&p_pool->free_list)) {
185321936Shselasky				p_pool->pfn_dtor((cl_pool_item_t *)
186321936Shselasky						 cl_qlist_remove_head(&p_pool->
187321936Shselasky								      free_list),
188321936Shselasky						 (void *)p_pool->context);
189321936Shselasky			}
190321936Shselasky		} else {
191321936Shselasky			cl_qlist_remove_all(&p_pool->free_list);
192321936Shselasky		}
193321936Shselasky
194321936Shselasky		/* Free all allocated memory blocks. */
195321936Shselasky		while (!cl_is_qlist_empty(&p_pool->alloc_list))
196321936Shselasky			free(cl_qlist_remove_head(&p_pool->alloc_list));
197321936Shselasky
198321936Shselasky		if (p_pool->component_sizes) {
199321936Shselasky			free(p_pool->component_sizes);
200321936Shselasky			p_pool->component_sizes = NULL;
201321936Shselasky		}
202321936Shselasky	}
203321936Shselasky
204321936Shselasky	p_pool->state = CL_UNINITIALIZED;
205321936Shselasky}
206321936Shselasky
207321936Shselaskycl_status_t cl_qcpool_grow(IN cl_qcpool_t * const p_pool, IN size_t obj_count)
208321936Shselasky{
209321936Shselasky	cl_status_t status = CL_SUCCESS;
210321936Shselasky	uint8_t *p_objects;
211321936Shselasky	cl_pool_item_t *p_pool_item;
212321936Shselasky	uint32_t i;
213321936Shselasky	size_t obj_size;
214321936Shselasky
215321936Shselasky	CL_ASSERT(p_pool);
216321936Shselasky	CL_ASSERT(p_pool->state == CL_INITIALIZED);
217321936Shselasky	CL_ASSERT(obj_count);
218321936Shselasky
219321936Shselasky	/* Validate that growth is possible. */
220321936Shselasky	if (p_pool->num_objects == p_pool->max_objects)
221321936Shselasky		return (CL_INSUFFICIENT_MEMORY);
222321936Shselasky
223321936Shselasky	/* Cap the growth to the desired maximum. */
224321936Shselasky	if (obj_count > (p_pool->max_objects - p_pool->num_objects))
225321936Shselasky		obj_count = p_pool->max_objects - p_pool->num_objects;
226321936Shselasky
227321936Shselasky	/* Calculate the size of an object. */
228321936Shselasky	obj_size = 0;
229321936Shselasky	for (i = 0; i < p_pool->num_components; i++)
230321936Shselasky		obj_size += p_pool->component_sizes[i];
231321936Shselasky
232321936Shselasky	/* Allocate the buffer for the new objects. */
233321936Shselasky	p_objects = (uint8_t *)
234321936Shselasky	    malloc(sizeof(cl_list_item_t) + (obj_size * obj_count));
235321936Shselasky
236321936Shselasky	/* Make sure the allocation succeeded. */
237321936Shselasky	if (!p_objects)
238321936Shselasky		return (CL_INSUFFICIENT_MEMORY);
239321936Shselasky	else
240321936Shselasky		memset(p_objects, 0,
241321936Shselasky		       sizeof(cl_list_item_t) + (obj_size * obj_count));
242321936Shselasky
243321936Shselasky	/* Insert the allocation in our list. */
244321936Shselasky	cl_qlist_insert_tail(&p_pool->alloc_list, (cl_list_item_t *) p_objects);
245321936Shselasky	p_objects += sizeof(cl_list_item_t);
246321936Shselasky
247321936Shselasky	/* initialize the new elements and add them to the free list */
248321936Shselasky	while (obj_count--) {
249321936Shselasky		/* Setup the array of components for the current object. */
250321936Shselasky		p_pool->p_components[0] = p_objects;
251321936Shselasky		for (i = 1; i < p_pool->num_components; i++) {
252321936Shselasky			/* Calculate the pointer to the next component. */
253321936Shselasky			p_pool->p_components[i] =
254321936Shselasky			    (uint8_t *) p_pool->p_components[i - 1] +
255321936Shselasky			    p_pool->component_sizes[i - 1];
256321936Shselasky		}
257321936Shselasky
258321936Shselasky		/*
259321936Shselasky		 * call the user's initializer
260321936Shselasky		 * this can fail!
261321936Shselasky		 */
262321936Shselasky		if (p_pool->pfn_init) {
263321936Shselasky			p_pool_item = NULL;
264321936Shselasky			status = p_pool->pfn_init(p_pool->p_components,
265321936Shselasky						  p_pool->num_components,
266321936Shselasky						  (void *)p_pool->context,
267321936Shselasky						  &p_pool_item);
268321936Shselasky			if (status != CL_SUCCESS) {
269321936Shselasky				/*
270321936Shselasky				 * User initialization failed
271321936Shselasky				 * we may have only grown the pool by some partial amount
272321936Shselasky				 * Invoke the destructor for the object that failed
273321936Shselasky				 * initialization.
274321936Shselasky				 */
275321936Shselasky				if (p_pool->pfn_dtor)
276321936Shselasky					p_pool->pfn_dtor(p_pool_item,
277321936Shselasky							 (void *)p_pool->
278321936Shselasky							 context);
279321936Shselasky
280321936Shselasky				/* Return the user's status. */
281321936Shselasky				return (status);
282321936Shselasky			}
283321936Shselasky			CL_ASSERT(p_pool_item);
284321936Shselasky		} else {
285321936Shselasky			/*
286321936Shselasky			 * If no initializer is provided, assume that the pool item
287321936Shselasky			 * is stored at the beginning of the first component.
288321936Shselasky			 */
289321936Shselasky			p_pool_item =
290321936Shselasky			    (cl_pool_item_t *) p_pool->p_components[0];
291321936Shselasky		}
292321936Shselasky
293321936Shselasky#ifdef _DEBUG_
294321936Shselasky		/*
295321936Shselasky		 * Set the pool item's pool pointer to this pool so that we can
296321936Shselasky		 * check that items get returned to the correct pool.
297321936Shselasky		 */
298321936Shselasky		p_pool_item->p_pool = p_pool;
299321936Shselasky#endif
300321936Shselasky
301321936Shselasky		/* Insert the new item in the free list, traping for failure. */
302321936Shselasky		cl_qlist_insert_head(&p_pool->free_list,
303321936Shselasky				     &p_pool_item->list_item);
304321936Shselasky
305321936Shselasky		p_pool->num_objects++;
306321936Shselasky
307321936Shselasky		/* move the pointer to the next item */
308321936Shselasky		p_objects += obj_size;
309321936Shselasky	}
310321936Shselasky
311321936Shselasky	return (status);
312321936Shselasky}
313321936Shselasky
314321936Shselaskycl_pool_item_t *cl_qcpool_get(IN cl_qcpool_t * const p_pool)
315321936Shselasky{
316321936Shselasky	cl_list_item_t *p_list_item;
317321936Shselasky
318321936Shselasky	CL_ASSERT(p_pool);
319321936Shselasky	CL_ASSERT(p_pool->state == CL_INITIALIZED);
320321936Shselasky
321321936Shselasky	if (cl_is_qlist_empty(&p_pool->free_list)) {
322321936Shselasky		/*
323321936Shselasky		 * No object is available.
324321936Shselasky		 * Return NULL if the user does not want automatic growth.
325321936Shselasky		 */
326321936Shselasky		if (!p_pool->grow_size)
327321936Shselasky			return (NULL);
328321936Shselasky
329321936Shselasky		/* We ran out of elements.  Get more */
330321936Shselasky		cl_qcpool_grow(p_pool, p_pool->grow_size);
331321936Shselasky		/*
332321936Shselasky		 * We may not have gotten everything we wanted but we might have
333321936Shselasky		 * gotten something.
334321936Shselasky		 */
335321936Shselasky		if (cl_is_qlist_empty(&p_pool->free_list))
336321936Shselasky			return (NULL);
337321936Shselasky	}
338321936Shselasky
339321936Shselasky	p_list_item = cl_qlist_remove_head(&p_pool->free_list);
340321936Shselasky	/* OK, at this point we have an object */
341321936Shselasky	CL_ASSERT(p_list_item != cl_qlist_end(&p_pool->free_list));
342321936Shselasky	return ((cl_pool_item_t *) p_list_item);
343321936Shselasky}
344321936Shselasky
345321936Shselaskycl_pool_item_t *cl_qcpool_get_tail(IN cl_qcpool_t * const p_pool)
346321936Shselasky{
347321936Shselasky	cl_list_item_t *p_list_item;
348321936Shselasky
349321936Shselasky	CL_ASSERT(p_pool);
350321936Shselasky	CL_ASSERT(p_pool->state == CL_INITIALIZED);
351321936Shselasky
352321936Shselasky	if (cl_is_qlist_empty(&p_pool->free_list)) {
353321936Shselasky		/*
354321936Shselasky		 * No object is available.
355321936Shselasky		 * Return NULL if the user does not want automatic growth.
356321936Shselasky		 */
357321936Shselasky		if (!p_pool->grow_size)
358321936Shselasky			return (NULL);
359321936Shselasky
360321936Shselasky		/* We ran out of elements.  Get more */
361321936Shselasky		cl_qcpool_grow(p_pool, p_pool->grow_size);
362321936Shselasky		/*
363321936Shselasky		 * We may not have gotten everything we wanted but we might have
364321936Shselasky		 * gotten something.
365321936Shselasky		 */
366321936Shselasky		if (cl_is_qlist_empty(&p_pool->free_list))
367321936Shselasky			return (NULL);
368321936Shselasky	}
369321936Shselasky
370321936Shselasky	p_list_item = cl_qlist_remove_tail(&p_pool->free_list);
371321936Shselasky	/* OK, at this point we have an object */
372321936Shselasky	CL_ASSERT(p_list_item != cl_qlist_end(&p_pool->free_list));
373321936Shselasky	return ((cl_pool_item_t *) p_list_item);
374321936Shselasky}
375321936Shselasky
376321936Shselasky/*
377321936Shselasky * IMPLEMENTATION OF QUICK GROW POOL
378321936Shselasky */
379321936Shselasky
380321936Shselasky/*
381321936Shselasky * Callback to translate quick composite to quick grow pool
382321936Shselasky * initializer callback.
383321936Shselasky */
384321936Shselaskystatic cl_status_t __cl_qpool_init_cb(IN void **const p_comp_array,
385321936Shselasky				      IN const uint32_t num_components,
386321936Shselasky				      IN void *const context,
387321936Shselasky				      OUT cl_pool_item_t ** const pp_pool_item)
388321936Shselasky{
389321936Shselasky	cl_qpool_t *p_pool = (cl_qpool_t *) context;
390321936Shselasky
391321936Shselasky	CL_ASSERT(p_pool);
392321936Shselasky	CL_ASSERT(p_pool->pfn_init);
393321936Shselasky	CL_ASSERT(num_components == 1);
394321936Shselasky
395321936Shselasky	UNUSED_PARAM(num_components);
396321936Shselasky
397321936Shselasky	return (p_pool->pfn_init(p_comp_array[0], (void *)p_pool->context,
398321936Shselasky				 pp_pool_item));
399321936Shselasky}
400321936Shselasky
401321936Shselasky/*
402321936Shselasky * Callback to translate quick composite to quick grow pool
403321936Shselasky * destructor callback.
404321936Shselasky */
405321936Shselaskystatic void __cl_qpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
406321936Shselasky			       IN void *const context)
407321936Shselasky{
408321936Shselasky	cl_qpool_t *p_pool = (cl_qpool_t *) context;
409321936Shselasky
410321936Shselasky	CL_ASSERT(p_pool);
411321936Shselasky	CL_ASSERT(p_pool->pfn_dtor);
412321936Shselasky
413321936Shselasky	p_pool->pfn_dtor(p_pool_item, (void *)p_pool->context);
414321936Shselasky}
415321936Shselasky
416321936Shselaskyvoid cl_qpool_construct(IN cl_qpool_t * const p_pool)
417321936Shselasky{
418321936Shselasky	memset(p_pool, 0, sizeof(cl_qpool_t));
419321936Shselasky
420321936Shselasky	cl_qcpool_construct(&p_pool->qcpool);
421321936Shselasky}
422321936Shselasky
423321936Shselaskycl_status_t cl_qpool_init(IN cl_qpool_t * const p_pool,
424321936Shselasky			  IN const size_t min_size, IN const size_t max_size,
425321936Shselasky			  IN const size_t grow_size,
426321936Shselasky			  IN const size_t object_size,
427321936Shselasky			  IN cl_pfn_qpool_init_t pfn_initializer OPTIONAL,
428321936Shselasky			  IN cl_pfn_qpool_dtor_t pfn_destructor OPTIONAL,
429321936Shselasky			  IN const void *const context)
430321936Shselasky{
431321936Shselasky	cl_status_t status;
432321936Shselasky
433321936Shselasky	CL_ASSERT(p_pool);
434321936Shselasky
435321936Shselasky	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
436321936Shselasky	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
437321936Shselasky	p_pool->context = context;
438321936Shselasky
439321936Shselasky	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
440321936Shselasky				&object_size, 1,
441321936Shselasky				pfn_initializer ? __cl_qpool_init_cb : NULL,
442321936Shselasky				pfn_destructor ? __cl_qpool_dtor_cb : NULL,
443321936Shselasky				p_pool);
444321936Shselasky
445321936Shselasky	return (status);
446321936Shselasky}
447321936Shselasky
448321936Shselasky/*
449321936Shselasky * IMPLEMENTATION OF COMPOSITE POOL
450321936Shselasky */
451321936Shselasky
452321936Shselasky/*
453321936Shselasky * Callback to translate quick composite to compsite pool
454321936Shselasky * initializer callback.
455321936Shselasky */
456321936Shselaskystatic cl_status_t __cl_cpool_init_cb(IN void **const p_comp_array,
457321936Shselasky				      IN const uint32_t num_components,
458321936Shselasky				      IN void *const context,
459321936Shselasky				      OUT cl_pool_item_t ** const pp_pool_item)
460321936Shselasky{
461321936Shselasky	cl_cpool_t *p_pool = (cl_cpool_t *) context;
462321936Shselasky	cl_pool_obj_t *p_pool_obj;
463321936Shselasky	cl_status_t status = CL_SUCCESS;
464321936Shselasky
465321936Shselasky	CL_ASSERT(p_pool);
466321936Shselasky
467321936Shselasky	/*
468321936Shselasky	 * Set our pointer to the list item, which is stored at the beginning of
469321936Shselasky	 * the first component.
470321936Shselasky	 */
471321936Shselasky	p_pool_obj = (cl_pool_obj_t *) p_comp_array[0];
472321936Shselasky	/* Set the pool item pointer for the caller. */
473321936Shselasky	*pp_pool_item = &p_pool_obj->pool_item;
474321936Shselasky
475321936Shselasky	/* Calculate the pointer to the user's first component. */
476321936Shselasky	p_comp_array[0] = ((uint8_t *) p_comp_array[0]) + sizeof(cl_pool_obj_t);
477321936Shselasky
478321936Shselasky	/*
479321936Shselasky	 * Set the object pointer in the pool object to point to the first of the
480321936Shselasky	 * user's components.
481321936Shselasky	 */
482321936Shselasky	p_pool_obj->p_object = p_comp_array[0];
483321936Shselasky
484321936Shselasky	/* Invoke the user's constructor callback. */
485321936Shselasky	if (p_pool->pfn_init) {
486321936Shselasky		status = p_pool->pfn_init(p_comp_array, num_components,
487321936Shselasky					  (void *)p_pool->context);
488321936Shselasky	}
489321936Shselasky
490321936Shselasky	return (status);
491321936Shselasky}
492321936Shselasky
493321936Shselasky/*
494321936Shselasky * Callback to translate quick composite to composite pool
495321936Shselasky * destructor callback.
496321936Shselasky */
497321936Shselaskystatic void __cl_cpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
498321936Shselasky			       IN void *const context)
499321936Shselasky{
500321936Shselasky	cl_cpool_t *p_pool = (cl_cpool_t *) context;
501321936Shselasky
502321936Shselasky	CL_ASSERT(p_pool);
503321936Shselasky	CL_ASSERT(p_pool->pfn_dtor);
504321936Shselasky	CL_ASSERT(((cl_pool_obj_t *) p_pool_item)->p_object);
505321936Shselasky
506321936Shselasky	/* Invoke the user's destructor callback. */
507321936Shselasky	p_pool->pfn_dtor((void *)((cl_pool_obj_t *) p_pool_item)->p_object,
508321936Shselasky			 (void *)p_pool->context);
509321936Shselasky}
510321936Shselasky
511321936Shselaskyvoid cl_cpool_construct(IN cl_cpool_t * const p_pool)
512321936Shselasky{
513321936Shselasky	CL_ASSERT(p_pool);
514321936Shselasky
515321936Shselasky	memset(p_pool, 0, sizeof(cl_cpool_t));
516321936Shselasky
517321936Shselasky	cl_qcpool_construct(&p_pool->qcpool);
518321936Shselasky}
519321936Shselasky
520321936Shselaskycl_status_t cl_cpool_init(IN cl_cpool_t * const p_pool,
521321936Shselasky			  IN const size_t min_size, IN const size_t max_size,
522321936Shselasky			  IN const size_t grow_size,
523321936Shselasky			  IN size_t * const component_sizes,
524321936Shselasky			  IN const uint32_t num_components,
525321936Shselasky			  IN cl_pfn_cpool_init_t pfn_initializer OPTIONAL,
526321936Shselasky			  IN cl_pfn_cpool_dtor_t pfn_destructor OPTIONAL,
527321936Shselasky			  IN const void *const context)
528321936Shselasky{
529321936Shselasky	cl_status_t status;
530321936Shselasky
531321936Shselasky	CL_ASSERT(p_pool);
532321936Shselasky	CL_ASSERT(num_components);
533321936Shselasky	CL_ASSERT(component_sizes);
534321936Shselasky
535321936Shselasky	/* Add the size of the pool object to the first component. */
536321936Shselasky	component_sizes[0] += sizeof(cl_pool_obj_t);
537321936Shselasky
538321936Shselasky	/* Store callback function pointers. */
539321936Shselasky	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
540321936Shselasky	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
541321936Shselasky	p_pool->context = context;
542321936Shselasky
543321936Shselasky	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
544321936Shselasky				component_sizes, num_components,
545321936Shselasky				__cl_cpool_init_cb,
546321936Shselasky				pfn_destructor ? __cl_cpool_dtor_cb : NULL,
547321936Shselasky				p_pool);
548321936Shselasky
549321936Shselasky	/* Restore the original value of the first component. */
550321936Shselasky	component_sizes[0] -= sizeof(cl_pool_obj_t);
551321936Shselasky
552321936Shselasky	return (status);
553321936Shselasky}
554321936Shselasky
555321936Shselasky/*
556321936Shselasky * IMPLEMENTATION OF GROW POOL
557321936Shselasky */
558321936Shselasky
559321936Shselasky/*
560321936Shselasky * Callback to translate quick composite to grow pool constructor callback.
561321936Shselasky */
562321936Shselaskystatic cl_status_t __cl_pool_init_cb(IN void **const pp_obj,
563321936Shselasky				     IN const uint32_t count,
564321936Shselasky				     IN void *const context,
565321936Shselasky				     OUT cl_pool_item_t ** const pp_pool_item)
566321936Shselasky{
567321936Shselasky	cl_pool_t *p_pool = (cl_pool_t *) context;
568321936Shselasky	cl_pool_obj_t *p_pool_obj;
569321936Shselasky	cl_status_t status = CL_SUCCESS;
570321936Shselasky
571321936Shselasky	CL_ASSERT(p_pool);
572321936Shselasky	CL_ASSERT(pp_obj);
573321936Shselasky	CL_ASSERT(count == 1);
574321936Shselasky
575321936Shselasky	UNUSED_PARAM(count);
576321936Shselasky
577321936Shselasky	/*
578321936Shselasky	 * Set our pointer to the list item, which is stored at the beginning of
579321936Shselasky	 * the first component.
580321936Shselasky	 */
581321936Shselasky	p_pool_obj = (cl_pool_obj_t *) * pp_obj;
582321936Shselasky	*pp_pool_item = &p_pool_obj->pool_item;
583321936Shselasky
584321936Shselasky	/* Calculate the pointer to the user's first component. */
585321936Shselasky	*pp_obj = ((uint8_t *) * pp_obj) + sizeof(cl_pool_obj_t);
586321936Shselasky
587321936Shselasky	/*
588321936Shselasky	 * Set the object pointer in the pool item to point to the first of the
589321936Shselasky	 * user's components.
590321936Shselasky	 */
591321936Shselasky	p_pool_obj->p_object = *pp_obj;
592321936Shselasky
593321936Shselasky	/* Invoke the user's constructor callback. */
594321936Shselasky	if (p_pool->pfn_init)
595321936Shselasky		status = p_pool->pfn_init(*pp_obj, (void *)p_pool->context);
596321936Shselasky
597321936Shselasky	return (status);
598321936Shselasky}
599321936Shselasky
600321936Shselasky/*
601321936Shselasky * Callback to translate quick composite to grow pool destructor callback.
602321936Shselasky */
603321936Shselaskystatic void __cl_pool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
604321936Shselasky			      IN void *const context)
605321936Shselasky{
606321936Shselasky	cl_pool_t *p_pool = (cl_pool_t *) context;
607321936Shselasky
608321936Shselasky	CL_ASSERT(p_pool);
609321936Shselasky	CL_ASSERT(p_pool->pfn_dtor);
610321936Shselasky	CL_ASSERT(((cl_pool_obj_t *) p_pool_item)->p_object);
611321936Shselasky
612321936Shselasky	/* Invoke the user's destructor callback. */
613321936Shselasky	p_pool->pfn_dtor((void *)((cl_pool_obj_t *) p_pool_item)->p_object,
614321936Shselasky			 (void *)p_pool->context);
615321936Shselasky}
616321936Shselasky
617321936Shselaskyvoid cl_pool_construct(IN cl_pool_t * const p_pool)
618321936Shselasky{
619321936Shselasky	CL_ASSERT(p_pool);
620321936Shselasky
621321936Shselasky	memset(p_pool, 0, sizeof(cl_pool_t));
622321936Shselasky
623321936Shselasky	cl_qcpool_construct(&p_pool->qcpool);
624321936Shselasky}
625321936Shselasky
626321936Shselaskycl_status_t cl_pool_init(IN cl_pool_t * const p_pool, IN const size_t min_size,
627321936Shselasky			 IN const size_t max_size, IN const size_t grow_size,
628321936Shselasky			 IN const size_t object_size,
629321936Shselasky			 IN cl_pfn_pool_init_t pfn_initializer OPTIONAL,
630321936Shselasky			 IN cl_pfn_pool_dtor_t pfn_destructor OPTIONAL,
631321936Shselasky			 IN const void *const context)
632321936Shselasky{
633321936Shselasky	cl_status_t status;
634321936Shselasky	size_t total_size;
635321936Shselasky
636321936Shselasky	CL_ASSERT(p_pool);
637321936Shselasky
638321936Shselasky	/* Add the size of the list item to the first component. */
639321936Shselasky	total_size = object_size + sizeof(cl_pool_obj_t);
640321936Shselasky
641321936Shselasky	/* Store callback function pointers. */
642321936Shselasky	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
643321936Shselasky	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
644321936Shselasky	p_pool->context = context;
645321936Shselasky
646321936Shselasky	/*
647321936Shselasky	 * We need an initializer in all cases for quick composite pool, since
648321936Shselasky	 * the user pointer must be manipulated to hide the prefixed cl_pool_obj_t.
649321936Shselasky	 */
650321936Shselasky	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
651321936Shselasky				&total_size, 1, __cl_pool_init_cb,
652321936Shselasky				pfn_destructor ? __cl_pool_dtor_cb : NULL,
653321936Shselasky				p_pool);
654321936Shselasky
655321936Shselasky	return (status);
656321936Shselasky}
657