]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/complib/cl_pool.c
Merge compiler-rt trunk r321414 to contrib/compiler-rt.
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / complib / cl_pool.c
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 }