/* $OpenBSD: rf_freelist.h,v 1.3 2002/12/16 07:01:04 tdeval Exp $ */ /* $NetBSD: rf_freelist.h,v 1.3 1999/02/05 00:06:11 oster Exp $ */ /* * rf_freelist.h */ /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. * * Author: Jim Zelenka * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * rf_freelist.h -- Code to manage counted freelists. * * Keep an arena of fixed-size objects. When a new object is needed, * allocate it as necessary. When an object is freed, either put it * in the arena, or really free it, depending on the maximum arena * size. */ #ifndef _RF__RF_FREELIST_H_ #define _RF__RF_FREELIST_H_ #include "rf_types.h" #include "rf_debugMem.h" #include "rf_general.h" #include "rf_threadstuff.h" #define RF_FREELIST_STATS 0 #if RF_FREELIST_STATS > 0 typedef struct RF_FreeListStats_s { char *file; int line; int allocations; int frees; int max_free; int grows; int outstanding; int max_outstanding; } RF_FreeListStats_t; #define RF_FREELIST_STAT_INIT(_fl_) \ do { \ bzero((char *)&((_fl_)->stats), sizeof(RF_FreeListStats_t)); \ (_fl_)->stats.file = __FILE__; \ (_fl_)->stats.line = __LINE__; \ } while (0) #define RF_FREELIST_STAT_ALLOC(_fl_) \ do { \ (_fl_)->stats.allocations++; \ (_fl_)->stats.outstanding++; \ if ((_fl_)->stats.outstanding > (_fl_)->stats.max_outstanding) \ (_fl_)->stats.max_outstanding = \ (_fl_)->stats.outstanding; \ } while (0) #define RF_FREELIST_STAT_FREE_UPDATE(_fl_) \ do { \ if ((_fl_)->free_cnt > (_fl_)->stats.max_free) \ (_fl_)->stats.max_free = (_fl_)->free_cnt; \ } while (0) #define RF_FREELIST_STAT_FREE(_fl_) \ do { \ (_fl_)->stats.frees++; \ (_fl_)->stats.outstanding--; \ RF_FREELIST_STAT_FREE_UPDATE(_fl_); \ } while (0) #define RF_FREELIST_STAT_GROW(_fl_) \ do { \ (_fl_)->stats.grows++; \ RF_FREELIST_STAT_FREE_UPDATE(_fl_); \ } while (0) #define RF_FREELIST_STAT_REPORT(_fl_) \ do { \ printf("Freelist at %s %d (%s)\n", (_fl_)->stats.file, \ (_fl_)->stats.line, RF_STRING(_fl_)); \ printf(" %d allocations, %d frees\n", \ (_fl_)->stats.allocations, (_fl_)->stats.frees); \ printf(" %d grows\n", (_fl_)->stats.grows); \ printf(" %d outstanding\n", (_fl_)->stats.outstanding); \ printf(" %d free (max)\n", (_fl_)->stats.max_free); \ printf(" %d outstanding (max)\n", \ (_fl_)->stats.max_outstanding); \ } while (0) #else /* RF_FREELIST_STATS > 0 */ #define RF_FREELIST_STAT_INIT(_fl_) #define RF_FREELIST_STAT_ALLOC(_fl_) #define RF_FREELIST_STAT_FREE_UPDATE(_fl_) #define RF_FREELIST_STAT_FREE(_fl_) #define RF_FREELIST_STAT_GROW(_fl_) #define RF_FREELIST_STAT_REPORT(_fl_) #endif /* RF_FREELIST_STATS > 0 */ struct RF_FreeList_s { void *objlist; /* List of free obj. */ int free_cnt; /* How many free obj. */ int max_free_cnt; /* Max free arena size. */ int obj_inc; /* How many to allocate at a time. */ int obj_size; /* Size of objects. */ RF_DECLARE_MUTEX(lock); #if RF_FREELIST_STATS > 0 RF_FreeListStats_t stats; /* Statistics. */ #endif /* RF_FREELIST_STATS > 0 */ }; /* * fl = FreeList. * maxcnt = Max number of items in arena. * inc = How many to allocate at a time. * size = Size of object. */ #define RF_FREELIST_CREATE(_fl_,_maxcnt_,_inc_,_size_) \ do { \ int rc; \ RF_ASSERT((_inc_) > 0); \ RF_Malloc(_fl_, sizeof(RF_FreeList_t), (RF_FreeList_t *)); \ (_fl_)->objlist = NULL; \ (_fl_)->free_cnt = 0; \ (_fl_)->max_free_cnt = _maxcnt_; \ (_fl_)->obj_inc = _inc_; \ (_fl_)->obj_size = _size_; \ rc = rf_mutex_init(&(_fl_)->lock); \ if (rc) { \ RF_Free(_fl_, sizeof(RF_FreeList_t)); \ _fl_ = NULL; \ } \ RF_FREELIST_STAT_INIT(_fl_); \ } while (0) /* * fl = FreeList. * cnt = Number to prime with. * nextp = Name of "next" pointer in obj. * cast = Object cast. */ #define RF_FREELIST_PRIME(_fl_,_cnt_,_nextp_,_cast_) \ do { \ void *_p; \ int _i; \ RF_LOCK_MUTEX((_fl_)->lock); \ for (_i = 0; _i < (_cnt_); _i++) { \ RF_Calloc(_p, 1, (_fl_)->obj_size, (void *)); \ if (_p) { \ (_cast_(_p))->_nextp_ = (_fl_)->objlist; \ (_fl_)->objlist = _p; \ (_fl_)->free_cnt++; \ } \ else { \ break; \ } \ } \ RF_FREELIST_STAT_FREE_UPDATE(_fl_); \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) #define RF_FREELIST_MUTEX_OF(_fl_) ((_fl_)->lock) #define RF_FREELIST_DO_UNLOCK(_fl_) RF_UNLOCK_MUTEX((_fl_)->lock) #define RF_FREELIST_DO_LOCK(_fl_) RF_LOCK_MUTEX((_fl_)->lock) /* * fl = FreeList. * cnt = Number to prime with. * nextp = Name of "next" pointer in obj. * cast = Object cast. * init = Func to call to init obj. */ #define RF_FREELIST_PRIME_INIT(_fl_,_cnt_,_nextp_,_cast_,_init_) \ do { \ void *_p; \ int _i; \ RF_LOCK_MUTEX((_fl_)->lock); \ for (_i = 0; _i < (_cnt_); _i++) { \ RF_Calloc(_p, 1, (_fl_)->obj_size, (void *)); \ if (_init_(_cast_ _p)) { \ RF_Free(_p, (_fl_)->obj_size); \ _p = NULL; \ } \ if (_p) { \ (_cast_(_p))->_nextp_ = (_fl_)->objlist; \ (_fl_)->objlist = _p; \ (_fl_)->free_cnt++; \ } \ else { \ break; \ } \ } \ RF_FREELIST_STAT_FREE_UPDATE(_fl_); \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) /* * fl = FreeList. * cnt = Number to prime with. * nextp = Name of "next" pointer in obj. * cast = Object cast. * init = Func to call to init obj. * arg = Arg to init obj func. */ #define RF_FREELIST_PRIME_INIT_ARG(_fl_,_cnt_,_nextp_,_cast_,_init_,_arg_) \ do { \ void *_p; \ int _i; \ RF_LOCK_MUTEX((_fl_)->lock); \ for (_i = 0; _i < (_cnt_); _i++) { \ RF_Calloc(_p, 1, (_fl_)->obj_size, (void *)); \ if (_init_(_cast_ _p, _arg_)) { \ RF_Free(_p, (_fl_)->obj_size); \ _p = NULL; \ } \ if (_p) { \ (_cast_(_p))->_nextp_ = (_fl_)->objlist; \ (_fl_)->objlist = _p; \ (_fl_)->free_cnt++; \ } \ else { \ break; \ } \ } \ RF_FREELIST_STAT_FREE_UPDATE(_fl_); \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) /* * fl = FreeList. * obj = Object to allocate. * nextp = Name of "next" pointer in obj. * cast = Cast of obj assignment. * init = Init obj func. */ #define RF_FREELIST_GET_INIT(_fl_,_obj_,_nextp_,_cast_,_init_) \ do { \ void *_p; \ int _i; \ RF_LOCK_MUTEX((_fl_)->lock); \ RF_ASSERT(sizeof(*(_obj_)) == ((_fl_)->obj_size)); \ if (_fl_->objlist) { \ _obj_ = _cast_((_fl_)->objlist); \ (_fl_)->objlist = (void *)((_obj_)->_nextp_); \ (_fl_)->free_cnt--; \ } \ else { \ /* \ * Allocate one at a time so we can free \ * one at a time without cleverness when arena \ * is full. \ */ \ RF_Calloc(_obj_, 1, (_fl_)->obj_size, _cast_); \ if (_obj_) { \ if (_init_(_obj_)) { \ RF_Free(_obj_, (_fl_)->obj_size); \ _obj_ = NULL; \ } \ else { \ for (_i = 1; _i < (_fl_)->obj_inc; \ _i++) { \ RF_Calloc(_p, 1, \ (_fl_)->obj_size, \ (void *)); \ if (_p) { \ if (_init_(_p)) { \ RF_Free(_p, \ (_fl_)->obj_size); \ _p = NULL; \ break; \ } \ (_cast_(_p))->_nextp_ = \ (_fl_)->objlist; \ (_fl_)->objlist = _p; \ } \ else { \ break; \ } \ } \ } \ } \ RF_FREELIST_STAT_GROW(_fl_); \ } \ RF_FREELIST_STAT_ALLOC(_fl_); \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) /* * fl = FreeList. * obj = Object to allocate. * nextp = Name of "next" pointer in obj. * cast = Cast of obj assignment. * init = Init obj func. * arg = Arg to init obj func. */ #define RF_FREELIST_GET_INIT_ARG(_fl_,_obj_,_nextp_,_cast_,_init_,_arg_) \ do { \ void *_p; \ int _i; \ RF_LOCK_MUTEX((_fl_)->lock); \ RF_ASSERT(sizeof(*(_obj_)) == ((_fl_)->obj_size)); \ if (_fl_->objlist) { \ _obj_ = _cast_((_fl_)->objlist); \ (_fl_)->objlist = (void *)((_obj_)->_nextp_); \ (_fl_)->free_cnt--; \ } \ else { \ /* \ * Allocate one at a time so we can free \ * one at a time without cleverness when arena \ * is full. \ */ \ RF_Calloc(_obj_, 1, (_fl_)->obj_size, _cast_); \ if (_obj_) { \ if (_init_(_obj_, _arg_)) { \ RF_Free(_obj_, (_fl_)->obj_size); \ _obj_ = NULL; \ } \ else { \ for (_i = 1; _i < (_fl_)->obj_inc; \ _i++) { \ RF_Calloc(_p, 1, \ (_fl_)->obj_size, (void *)); \ if (_p) { \ if (_init_(_p, _arg_)) \ { \ RF_Free(_p, \ (_fl_)->obj_size); \ _p = NULL; \ break; \ } \ (_cast_(_p))->_nextp_ = \ (_fl_)->objlist; \ (_fl_)->objlist = _p; \ } \ else { \ break; \ } \ } \ } \ } \ RF_FREELIST_STAT_GROW(_fl_); \ } \ RF_FREELIST_STAT_ALLOC(_fl_); \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) /* * fl = FreeList. * obj = Object to allocate. * nextp = Name of "next" pointer in obj. * cast = Cast of obj assignment. * init = Init obj func. */ #define RF_FREELIST_GET_INIT_NOUNLOCK(_fl_,_obj_,_nextp_,_cast_,_init_) \ do { \ void *_p; \ int _i; \ RF_LOCK_MUTEX((_fl_)->lock); \ RF_ASSERT(sizeof(*(_obj_)) == ((_fl_)->obj_size)); \ if (_fl_->objlist) { \ _obj_ = _cast_((_fl_)->objlist); \ (_fl_)->objlist = (void *)((_obj_)->_nextp_); \ (_fl_)->free_cnt--; \ } \ else { \ /* \ * Allocate one at a time so we can free \ * one at a time without cleverness when arena \ * is full. \ */ \ RF_Calloc(_obj_, 1, (_fl_)->obj_size, _cast_); \ if (_obj_) { \ if (_init_(_obj_)) { \ RF_Free(_obj_, (_fl_)->obj_size); \ _obj_ = NULL; \ } \ else { \ for (_i = 1; _i < (_fl_)->obj_inc; \ _i++) { \ RF_Calloc(_p, 1, \ (_fl_)->obj_size, \ (void *)); \ if (_p) { \ if (_init_(_p)) { \ RF_Free(_p, \ (_fl_)->obj_size); \ _p = NULL; \ break; \ } \ (_cast_(_p))->_nextp_ = \ (_fl_)->objlist; \ (_fl_)->objlist = _p; \ } \ else { \ break; \ } \ } \ } \ } \ RF_FREELIST_STAT_GROW(_fl_); \ } \ RF_FREELIST_STAT_ALLOC(_fl_); \ } while (0) /* * fl = FreeList. * obj = Object to allocate. * nextp = Name of "next" pointer in obj. * cast = Cast of obj assignment. */ #define RF_FREELIST_GET(_fl_,_obj_,_nextp_,_cast_) \ do { \ void *_p; \ int _i; \ RF_LOCK_MUTEX((_fl_)->lock); \ RF_ASSERT(sizeof(*(_obj_)) == ((_fl_)->obj_size)); \ if (_fl_->objlist) { \ _obj_ = _cast_((_fl_)->objlist); \ (_fl_)->objlist = (void *)((_obj_)->_nextp_); \ (_fl_)->free_cnt--; \ } \ else { \ /* \ * Allocate one at a time so we can free \ * one at a time without cleverness when arena \ * is full. \ */ \ RF_Calloc(_obj_, 1, (_fl_)->obj_size, _cast_); \ if (_obj_) { \ for (_i = 1; _i < (_fl_)->obj_inc; _i++) { \ RF_Calloc(_p, 1, (_fl_)->obj_size, \ (void *)); \ if (_p) { \ (_cast_(_p))->_nextp_ = \ (_fl_)->objlist; \ (_fl_)->objlist = _p; \ } \ else { \ break; \ } \ } \ } \ RF_FREELIST_STAT_GROW(_fl_); \ } \ RF_FREELIST_STAT_ALLOC(_fl_); \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) /* * fl = FreeList. * obj = Object to allocate. * nextp = Name of "next" pointer in obj. * cast = Cast of obj assignment. * num = Num objs to return. */ #define RF_FREELIST_GET_N(_fl_,_obj_,_nextp_,_cast_,_num_) \ do { \ void *_p, *_l, *_f; \ int _i, _n; \ _l = _f = NULL; \ _n = 0; \ RF_LOCK_MUTEX((_fl_)->lock); \ RF_ASSERT(sizeof(*(_obj_)) == ((_fl_)->obj_size)); \ for (_n = 0; _n < _num_; _n++) { \ if (_fl_->objlist) { \ _obj_ = _cast_((_fl_)->objlist); \ (_fl_)->objlist = (void *)((_obj_)->_nextp_); \ (_fl_)->free_cnt--; \ } \ else { \ /* \ * Allocate one at a time so we can free \ * one at a time without cleverness when arena \ * is full. \ */ \ RF_Calloc(_obj_, 1, (_fl_)->obj_size, _cast_); \ if (_obj_) { \ for (_i = 1; _i < (_fl_)->obj_inc; \ _i++) { \ RF_Calloc(_p, 1, \ (_fl_)->obj_size, \ (void *)); \ if (_p) { \ (_cast_(_p))->_nextp_ = \ (_fl_)->objlist; \ (_fl_)->objlist = _p; \ } \ else { \ break; \ } \ } \ } \ RF_FREELIST_STAT_GROW(_fl_); \ } \ if (_f == NULL) \ _f = _obj_; \ if (_obj_) { \ (_cast_(_obj_))->_nextp_ = _l; \ _l = _obj_; \ RF_FREELIST_STAT_ALLOC(_fl_); \ } \ else { \ (_cast_(_f))->_nextp_ = (_fl_)->objlist; \ (_fl_)->objlist = _l; \ _n = _num_; \ } \ } \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) /* * fl = FreeList. * obj = Object to free. * nextp = Name of "next" pointer in obj. */ #define RF_FREELIST_FREE(_fl_,_obj_,_nextp_) \ do { \ RF_LOCK_MUTEX((_fl_)->lock); \ if ((_fl_)->free_cnt == (_fl_)->max_free_cnt) { \ RF_Free(_obj_, (_fl_)->obj_size); \ } \ else { \ RF_ASSERT((_fl_)->free_cnt < (_fl_)->max_free_cnt); \ (_obj_)->_nextp_ = (_fl_)->objlist; \ (_fl_)->objlist = (void *)(_obj_); \ (_fl_)->free_cnt++; \ } \ RF_FREELIST_STAT_FREE(_fl_); \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) /* * fl = FreeList. * obj = Object to free. * nextp = Name of "next" pointer in obj. * num = Num to free (debugging). */ #define RF_FREELIST_FREE_N(_fl_,_obj_,_nextp_,_cast_,_num_) \ do { \ void *_no; \ int _n; \ _n = 0; \ RF_LOCK_MUTEX((_fl_)->lock); \ while(_obj_) { \ _no = (_cast_(_obj_))->_nextp_; \ if ((_fl_)->free_cnt == (_fl_)->max_free_cnt) { \ RF_Free(_obj_, (_fl_)->obj_size); \ } \ else { \ RF_ASSERT((_fl_)->free_cnt < \ (_fl_)->max_free_cnt); \ (_obj_)->_nextp_ = (_fl_)->objlist; \ (_fl_)->objlist = (void *)(_obj_); \ (_fl_)->free_cnt++; \ } \ _n++; \ _obj_ = _no; \ RF_FREELIST_STAT_FREE(_fl_); \ } \ RF_ASSERT(_n==(_num_)); \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) /* * fl = FreeList. * obj = Object to free. * nextp = Name of "next" pointer in obj. * clean = Undo for init. */ #define RF_FREELIST_FREE_CLEAN(_fl_,_obj_,_nextp_,_clean_) \ do { \ RF_LOCK_MUTEX((_fl_)->lock); \ if ((_fl_)->free_cnt == (_fl_)->max_free_cnt) { \ _clean_(_obj_); \ RF_Free(_obj_, (_fl_)->obj_size); \ } \ else { \ RF_ASSERT((_fl_)->free_cnt < (_fl_)->max_free_cnt); \ (_obj_)->_nextp_ = (_fl_)->objlist; \ (_fl_)->objlist = (void *)(_obj_); \ (_fl_)->free_cnt++; \ } \ RF_FREELIST_STAT_FREE(_fl_); \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) /* * fl = FreeList. * obj = Object to free. * nextp = Name of "next" pointer in obj. * clean = Undo for init. * arg = Arg for undo func. */ #define RF_FREELIST_FREE_CLEAN_ARG(_fl_,_obj_,_nextp_,_clean_,_arg_) \ do { \ RF_LOCK_MUTEX((_fl_)->lock); \ if ((_fl_)->free_cnt == (_fl_)->max_free_cnt) { \ _clean_(_obj_, _arg_); \ RF_Free(_obj_, (_fl_)->obj_size); \ } \ else { \ RF_ASSERT((_fl_)->free_cnt < (_fl_)->max_free_cnt); \ (_obj_)->_nextp_ = (_fl_)->objlist; \ (_fl_)->objlist = (void *)(_obj_); \ (_fl_)->free_cnt++; \ } \ RF_FREELIST_STAT_FREE(_fl_); \ RF_UNLOCK_MUTEX((_fl_)->lock); \ } while (0) /* * fl = FreeList. * obj = Object to free. * nextp = Name of "next" pointer in obj. * clean = Undo for init. */ #define RF_FREELIST_FREE_CLEAN_NOUNLOCK(_fl_,_obj_,_nextp_,_clean_) \ do { \ RF_LOCK_MUTEX((_fl_)->lock); \ if ((_fl_)->free_cnt == (_fl_)->max_free_cnt) { \ _clean_(_obj_); \ RF_Free(_obj_, (_fl_)->obj_size); \ } \ else { \ RF_ASSERT((_fl_)->free_cnt < (_fl_)->max_free_cnt); \ (_obj_)->_nextp_ = (_fl_)->objlist; \ (_fl_)->objlist = (void *)(_obj_); \ (_fl_)->free_cnt++; \ } \ RF_FREELIST_STAT_FREE(_fl_); \ } while (0) /* * fl = FreeList. * nextp = Name of "next" pointer in obj. * cast = Cast to object type. */ #define RF_FREELIST_DESTROY(_fl_,_nextp_,_cast_) \ do { \ void *_cur, *_next; \ RF_FREELIST_STAT_REPORT(_fl_); \ rf_mutex_destroy(&((_fl_)->lock)); \ for (_cur = (_fl_)->objlist; _cur; _cur = _next) { \ _next = (_cast_ _cur)->_nextp_; \ RF_Free(_cur, (_fl_)->obj_size); \ } \ RF_Free(_fl_, sizeof(RF_FreeList_t)); \ } while (0) /* * fl = FreeList. * nextp = Name of "next" pointer in obj. * cast = Cast to object type. * clean = Func to undo obj init. */ #define RF_FREELIST_DESTROY_CLEAN(_fl_,_nextp_,_cast_,_clean_) \ do { \ void *_cur, *_next; \ RF_FREELIST_STAT_REPORT(_fl_); \ rf_mutex_destroy(&((_fl_)->lock)); \ for (_cur = (_fl_)->objlist; _cur; _cur = _next) { \ _next = (_cast_ _cur)->_nextp_; \ _clean_(_cur); \ RF_Free(_cur, (_fl_)->obj_size); \ } \ RF_Free(_fl_, sizeof(RF_FreeList_t)); \ } while (0) /* * fl = FreeList. * nextp = Name of "next" pointer in obj. * cast = Cast to object type. * clean = Func to undo obj init. * arg = Arg for undo func. */ #define RF_FREELIST_DESTROY_CLEAN_ARG(_fl_,_nextp_,_cast_,_clean_,_arg_) \ do { \ void *_cur, *_next; \ RF_FREELIST_STAT_REPORT(_fl_); \ rf_mutex_destroy(&((_fl_)->lock)); \ for (_cur = (_fl_)->objlist; _cur; _cur = _next) { \ _next = (_cast_ _cur)->_nextp_; \ _clean_(_cur, _arg_); \ RF_Free(_cur, (_fl_)->obj_size); \ } \ RF_Free(_fl_, sizeof(RF_FreeList_t)); \ } while (0) #endif /* !_RF__RF_FREELIST_H_ */