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