cl_pool.c revision 219820
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