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