1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * All rights reserved.
5*7c478bd9Sstevel@tonic-gate *
6*7c478bd9Sstevel@tonic-gate * Permission is hereby granted, free of charge, to any person obtaining a
7*7c478bd9Sstevel@tonic-gate * copy of this software and associated documentation files (the
8*7c478bd9Sstevel@tonic-gate * "Software"), to deal in the Software without restriction, including
9*7c478bd9Sstevel@tonic-gate * without limitation the rights to use, copy, modify, merge, publish,
10*7c478bd9Sstevel@tonic-gate * distribute, and/or sell copies of the Software, and to permit persons
11*7c478bd9Sstevel@tonic-gate * to whom the Software is furnished to do so, provided that the above
12*7c478bd9Sstevel@tonic-gate * copyright notice(s) and this permission notice appear in all copies of
13*7c478bd9Sstevel@tonic-gate * the Software and that both the above copyright notice(s) and this
14*7c478bd9Sstevel@tonic-gate * permission notice appear in supporting documentation.
15*7c478bd9Sstevel@tonic-gate *
16*7c478bd9Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17*7c478bd9Sstevel@tonic-gate * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*7c478bd9Sstevel@tonic-gate * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
19*7c478bd9Sstevel@tonic-gate * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20*7c478bd9Sstevel@tonic-gate * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
21*7c478bd9Sstevel@tonic-gate * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
22*7c478bd9Sstevel@tonic-gate * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
23*7c478bd9Sstevel@tonic-gate * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
24*7c478bd9Sstevel@tonic-gate * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25*7c478bd9Sstevel@tonic-gate *
26*7c478bd9Sstevel@tonic-gate * Except as contained in this notice, the name of a copyright holder
27*7c478bd9Sstevel@tonic-gate * shall not be used in advertising or otherwise to promote the sale, use
28*7c478bd9Sstevel@tonic-gate * or other dealings in this Software without prior written authorization
29*7c478bd9Sstevel@tonic-gate * of the copyright holder.
30*7c478bd9Sstevel@tonic-gate */
31*7c478bd9Sstevel@tonic-gate
32*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
33*7c478bd9Sstevel@tonic-gate
34*7c478bd9Sstevel@tonic-gate #include <stdio.h>
35*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
36*7c478bd9Sstevel@tonic-gate #include <errno.h>
37*7c478bd9Sstevel@tonic-gate
38*7c478bd9Sstevel@tonic-gate #include "freelist.h"
39*7c478bd9Sstevel@tonic-gate
40*7c478bd9Sstevel@tonic-gate typedef struct FreeListBlock FreeListBlock;
41*7c478bd9Sstevel@tonic-gate struct FreeListBlock {
42*7c478bd9Sstevel@tonic-gate FreeListBlock *next; /* The next block in the list */
43*7c478bd9Sstevel@tonic-gate char *nodes; /* The array of free-list nodes */
44*7c478bd9Sstevel@tonic-gate };
45*7c478bd9Sstevel@tonic-gate
46*7c478bd9Sstevel@tonic-gate struct FreeList {
47*7c478bd9Sstevel@tonic-gate size_t node_size; /* The size of a free-list node */
48*7c478bd9Sstevel@tonic-gate unsigned blocking_factor; /* The number of nodes per block */
49*7c478bd9Sstevel@tonic-gate long nbusy; /* The number of nodes that are in use */
50*7c478bd9Sstevel@tonic-gate long ntotal; /* The total number of nodes in the free list */
51*7c478bd9Sstevel@tonic-gate FreeListBlock *block; /* The head of the list of free-list blocks */
52*7c478bd9Sstevel@tonic-gate void *free_list; /* The free-list of nodes */
53*7c478bd9Sstevel@tonic-gate };
54*7c478bd9Sstevel@tonic-gate
55*7c478bd9Sstevel@tonic-gate static FreeListBlock *_new_FreeListBlock(FreeList *fl);
56*7c478bd9Sstevel@tonic-gate static FreeListBlock *_del_FreeListBlock(FreeListBlock *fl);
57*7c478bd9Sstevel@tonic-gate static void _thread_FreeListBlock(FreeList *fl, FreeListBlock *block);
58*7c478bd9Sstevel@tonic-gate
59*7c478bd9Sstevel@tonic-gate /*.......................................................................
60*7c478bd9Sstevel@tonic-gate * Allocate a new free-list from blocks of 'blocking_factor' objects of size
61*7c478bd9Sstevel@tonic-gate * node_size.
62*7c478bd9Sstevel@tonic-gate *
63*7c478bd9Sstevel@tonic-gate * Input:
64*7c478bd9Sstevel@tonic-gate * node_size size_t The size of the free-list nodes to be returned
65*7c478bd9Sstevel@tonic-gate * by _new_FreeListNode(). Use sizeof() to
66*7c478bd9Sstevel@tonic-gate * determine this.
67*7c478bd9Sstevel@tonic-gate * blocking_factor unsigned The number of objects of size 'object_size'
68*7c478bd9Sstevel@tonic-gate * to allocate per block.
69*7c478bd9Sstevel@tonic-gate * Output:
70*7c478bd9Sstevel@tonic-gate * return FreeList * The new freelist, or NULL on error.
71*7c478bd9Sstevel@tonic-gate */
_new_FreeList(size_t node_size,unsigned blocking_factor)72*7c478bd9Sstevel@tonic-gate FreeList *_new_FreeList(size_t node_size, unsigned blocking_factor)
73*7c478bd9Sstevel@tonic-gate {
74*7c478bd9Sstevel@tonic-gate FreeList *fl; /* The new free-list container */
75*7c478bd9Sstevel@tonic-gate /*
76*7c478bd9Sstevel@tonic-gate * When a free-list node is on the free-list, it is used as a (void *)
77*7c478bd9Sstevel@tonic-gate * link field. Roundup node_size to a mulitple of the size of a void
78*7c478bd9Sstevel@tonic-gate * pointer. This, plus the fact that the array of nodes is obtained via
79*7c478bd9Sstevel@tonic-gate * malloc, which returns memory suitably aligned for any object, will
80*7c478bd9Sstevel@tonic-gate * ensure that the first sizeof(void *) bytes of each node will be
81*7c478bd9Sstevel@tonic-gate * suitably aligned to use as a (void *) link pointer.
82*7c478bd9Sstevel@tonic-gate */
83*7c478bd9Sstevel@tonic-gate node_size = sizeof(void *) *
84*7c478bd9Sstevel@tonic-gate ((node_size + sizeof(void *) - 1) / sizeof(void *));
85*7c478bd9Sstevel@tonic-gate /*
86*7c478bd9Sstevel@tonic-gate * Enfore a minimum block size.
87*7c478bd9Sstevel@tonic-gate */
88*7c478bd9Sstevel@tonic-gate if(blocking_factor < 1)
89*7c478bd9Sstevel@tonic-gate blocking_factor = 1;
90*7c478bd9Sstevel@tonic-gate /*
91*7c478bd9Sstevel@tonic-gate * Allocate the container of the free list.
92*7c478bd9Sstevel@tonic-gate */
93*7c478bd9Sstevel@tonic-gate fl = (FreeList *) malloc(sizeof(FreeList));
94*7c478bd9Sstevel@tonic-gate if(!fl) {
95*7c478bd9Sstevel@tonic-gate errno = ENOMEM;
96*7c478bd9Sstevel@tonic-gate return NULL;
97*7c478bd9Sstevel@tonic-gate };
98*7c478bd9Sstevel@tonic-gate /*
99*7c478bd9Sstevel@tonic-gate * Before attempting any operation that might fail, initialize the
100*7c478bd9Sstevel@tonic-gate * container at least up to the point at which it can safely be passed
101*7c478bd9Sstevel@tonic-gate * to _del_FreeList().
102*7c478bd9Sstevel@tonic-gate */
103*7c478bd9Sstevel@tonic-gate fl->node_size = node_size;
104*7c478bd9Sstevel@tonic-gate fl->blocking_factor = blocking_factor;
105*7c478bd9Sstevel@tonic-gate fl->nbusy = 0;
106*7c478bd9Sstevel@tonic-gate fl->ntotal = 0;
107*7c478bd9Sstevel@tonic-gate fl->block = NULL;
108*7c478bd9Sstevel@tonic-gate fl->free_list = NULL;
109*7c478bd9Sstevel@tonic-gate /*
110*7c478bd9Sstevel@tonic-gate * Allocate the first block of memory.
111*7c478bd9Sstevel@tonic-gate */
112*7c478bd9Sstevel@tonic-gate fl->block = _new_FreeListBlock(fl);
113*7c478bd9Sstevel@tonic-gate if(!fl->block) {
114*7c478bd9Sstevel@tonic-gate errno = ENOMEM;
115*7c478bd9Sstevel@tonic-gate return _del_FreeList(fl, 1);
116*7c478bd9Sstevel@tonic-gate };
117*7c478bd9Sstevel@tonic-gate /*
118*7c478bd9Sstevel@tonic-gate * Add the new list of nodes to the free-list.
119*7c478bd9Sstevel@tonic-gate */
120*7c478bd9Sstevel@tonic-gate fl->free_list = fl->block->nodes;
121*7c478bd9Sstevel@tonic-gate /*
122*7c478bd9Sstevel@tonic-gate * Return the free-list for use.
123*7c478bd9Sstevel@tonic-gate */
124*7c478bd9Sstevel@tonic-gate return fl;
125*7c478bd9Sstevel@tonic-gate }
126*7c478bd9Sstevel@tonic-gate
127*7c478bd9Sstevel@tonic-gate /*.......................................................................
128*7c478bd9Sstevel@tonic-gate * Re-thread a freelist to reclaim all allocated nodes.
129*7c478bd9Sstevel@tonic-gate * This function should not be called unless if it is known that none
130*7c478bd9Sstevel@tonic-gate * of the currently allocated nodes are still being used.
131*7c478bd9Sstevel@tonic-gate *
132*7c478bd9Sstevel@tonic-gate * Input:
133*7c478bd9Sstevel@tonic-gate * fl FreeList * The free-list to be reset, or NULL.
134*7c478bd9Sstevel@tonic-gate */
_rst_FreeList(FreeList * fl)135*7c478bd9Sstevel@tonic-gate void _rst_FreeList(FreeList *fl)
136*7c478bd9Sstevel@tonic-gate {
137*7c478bd9Sstevel@tonic-gate if(fl) {
138*7c478bd9Sstevel@tonic-gate FreeListBlock *block;
139*7c478bd9Sstevel@tonic-gate /*
140*7c478bd9Sstevel@tonic-gate * Re-thread the nodes of each block into individual free-lists.
141*7c478bd9Sstevel@tonic-gate */
142*7c478bd9Sstevel@tonic-gate for(block=fl->block; block; block=block->next)
143*7c478bd9Sstevel@tonic-gate _thread_FreeListBlock(fl, block);
144*7c478bd9Sstevel@tonic-gate /*
145*7c478bd9Sstevel@tonic-gate * Link all of the block freelists into one large freelist.
146*7c478bd9Sstevel@tonic-gate */
147*7c478bd9Sstevel@tonic-gate fl->free_list = NULL;
148*7c478bd9Sstevel@tonic-gate for(block=fl->block; block; block=block->next) {
149*7c478bd9Sstevel@tonic-gate /*
150*7c478bd9Sstevel@tonic-gate * Locate the last node of the current block.
151*7c478bd9Sstevel@tonic-gate */
152*7c478bd9Sstevel@tonic-gate char *last_node = block->nodes + fl->node_size *
153*7c478bd9Sstevel@tonic-gate (fl->blocking_factor - 1);
154*7c478bd9Sstevel@tonic-gate /*
155*7c478bd9Sstevel@tonic-gate * Make the link-field of the last node point to the first
156*7c478bd9Sstevel@tonic-gate * node of the current freelist, then make the first node of the
157*7c478bd9Sstevel@tonic-gate * new block the start of the freelist.
158*7c478bd9Sstevel@tonic-gate */
159*7c478bd9Sstevel@tonic-gate *(void **)last_node = fl->free_list;
160*7c478bd9Sstevel@tonic-gate fl->free_list = block->nodes;
161*7c478bd9Sstevel@tonic-gate };
162*7c478bd9Sstevel@tonic-gate /*
163*7c478bd9Sstevel@tonic-gate * All allocated nodes have now been returned to the freelist.
164*7c478bd9Sstevel@tonic-gate */
165*7c478bd9Sstevel@tonic-gate fl->nbusy = 0;
166*7c478bd9Sstevel@tonic-gate };
167*7c478bd9Sstevel@tonic-gate }
168*7c478bd9Sstevel@tonic-gate
169*7c478bd9Sstevel@tonic-gate /*.......................................................................
170*7c478bd9Sstevel@tonic-gate * Delete a free-list.
171*7c478bd9Sstevel@tonic-gate *
172*7c478bd9Sstevel@tonic-gate * Input:
173*7c478bd9Sstevel@tonic-gate * fl FreeList * The free-list to be deleted, or NULL.
174*7c478bd9Sstevel@tonic-gate * force int If force==0 then _del_FreeList() will complain
175*7c478bd9Sstevel@tonic-gate * and refuse to delete the free-list if any
176*7c478bd9Sstevel@tonic-gate * of nodes have not been returned to the free-list.
177*7c478bd9Sstevel@tonic-gate * If force!=0 then _del_FreeList() will not check
178*7c478bd9Sstevel@tonic-gate * whether any nodes are still in use and will
179*7c478bd9Sstevel@tonic-gate * always delete the list.
180*7c478bd9Sstevel@tonic-gate * Output:
181*7c478bd9Sstevel@tonic-gate * return FreeList * Always NULL (even if the list couldn't be
182*7c478bd9Sstevel@tonic-gate * deleted).
183*7c478bd9Sstevel@tonic-gate */
_del_FreeList(FreeList * fl,int force)184*7c478bd9Sstevel@tonic-gate FreeList *_del_FreeList(FreeList *fl, int force)
185*7c478bd9Sstevel@tonic-gate {
186*7c478bd9Sstevel@tonic-gate if(fl) {
187*7c478bd9Sstevel@tonic-gate /*
188*7c478bd9Sstevel@tonic-gate * Check whether any nodes are in use.
189*7c478bd9Sstevel@tonic-gate */
190*7c478bd9Sstevel@tonic-gate if(!force && _busy_FreeListNodes(fl) != 0) {
191*7c478bd9Sstevel@tonic-gate errno = EBUSY;
192*7c478bd9Sstevel@tonic-gate return NULL;
193*7c478bd9Sstevel@tonic-gate };
194*7c478bd9Sstevel@tonic-gate /*
195*7c478bd9Sstevel@tonic-gate * Delete the list blocks.
196*7c478bd9Sstevel@tonic-gate */
197*7c478bd9Sstevel@tonic-gate {
198*7c478bd9Sstevel@tonic-gate FreeListBlock *next = fl->block;
199*7c478bd9Sstevel@tonic-gate while(next) {
200*7c478bd9Sstevel@tonic-gate FreeListBlock *block = next;
201*7c478bd9Sstevel@tonic-gate next = block->next;
202*7c478bd9Sstevel@tonic-gate block = _del_FreeListBlock(block);
203*7c478bd9Sstevel@tonic-gate };
204*7c478bd9Sstevel@tonic-gate };
205*7c478bd9Sstevel@tonic-gate fl->block = NULL;
206*7c478bd9Sstevel@tonic-gate fl->free_list = NULL;
207*7c478bd9Sstevel@tonic-gate /*
208*7c478bd9Sstevel@tonic-gate * Discard the container.
209*7c478bd9Sstevel@tonic-gate */
210*7c478bd9Sstevel@tonic-gate free(fl);
211*7c478bd9Sstevel@tonic-gate };
212*7c478bd9Sstevel@tonic-gate return NULL;
213*7c478bd9Sstevel@tonic-gate }
214*7c478bd9Sstevel@tonic-gate
215*7c478bd9Sstevel@tonic-gate /*.......................................................................
216*7c478bd9Sstevel@tonic-gate * Allocate a new object from a free-list.
217*7c478bd9Sstevel@tonic-gate *
218*7c478bd9Sstevel@tonic-gate * Input:
219*7c478bd9Sstevel@tonic-gate * fl FreeList * The free-list to return an object from.
220*7c478bd9Sstevel@tonic-gate * Output:
221*7c478bd9Sstevel@tonic-gate * return void * A new object of the size that was specified via
222*7c478bd9Sstevel@tonic-gate * the node_size argument of _new_FreeList() when
223*7c478bd9Sstevel@tonic-gate * the free-list was created, or NULL if there
224*7c478bd9Sstevel@tonic-gate * is insufficient memory, or 'fl' is NULL.
225*7c478bd9Sstevel@tonic-gate */
_new_FreeListNode(FreeList * fl)226*7c478bd9Sstevel@tonic-gate void *_new_FreeListNode(FreeList *fl)
227*7c478bd9Sstevel@tonic-gate {
228*7c478bd9Sstevel@tonic-gate void *node; /* The node to be returned */
229*7c478bd9Sstevel@tonic-gate /*
230*7c478bd9Sstevel@tonic-gate * Check arguments.
231*7c478bd9Sstevel@tonic-gate */
232*7c478bd9Sstevel@tonic-gate if(!fl)
233*7c478bd9Sstevel@tonic-gate return NULL;
234*7c478bd9Sstevel@tonic-gate /*
235*7c478bd9Sstevel@tonic-gate * If the free-list has been exhausted extend it by allocating
236*7c478bd9Sstevel@tonic-gate * another block of nodes.
237*7c478bd9Sstevel@tonic-gate */
238*7c478bd9Sstevel@tonic-gate if(!fl->free_list) {
239*7c478bd9Sstevel@tonic-gate FreeListBlock *block = _new_FreeListBlock(fl);
240*7c478bd9Sstevel@tonic-gate if(!block)
241*7c478bd9Sstevel@tonic-gate return NULL;
242*7c478bd9Sstevel@tonic-gate /*
243*7c478bd9Sstevel@tonic-gate * Prepend the new block to the list of free-list blocks.
244*7c478bd9Sstevel@tonic-gate */
245*7c478bd9Sstevel@tonic-gate block->next = fl->block;
246*7c478bd9Sstevel@tonic-gate fl->block = block;
247*7c478bd9Sstevel@tonic-gate /*
248*7c478bd9Sstevel@tonic-gate * Add the new list of nodes to the free-list.
249*7c478bd9Sstevel@tonic-gate */
250*7c478bd9Sstevel@tonic-gate fl->free_list = fl->block->nodes;
251*7c478bd9Sstevel@tonic-gate };
252*7c478bd9Sstevel@tonic-gate /*
253*7c478bd9Sstevel@tonic-gate * Remove and return a node from the front of the free list.
254*7c478bd9Sstevel@tonic-gate */
255*7c478bd9Sstevel@tonic-gate node = fl->free_list;
256*7c478bd9Sstevel@tonic-gate fl->free_list = *(void **)node;
257*7c478bd9Sstevel@tonic-gate /*
258*7c478bd9Sstevel@tonic-gate * Record the loss of a node from the free-list.
259*7c478bd9Sstevel@tonic-gate */
260*7c478bd9Sstevel@tonic-gate fl->nbusy++;
261*7c478bd9Sstevel@tonic-gate /*
262*7c478bd9Sstevel@tonic-gate * Return the node.
263*7c478bd9Sstevel@tonic-gate */
264*7c478bd9Sstevel@tonic-gate return node;
265*7c478bd9Sstevel@tonic-gate }
266*7c478bd9Sstevel@tonic-gate
267*7c478bd9Sstevel@tonic-gate /*.......................................................................
268*7c478bd9Sstevel@tonic-gate * Return an object to the free-list that it was allocated from.
269*7c478bd9Sstevel@tonic-gate *
270*7c478bd9Sstevel@tonic-gate * Input:
271*7c478bd9Sstevel@tonic-gate * fl FreeList * The free-list from which the object was taken.
272*7c478bd9Sstevel@tonic-gate * object void * The node to be returned.
273*7c478bd9Sstevel@tonic-gate * Output:
274*7c478bd9Sstevel@tonic-gate * return void * Always NULL.
275*7c478bd9Sstevel@tonic-gate */
_del_FreeListNode(FreeList * fl,void * object)276*7c478bd9Sstevel@tonic-gate void *_del_FreeListNode(FreeList *fl, void *object)
277*7c478bd9Sstevel@tonic-gate {
278*7c478bd9Sstevel@tonic-gate /*
279*7c478bd9Sstevel@tonic-gate * Check arguments.
280*7c478bd9Sstevel@tonic-gate */
281*7c478bd9Sstevel@tonic-gate if(!fl)
282*7c478bd9Sstevel@tonic-gate return NULL;
283*7c478bd9Sstevel@tonic-gate /*
284*7c478bd9Sstevel@tonic-gate * Return the node to the head of the free list.
285*7c478bd9Sstevel@tonic-gate */
286*7c478bd9Sstevel@tonic-gate if(object) {
287*7c478bd9Sstevel@tonic-gate *(void **)object = fl->free_list;
288*7c478bd9Sstevel@tonic-gate fl->free_list = object;
289*7c478bd9Sstevel@tonic-gate /*
290*7c478bd9Sstevel@tonic-gate * Record the return of the node to the free-list.
291*7c478bd9Sstevel@tonic-gate */
292*7c478bd9Sstevel@tonic-gate fl->nbusy--;
293*7c478bd9Sstevel@tonic-gate };
294*7c478bd9Sstevel@tonic-gate return NULL;
295*7c478bd9Sstevel@tonic-gate }
296*7c478bd9Sstevel@tonic-gate
297*7c478bd9Sstevel@tonic-gate /*.......................................................................
298*7c478bd9Sstevel@tonic-gate * Return a count of the number of nodes that are currently allocated.
299*7c478bd9Sstevel@tonic-gate *
300*7c478bd9Sstevel@tonic-gate * Input:
301*7c478bd9Sstevel@tonic-gate * fl FreeList * The list to count wrt, or NULL.
302*7c478bd9Sstevel@tonic-gate * Output:
303*7c478bd9Sstevel@tonic-gate * return long The number of nodes (or 0 if fl==NULL).
304*7c478bd9Sstevel@tonic-gate */
_busy_FreeListNodes(FreeList * fl)305*7c478bd9Sstevel@tonic-gate long _busy_FreeListNodes(FreeList *fl)
306*7c478bd9Sstevel@tonic-gate {
307*7c478bd9Sstevel@tonic-gate return fl ? fl->nbusy : 0;
308*7c478bd9Sstevel@tonic-gate }
309*7c478bd9Sstevel@tonic-gate
310*7c478bd9Sstevel@tonic-gate /*.......................................................................
311*7c478bd9Sstevel@tonic-gate * Query the number of allocated nodes in the freelist which are
312*7c478bd9Sstevel@tonic-gate * currently unused.
313*7c478bd9Sstevel@tonic-gate *
314*7c478bd9Sstevel@tonic-gate * Input:
315*7c478bd9Sstevel@tonic-gate * fl FreeList * The list to count wrt, or NULL.
316*7c478bd9Sstevel@tonic-gate * Output:
317*7c478bd9Sstevel@tonic-gate * return long The number of unused nodes (or 0 if fl==NULL).
318*7c478bd9Sstevel@tonic-gate */
_idle_FreeListNodes(FreeList * fl)319*7c478bd9Sstevel@tonic-gate long _idle_FreeListNodes(FreeList *fl)
320*7c478bd9Sstevel@tonic-gate {
321*7c478bd9Sstevel@tonic-gate return fl ? (fl->ntotal - fl->nbusy) : 0;
322*7c478bd9Sstevel@tonic-gate }
323*7c478bd9Sstevel@tonic-gate
324*7c478bd9Sstevel@tonic-gate /*.......................................................................
325*7c478bd9Sstevel@tonic-gate * Allocate a new list of free-list nodes. On return the nodes will
326*7c478bd9Sstevel@tonic-gate * be linked together as a list starting with the node at the lowest
327*7c478bd9Sstevel@tonic-gate * address and ending with a NULL next pointer.
328*7c478bd9Sstevel@tonic-gate *
329*7c478bd9Sstevel@tonic-gate * Input:
330*7c478bd9Sstevel@tonic-gate * fl FreeList * The free-list to allocate the list for.
331*7c478bd9Sstevel@tonic-gate * Output:
332*7c478bd9Sstevel@tonic-gate * return FreeListBlock * The new linked block of free-list nodes,
333*7c478bd9Sstevel@tonic-gate * or NULL on error.
334*7c478bd9Sstevel@tonic-gate */
_new_FreeListBlock(FreeList * fl)335*7c478bd9Sstevel@tonic-gate static FreeListBlock *_new_FreeListBlock(FreeList *fl)
336*7c478bd9Sstevel@tonic-gate {
337*7c478bd9Sstevel@tonic-gate FreeListBlock *block; /* The new block to be returned */
338*7c478bd9Sstevel@tonic-gate /*
339*7c478bd9Sstevel@tonic-gate * Allocate the container.
340*7c478bd9Sstevel@tonic-gate */
341*7c478bd9Sstevel@tonic-gate block = (FreeListBlock *) malloc(sizeof(FreeListBlock));
342*7c478bd9Sstevel@tonic-gate if(!block)
343*7c478bd9Sstevel@tonic-gate return NULL;
344*7c478bd9Sstevel@tonic-gate /*
345*7c478bd9Sstevel@tonic-gate * Before attempting any operation that might fail, initialize the
346*7c478bd9Sstevel@tonic-gate * container at least up to the point at which it can safely be passed
347*7c478bd9Sstevel@tonic-gate * to _del_FreeListBlock().
348*7c478bd9Sstevel@tonic-gate */
349*7c478bd9Sstevel@tonic-gate block->next = NULL;
350*7c478bd9Sstevel@tonic-gate block->nodes = NULL;
351*7c478bd9Sstevel@tonic-gate /*
352*7c478bd9Sstevel@tonic-gate * Allocate the block of nodes.
353*7c478bd9Sstevel@tonic-gate */
354*7c478bd9Sstevel@tonic-gate block->nodes = (char *) malloc(fl->node_size * fl->blocking_factor);
355*7c478bd9Sstevel@tonic-gate if(!block->nodes)
356*7c478bd9Sstevel@tonic-gate return _del_FreeListBlock(block);
357*7c478bd9Sstevel@tonic-gate /*
358*7c478bd9Sstevel@tonic-gate * Initialize the block as a linked list of FreeListNode's.
359*7c478bd9Sstevel@tonic-gate */
360*7c478bd9Sstevel@tonic-gate _thread_FreeListBlock(fl, block);
361*7c478bd9Sstevel@tonic-gate /*
362*7c478bd9Sstevel@tonic-gate * Update the record of the number of nodes in the freelist.
363*7c478bd9Sstevel@tonic-gate */
364*7c478bd9Sstevel@tonic-gate fl->ntotal += fl->blocking_factor;
365*7c478bd9Sstevel@tonic-gate return block;
366*7c478bd9Sstevel@tonic-gate }
367*7c478bd9Sstevel@tonic-gate
368*7c478bd9Sstevel@tonic-gate /*.......................................................................
369*7c478bd9Sstevel@tonic-gate * Link each node of a freelist block to the node that follows it.
370*7c478bd9Sstevel@tonic-gate *
371*7c478bd9Sstevel@tonic-gate * Input:
372*7c478bd9Sstevel@tonic-gate * fl FreeList * The freelist that contains the block.
373*7c478bd9Sstevel@tonic-gate * block FreeListBlock * The block to be threaded.
374*7c478bd9Sstevel@tonic-gate */
_thread_FreeListBlock(FreeList * fl,FreeListBlock * block)375*7c478bd9Sstevel@tonic-gate static void _thread_FreeListBlock(FreeList *fl, FreeListBlock *block)
376*7c478bd9Sstevel@tonic-gate {
377*7c478bd9Sstevel@tonic-gate char *mem = block->nodes;
378*7c478bd9Sstevel@tonic-gate int i;
379*7c478bd9Sstevel@tonic-gate for(i=0; i<fl->blocking_factor - 1; i++, mem += fl->node_size)
380*7c478bd9Sstevel@tonic-gate *(void **)mem = mem + fl->node_size; /* Link to the next node */
381*7c478bd9Sstevel@tonic-gate *(void **)mem = NULL; /* Terminate the list */
382*7c478bd9Sstevel@tonic-gate }
383*7c478bd9Sstevel@tonic-gate
384*7c478bd9Sstevel@tonic-gate /*.......................................................................
385*7c478bd9Sstevel@tonic-gate * Delete a free-list block.
386*7c478bd9Sstevel@tonic-gate *
387*7c478bd9Sstevel@tonic-gate * Input:
388*7c478bd9Sstevel@tonic-gate * fl FreeListBlock * The block to be deleted, or NULL.
389*7c478bd9Sstevel@tonic-gate * Output:
390*7c478bd9Sstevel@tonic-gate * return FreeListBlock * Always NULL.
391*7c478bd9Sstevel@tonic-gate */
_del_FreeListBlock(FreeListBlock * fl)392*7c478bd9Sstevel@tonic-gate static FreeListBlock *_del_FreeListBlock(FreeListBlock *fl)
393*7c478bd9Sstevel@tonic-gate {
394*7c478bd9Sstevel@tonic-gate if(fl) {
395*7c478bd9Sstevel@tonic-gate fl->next = NULL;
396*7c478bd9Sstevel@tonic-gate if(fl->nodes)
397*7c478bd9Sstevel@tonic-gate free(fl->nodes);
398*7c478bd9Sstevel@tonic-gate fl->nodes = NULL;
399*7c478bd9Sstevel@tonic-gate free(fl);
400*7c478bd9Sstevel@tonic-gate };
401*7c478bd9Sstevel@tonic-gate return NULL;
402*7c478bd9Sstevel@tonic-gate }
403