2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
3 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
\r
5 * This software is available to you under the OpenIB.org BSD license
\r
8 * Redistribution and use in source and binary forms, with or
\r
9 * without modification, are permitted provided that the following
\r
10 * conditions are met:
\r
12 * - Redistributions of source code must retain the above
\r
13 * copyright notice, this list of conditions and the following
\r
16 * - Redistributions in binary form must reproduce the above
\r
17 * copyright notice, this list of conditions and the following
\r
18 * disclaimer in the documentation and/or other materials
\r
19 * provided with the distribution.
\r
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
25 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
26 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
36 * Implementation of the grow pools. The grow pools manage a pool of objects.
\r
37 * The pools can grow to meet demand, limited only by system memory.
\r
44 #include <complib/cl_qcomppool.h>
\r
45 #include <complib/cl_comppool.h>
\r
46 #include <complib/cl_qpool.h>
\r
47 #include <complib/cl_pool.h>
\r
48 #include <complib/cl_memory.h>
\r
49 #include <complib/cl_math.h>
\r
53 * IMPLEMENTATION OF QUICK COMPOSITE POOL
\r
57 cl_qcpool_construct(
\r
58 IN cl_qcpool_t* const p_pool )
\r
60 CL_ASSERT( p_pool );
\r
62 cl_memclr( p_pool, sizeof(cl_qcpool_t) );
\r
64 p_pool->state = CL_UNINITIALIZED;
\r
70 IN cl_qcpool_t* const p_pool,
\r
71 IN const size_t min_size,
\r
72 IN const size_t max_size,
\r
73 IN const size_t grow_size,
\r
74 IN const size_t* const component_sizes,
\r
75 IN const uint32_t num_components,
\r
76 IN cl_pfn_qcpool_init_t pfn_initializer OPTIONAL,
\r
77 IN cl_pfn_qcpool_dtor_t pfn_destructor OPTIONAL,
\r
78 IN const void* const context )
\r
83 CL_ASSERT( p_pool );
\r
84 /* Must have a minimum of 1 component. */
\r
85 CL_ASSERT( num_components );
\r
86 /* A component size array is required. */
\r
87 CL_ASSERT( component_sizes );
\r
89 * If no initializer is provided, the first component must be large
\r
90 * enough to hold a pool item.
\r
92 CL_ASSERT( pfn_initializer ||
\r
93 (component_sizes[0] >= sizeof(cl_pool_item_t)) );
\r
95 cl_qcpool_construct( p_pool );
\r
97 if( num_components > 1 && !pfn_initializer )
\r
98 return( CL_INVALID_SETTING );
\r
100 if( max_size && max_size < min_size )
\r
101 return( CL_INVALID_SETTING );
\r
104 * Allocate the array of component sizes and component pointers all
\r
105 * in one allocation.
\r
107 p_pool->component_sizes = (size_t*)cl_zalloc(
\r
108 (sizeof(size_t) + sizeof(void*)) * num_components );
\r
110 if( !p_pool->component_sizes )
\r
111 return( CL_INSUFFICIENT_MEMORY );
\r
113 /* Calculate the pointer to the array of pointers, used for callbacks. */
\r
114 p_pool->p_components =
\r
115 (void**)(p_pool->component_sizes + num_components);
\r
117 /* Copy the user's sizes into our array for future use. */
\r
118 cl_memcpy( p_pool->component_sizes, component_sizes,
\r
119 sizeof(uint32_t) * num_components );
\r
121 /* Store the number of components per object. */
\r
122 p_pool->num_components = num_components;
\r
124 /* Round up and store the size of the components. */
\r
125 for( i = 0; i < num_components; i++ )
\r
128 * We roundup each component size so that all components
\r
129 * are aligned on a natural boundary.
\r
131 p_pool->component_sizes[i] =
\r
132 ROUNDUP( p_pool->component_sizes[i], sizeof(uintn_t) );
\r
135 p_pool->max_objects = max_size? max_size : ~(size_t)0;
\r
136 p_pool->grow_size = grow_size;
\r
138 /* Store callback function pointers. */
\r
139 p_pool->pfn_init = pfn_initializer; /* may be NULL */
\r
140 p_pool->pfn_dtor = pfn_destructor; /* may be NULL */
\r
141 p_pool->context = context;
\r
143 cl_qlist_init( &p_pool->alloc_list );
\r
145 cl_qlist_init( &p_pool->free_list );
\r
148 * We are now initialized. We change the initialized flag before
\r
149 * growing since the grow function asserts that we are initialized.
\r
151 p_pool->state = CL_INITIALIZED;
\r
153 /* Allocate the minimum number of objects as requested. */
\r
155 return( CL_SUCCESS );
\r
157 status = cl_qcpool_grow( p_pool, min_size );
\r
158 /* Trap for error and cleanup if necessary. */
\r
159 if( status != CL_SUCCESS )
\r
160 cl_qcpool_destroy( p_pool );
\r
168 IN cl_qcpool_t* const p_pool )
\r
170 /* CL_ASSERT that a non-NULL pointer was provided. */
\r
171 CL_ASSERT( p_pool );
\r
172 /* CL_ASSERT that we are in a valid state (not uninitialized memory). */
\r
173 CL_ASSERT( cl_is_state_valid( p_pool->state ) );
\r
175 if( p_pool->state == CL_INITIALIZED )
\r
178 * Assert if the user hasn't put everything back in the pool
\r
179 * before destroying it
\r
180 * if they haven't, then most likely they are still using memory
\r
181 * that will be freed, and the destructor will not be called!
\r
184 // Assert can happen in shutdown. Need to find a way to distinguish between the cases
\r
185 // CL_ASSERT( cl_qcpool_count( p_pool ) == p_pool->num_objects );
\r
187 /* call the user's destructor for each object in the pool */
\r
188 if( p_pool->pfn_dtor )
\r
190 while( !cl_is_qlist_empty( &p_pool->free_list ) )
\r
192 p_pool->pfn_dtor( (cl_pool_item_t*)
\r
193 cl_qlist_remove_head( &p_pool->free_list ),
\r
194 (void*)p_pool->context );
\r
199 cl_qlist_remove_all( &p_pool->free_list );
\r
202 /* Free all alocated memory blocks. */
\r
203 while( !cl_is_qlist_empty( &p_pool->alloc_list ) )
\r
204 cl_free( cl_qlist_remove_head( &p_pool->alloc_list ) );
\r
206 if( p_pool->component_sizes )
\r
208 cl_free( p_pool->component_sizes );
\r
209 p_pool->component_sizes = NULL;
\r
213 p_pool->state = CL_UNINITIALIZED;
\r
219 IN cl_qcpool_t* const p_pool,
\r
220 IN size_t obj_count )
\r
222 cl_status_t status = CL_SUCCESS;
\r
223 uint8_t *p_objects;
\r
224 cl_pool_item_t *p_pool_item;
\r
228 CL_ASSERT( p_pool );
\r
229 CL_ASSERT( p_pool->state == CL_INITIALIZED );
\r
230 CL_ASSERT( obj_count );
\r
232 /* Validate that growth is possible. */
\r
233 if( p_pool->num_objects == p_pool->max_objects )
\r
234 return( CL_INSUFFICIENT_MEMORY );
\r
236 /* Cap the growth to the desired maximum. */
\r
237 if( obj_count > (p_pool->max_objects - p_pool->num_objects) )
\r
238 obj_count = p_pool->max_objects - p_pool->num_objects;
\r
240 /* Calculate the size of an object. */
\r
242 for( i = 0; i < p_pool->num_components; i++ )
\r
243 obj_size += p_pool->component_sizes[i];
\r
245 /* Allocate the buffer for the new objects. */
\r
246 p_objects = (uint8_t*)
\r
247 cl_zalloc( sizeof(cl_list_item_t) + (obj_size * obj_count) );
\r
249 /* Make sure the allocation succeeded. */
\r
251 return( CL_INSUFFICIENT_MEMORY );
\r
253 /* Insert the allocation in our list. */
\r
254 cl_qlist_insert_tail( &p_pool->alloc_list, (cl_list_item_t*)p_objects );
\r
255 p_objects += sizeof(cl_list_item_t);
\r
257 /* initialize the new elements and add them to the free list */
\r
258 while( obj_count-- )
\r
260 /* Setup the array of components for the current object. */
\r
261 p_pool->p_components[0] = p_objects;
\r
262 for( i = 1; i < p_pool->num_components; i++ )
\r
264 /* Calculate the pointer to the next component. */
\r
265 p_pool->p_components[i] = (uint8_t*)p_pool->p_components[i-1] +
\r
266 p_pool->component_sizes[i-1];
\r
270 * call the user's initializer
\r
273 if( p_pool->pfn_init )
\r
275 p_pool_item = NULL;
\r
276 status = p_pool->pfn_init( p_pool->p_components,
\r
277 p_pool->num_components, (void*)p_pool->context, &p_pool_item );
\r
278 if( status != CL_SUCCESS )
\r
281 * User initialization failed
\r
282 * we may have only grown the pool by some partial amount
\r
283 * Invoke the destructor for the object that failed
\r
286 if( p_pool->pfn_dtor )
\r
287 p_pool->pfn_dtor( p_pool_item, (void*)p_pool->context );
\r
289 /* Return the user's status. */
\r
292 CL_ASSERT( p_pool_item );
\r
297 * If no initializer is provided, assume that the pool item
\r
298 * is stored at the beginning of the first component.
\r
300 p_pool_item = (cl_pool_item_t*)p_pool->p_components[0];
\r
305 * Set the pool item's pool pointer to this pool so that we can
\r
306 * check that items get returned to the correct pool.
\r
308 p_pool_item->p_pool = p_pool;
\r
311 /* Insert the new item in the free list, traping for failure. */
\r
312 cl_qlist_insert_head( &p_pool->free_list, &p_pool_item->list_item );
\r
314 p_pool->num_objects++;
\r
316 /* move the pointer to the next item */
\r
317 p_objects += obj_size;
\r
326 IN cl_qcpool_t* const p_pool )
\r
328 cl_list_item_t *p_list_item;
\r
330 CL_ASSERT( p_pool );
\r
331 CL_ASSERT( p_pool->state == CL_INITIALIZED );
\r
333 if( cl_is_qlist_empty( &p_pool->free_list ) )
\r
336 * No object is available.
\r
337 * Return NULL if the user does not want automatic growth.
\r
339 if( !p_pool->grow_size )
\r
342 /* We ran out of elements. Get more */
\r
343 cl_qcpool_grow( p_pool, p_pool->grow_size );
\r
345 * We may not have gotten everything we wanted but we might have
\r
346 * gotten something.
\r
348 if( cl_is_qlist_empty( &p_pool->free_list ) )
\r
352 p_list_item = cl_qlist_remove_head( &p_pool->free_list );
\r
353 /* OK, at this point we have an object */
\r
354 CL_ASSERT( p_list_item != cl_qlist_end( &p_pool->free_list ) );
\r
355 return( (cl_pool_item_t*)p_list_item );
\r
360 cl_qcpool_get_tail(
\r
361 IN cl_qcpool_t* const p_pool )
\r
363 cl_list_item_t *p_list_item;
\r
365 CL_ASSERT( p_pool );
\r
366 CL_ASSERT( p_pool->state == CL_INITIALIZED );
\r
368 if( cl_is_qlist_empty( &p_pool->free_list ) )
\r
371 * No object is available.
\r
372 * Return NULL if the user does not want automatic growth.
\r
374 if( !p_pool->grow_size )
\r
377 /* We ran out of elements. Get more */
\r
378 cl_qcpool_grow( p_pool, p_pool->grow_size );
\r
380 * We may not have gotten everything we wanted but we might have
\r
381 * gotten something.
\r
383 if( cl_is_qlist_empty( &p_pool->free_list ) )
\r
387 p_list_item = cl_qlist_remove_tail( &p_pool->free_list );
\r
388 /* OK, at this point we have an object */
\r
389 CL_ASSERT( p_list_item != cl_qlist_end( &p_pool->free_list ) );
\r
390 return( (cl_pool_item_t*)p_list_item );
\r
395 * IMPLEMENTATION OF QUICK GROW POOL
\r
399 * Callback to translate quick composite to quick grow pool
\r
400 * initializer callback.
\r
403 __cl_qpool_init_cb(
\r
404 IN void** const p_comp_array,
\r
405 IN const uint32_t num_components,
\r
406 IN void* const context,
\r
407 OUT cl_pool_item_t** const pp_pool_item )
\r
409 cl_qpool_t *p_pool = (cl_qpool_t*)context;
\r
411 CL_ASSERT( p_pool );
\r
412 CL_ASSERT( p_pool->pfn_init );
\r
413 CL_ASSERT( num_components == 1 );
\r
415 UNUSED_PARAM( num_components );
\r
417 return( p_pool->pfn_init( p_comp_array[0], (void*)p_pool->context,
\r
423 * Callback to translate quick composite to quick grow pool
\r
424 * destructor callback.
\r
427 __cl_qpool_dtor_cb(
\r
428 IN const cl_pool_item_t* const p_pool_item,
\r
429 IN void* const context )
\r
431 cl_qpool_t *p_pool = (cl_qpool_t*)context;
\r
433 CL_ASSERT( p_pool );
\r
434 CL_ASSERT( p_pool->pfn_dtor );
\r
436 p_pool->pfn_dtor( p_pool_item, (void*)p_pool->context );
\r
441 cl_qpool_construct(
\r
442 IN cl_qpool_t* const p_pool )
\r
444 cl_memclr( p_pool, sizeof(cl_qpool_t) );
\r
446 cl_qcpool_construct( &p_pool->qcpool );
\r
452 IN cl_qpool_t* const p_pool,
\r
453 IN const size_t min_size,
\r
454 IN const size_t max_size,
\r
455 IN const size_t grow_size,
\r
456 IN const size_t object_size,
\r
457 IN cl_pfn_qpool_init_t pfn_initializer OPTIONAL,
\r
458 IN cl_pfn_qpool_dtor_t pfn_destructor OPTIONAL,
\r
459 IN const void* const context )
\r
461 cl_status_t status;
\r
462 CL_ASSERT( p_pool );
\r
464 p_pool->pfn_init = pfn_initializer; /* may be NULL */
\r
465 p_pool->pfn_dtor = pfn_destructor; /* may be NULL */
\r
466 p_pool->context = context;
\r
468 status = cl_qcpool_init( &p_pool->qcpool, min_size, max_size, grow_size,
\r
469 &object_size, 1, pfn_initializer ? __cl_qpool_init_cb : NULL,
\r
470 pfn_destructor ? __cl_qpool_dtor_cb : NULL, p_pool );
\r
477 * IMPLEMENTATION OF COMPOSITE POOL
\r
482 * Callback to translate quick composite to compsite pool
\r
483 * initializer callback.
\r
486 __cl_cpool_init_cb(
\r
487 IN void** const p_comp_array,
\r
488 IN const uint32_t num_components,
\r
489 IN void* const context,
\r
490 OUT cl_pool_item_t** const pp_pool_item )
\r
492 cl_cpool_t *p_pool = (cl_cpool_t*)context;
\r
493 cl_pool_obj_t *p_pool_obj;
\r
494 cl_status_t status = CL_SUCCESS;
\r
496 CL_ASSERT( p_pool );
\r
499 * Set our pointer to the list item, which is stored at the beginning of
\r
500 * the first component.
\r
502 p_pool_obj = (cl_pool_obj_t*)p_comp_array[0];
\r
503 /* Set the pool item pointer for the caller. */
\r
504 *pp_pool_item = (cl_pool_item_t*)p_pool_obj;
\r
506 /* Calculate the pointer to the user's first component. */
\r
507 p_comp_array[0] = ((uint8_t*)p_comp_array[0]) + sizeof(cl_pool_obj_t);
\r
510 * Set the object pointer in the pool object to point to the first of the
\r
511 * user's components.
\r
513 p_pool_obj->list_obj.p_object = p_comp_array[0];
\r
515 /* Invoke the user's constructor callback. */
\r
516 if( p_pool->pfn_init )
\r
518 status = p_pool->pfn_init( p_comp_array, num_components,
\r
519 (void*)p_pool->context );
\r
527 * Callback to translate quick composite to composite pool
\r
528 * destructor callback.
\r
531 __cl_cpool_dtor_cb(
\r
532 IN const cl_pool_item_t* const p_pool_item,
\r
533 IN void* const context )
\r
535 cl_cpool_t *p_pool = (cl_cpool_t*)context;
\r
536 CL_ASSERT( p_pool );
\r
537 CL_ASSERT( p_pool->pfn_dtor );
\r
538 CL_ASSERT( ((cl_pool_obj_t*)p_pool_item)->list_obj.p_object );
\r
540 /* Invoke the user's destructor callback. */
\r
541 p_pool->pfn_dtor( (void*)((cl_pool_obj_t*)p_pool_item)->list_obj.p_object,
\r
542 (void*)p_pool->context );
\r
547 cl_cpool_construct(
\r
548 IN cl_cpool_t* const p_pool )
\r
550 CL_ASSERT( p_pool );
\r
552 cl_memclr( p_pool, sizeof(cl_cpool_t) );
\r
554 cl_qcpool_construct( &p_pool->qcpool );
\r
560 IN cl_cpool_t* const p_pool,
\r
561 IN const size_t min_size,
\r
562 IN const size_t max_size,
\r
563 IN const size_t grow_size,
\r
564 IN size_t* const component_sizes,
\r
565 IN const uint32_t num_components,
\r
566 IN cl_pfn_cpool_init_t pfn_initializer OPTIONAL,
\r
567 IN cl_pfn_cpool_dtor_t pfn_destructor OPTIONAL,
\r
568 IN const void* const context )
\r
570 cl_status_t status;
\r
572 CL_ASSERT( p_pool );
\r
573 CL_ASSERT( num_components );
\r
574 CL_ASSERT( component_sizes );
\r
576 /* Add the size of the pool object to the first component. */
\r
577 component_sizes[0] += sizeof(cl_pool_obj_t);
\r
579 /* Store callback function pointers. */
\r
580 p_pool->pfn_init = pfn_initializer; /* may be NULL */
\r
581 p_pool->pfn_dtor = pfn_destructor; /* may be NULL */
\r
582 p_pool->context = context;
\r
584 status = cl_qcpool_init( &p_pool->qcpool, min_size, max_size, grow_size,
\r
585 component_sizes, num_components, __cl_cpool_init_cb,
\r
586 pfn_destructor ? __cl_cpool_dtor_cb : NULL,
\r
589 /* Restore the original value of the first component. */
\r
590 component_sizes[0] -= sizeof(cl_pool_obj_t);
\r
597 * IMPLEMENTATION OF GROW POOL
\r
601 * Callback to translate quick composite to grow pool constructor callback.
\r
605 IN void** const pp_obj,
\r
606 IN const uint32_t count,
\r
607 IN void* const context,
\r
608 OUT cl_pool_item_t** const pp_pool_item )
\r
610 cl_pool_t *p_pool = (cl_pool_t*)context;
\r
611 cl_pool_obj_t *p_pool_obj;
\r
612 cl_status_t status = CL_SUCCESS;
\r
614 CL_ASSERT( p_pool );
\r
615 CL_ASSERT( pp_obj );
\r
616 CL_ASSERT( count == 1 );
\r
618 UNUSED_PARAM( count );
\r
621 * Set our pointer to the list item, which is stored at the beginning of
\r
622 * the first component.
\r
624 p_pool_obj = (cl_pool_obj_t*)*pp_obj;
\r
625 *pp_pool_item = (cl_pool_item_t*)p_pool_obj;
\r
627 /* Calculate the pointer to the user's first component. */
\r
628 *pp_obj = ((uint8_t*)*pp_obj) + sizeof(cl_pool_obj_t);
\r
631 * Set the object pointer in the pool item to point to the first of the
\r
632 * user's components.
\r
634 p_pool_obj->list_obj.p_object = *pp_obj;
\r
636 /* Invoke the user's constructor callback. */
\r
637 if( p_pool->pfn_init )
\r
638 status = p_pool->pfn_init( *pp_obj, (void*)p_pool->context );
\r
645 * Callback to translate quick composite to grow pool destructor callback.
\r
649 IN const cl_pool_item_t* const p_pool_item,
\r
650 IN void* const context )
\r
652 cl_pool_t *p_pool = (cl_pool_t*)context;
\r
653 CL_ASSERT( p_pool );
\r
654 CL_ASSERT( p_pool->pfn_dtor );
\r
655 CL_ASSERT( ((cl_pool_obj_t*)p_pool_item)->list_obj.p_object );
\r
657 /* Invoke the user's destructor callback. */
\r
658 p_pool->pfn_dtor( (void*)((cl_pool_obj_t*)p_pool_item)->list_obj.p_object,
\r
659 (void*)p_pool->context );
\r
665 IN cl_pool_t* const p_pool )
\r
667 CL_ASSERT( p_pool );
\r
669 cl_memclr( p_pool, sizeof(cl_pool_t) );
\r
671 cl_qcpool_construct( &p_pool->qcpool );
\r
677 IN cl_pool_t* const p_pool,
\r
678 IN const size_t min_size,
\r
679 IN const size_t max_size,
\r
680 IN const size_t grow_size,
\r
681 IN const size_t object_size,
\r
682 IN cl_pfn_pool_init_t pfn_initializer OPTIONAL,
\r
683 IN cl_pfn_pool_dtor_t pfn_destructor OPTIONAL,
\r
684 IN const void* const context )
\r
686 cl_status_t status;
\r
689 CL_ASSERT( p_pool );
\r
691 /* Add the size of the list item to the first component. */
\r
692 total_size = object_size + sizeof(cl_pool_obj_t);
\r
694 /* Store callback function pointers. */
\r
695 p_pool->pfn_init = pfn_initializer; /* may be NULL */
\r
696 p_pool->pfn_dtor = pfn_destructor; /* may be NULL */
\r
697 p_pool->context = context;
\r
700 * We need an initializer in all cases for quick composite pool, since
\r
701 * the user pointer must be manipulated to hide the prefixed cl_pool_obj_t.
\r
703 status = cl_qcpool_init( &p_pool->qcpool, min_size, max_size, grow_size,
\r
704 &total_size, 1, __cl_pool_init_cb,
\r
705 pfn_destructor ? __cl_pool_dtor_cb : NULL, p_pool );
\r