xref: /optee_os/lib/libutils/isoc/bget.c (revision 17967299679c805b86fc045a4e0939ad2ad3a797)
1074ba9b2SJens Wiklander /*
2074ba9b2SJens Wiklander 
3074ba9b2SJens Wiklander 			       B G E T
4074ba9b2SJens Wiklander 
5074ba9b2SJens Wiklander 			   Buffer allocator
6074ba9b2SJens Wiklander 
7074ba9b2SJens Wiklander     Designed and implemented in April of 1972 by John Walker, based on the
8074ba9b2SJens Wiklander     Case Algol OPRO$ algorithm implemented in 1966.
9074ba9b2SJens Wiklander 
10074ba9b2SJens Wiklander     Reimplemented in 1975 by John Walker for the Interdata 70.
11074ba9b2SJens Wiklander     Reimplemented in 1977 by John Walker for the Marinchip 9900.
12074ba9b2SJens Wiklander     Reimplemented in 1982 by Duff Kurland for the Intel 8080.
13074ba9b2SJens Wiklander 
14074ba9b2SJens Wiklander     Portable C version implemented in September of 1990 by an older, wiser
15074ba9b2SJens Wiklander     instance of the original implementor.
16074ba9b2SJens Wiklander 
17074ba9b2SJens Wiklander     Souped up and/or weighed down  slightly  shortly  thereafter  by  Greg
18074ba9b2SJens Wiklander     Lutz.
19074ba9b2SJens Wiklander 
20074ba9b2SJens Wiklander     AMIX  edition, including the new compaction call-back option, prepared
21074ba9b2SJens Wiklander     by John Walker in July of 1992.
22074ba9b2SJens Wiklander 
23074ba9b2SJens Wiklander     Bug in built-in test program fixed, ANSI compiler warnings eradicated,
24074ba9b2SJens Wiklander     buffer pool validator  implemented,  and  guaranteed  repeatable  test
25074ba9b2SJens Wiklander     added by John Walker in October of 1995.
26074ba9b2SJens Wiklander 
27074ba9b2SJens Wiklander     This program is in the public domain.
28074ba9b2SJens Wiklander 
29074ba9b2SJens Wiklander      1. This is the book of the generations of Adam.   In the day that God
30074ba9b2SJens Wiklander 	created man, in the likeness of God made he him;
31074ba9b2SJens Wiklander      2. Male and female created he them;  and  blessed	them,  and  called
32074ba9b2SJens Wiklander 	their name Adam, in the day when they were created.
33074ba9b2SJens Wiklander      3. And  Adam  lived  an hundred and thirty years,	and begat a son in
34074ba9b2SJens Wiklander 	his own likeness, and after his image; and called his name Seth:
35074ba9b2SJens Wiklander      4. And the days of  Adam  after  he  had  begotten  Seth  were  eight
36074ba9b2SJens Wiklander 	hundred years: and he begat sons and daughters:
37074ba9b2SJens Wiklander      5. And  all  the  days  that Adam lived were nine	hundred and thirty
38074ba9b2SJens Wiklander 	years: and he died.
39074ba9b2SJens Wiklander      6. And Seth lived an hundred and five years, and begat Enos:
40074ba9b2SJens Wiklander      7. And Seth lived after he begat Enos eight hundred and seven  years,
41074ba9b2SJens Wiklander 	and begat sons and daughters:
42074ba9b2SJens Wiklander      8.  And  all the days of Seth were nine hundred and twelve years: and
43074ba9b2SJens Wiklander 	 he died.
44074ba9b2SJens Wiklander      9. And Enos lived ninety years, and begat Cainan:
45074ba9b2SJens Wiklander     10. And Enos lived after he begat  Cainan eight  hundred  and  fifteen
46074ba9b2SJens Wiklander 	years, and begat sons and daughters:
47074ba9b2SJens Wiklander     11. And  all  the days of Enos were nine hundred  and five years:  and
48074ba9b2SJens Wiklander 	he died.
49074ba9b2SJens Wiklander     12. And Cainan lived seventy years and begat Mahalaleel:
50074ba9b2SJens Wiklander     13. And Cainan lived  after he  begat  Mahalaleel  eight  hundred  and
51074ba9b2SJens Wiklander 	forty years, and begat sons and daughters:
52074ba9b2SJens Wiklander     14. And  all the days of Cainan were nine  hundred and ten years:  and
53074ba9b2SJens Wiklander 	he died.
54074ba9b2SJens Wiklander     15. And Mahalaleel lived sixty and five years, and begat Jared:
55074ba9b2SJens Wiklander     16. And Mahalaleel lived  after  he  begat	Jared  eight  hundred  and
56074ba9b2SJens Wiklander 	thirty years, and begat sons and daughters:
57074ba9b2SJens Wiklander     17. And  all  the  days  of Mahalaleel  were eight hundred	ninety and
58074ba9b2SJens Wiklander 	five years: and he died.
59074ba9b2SJens Wiklander     18. And Jared lived an hundred sixty and  two  years,   and  he  begat
60074ba9b2SJens Wiklander 	Enoch:
61074ba9b2SJens Wiklander     19. And  Jared  lived  after he begat Enoch  eight hundred years,  and
62074ba9b2SJens Wiklander 	begat sons and daughters:
63074ba9b2SJens Wiklander     20. And all the days of Jared  were nine hundred sixty and two  years:
64074ba9b2SJens Wiklander 	and he died.
65074ba9b2SJens Wiklander     21. And Enoch lived sixty and five years, and begat Methuselah:
66074ba9b2SJens Wiklander     22. And  Enoch  walked   with  God	after  he  begat Methuselah  three
67074ba9b2SJens Wiklander 	hundred years, and begat sons and daughters:
68074ba9b2SJens Wiklander     23. And all the days of  Enoch  were  three  hundred  sixty  and  five
69074ba9b2SJens Wiklander 	years:
70074ba9b2SJens Wiklander     24. And Enoch walked with God: and he was not; for God took him.
71074ba9b2SJens Wiklander     25. And  Methuselah  lived	an  hundred  eighty and  seven years,  and
72074ba9b2SJens Wiklander 	begat Lamech.
73074ba9b2SJens Wiklander     26. And Methuselah lived after he  begat Lamech seven  hundred  eighty
74074ba9b2SJens Wiklander 	and two years, and begat sons and daughters:
75074ba9b2SJens Wiklander     27. And  all the days of Methuselah  were nine hundred  sixty and nine
76074ba9b2SJens Wiklander 	years: and he died.
77074ba9b2SJens Wiklander     28. And Lamech lived an hundred eighty  and two  years,  and  begat  a
78074ba9b2SJens Wiklander 	son:
79074ba9b2SJens Wiklander     29. And  he called his name Noah, saying,  This same shall	comfort us
80074ba9b2SJens Wiklander 	concerning  our  work and toil of our hands, because of the ground
81074ba9b2SJens Wiklander 	which the LORD hath cursed.
82074ba9b2SJens Wiklander     30. And  Lamech  lived  after  he begat Noah  five hundred	ninety and
83074ba9b2SJens Wiklander 	five years, and begat sons and daughters:
84074ba9b2SJens Wiklander     31. And all the days of Lamech were  seven hundred seventy	and  seven
85074ba9b2SJens Wiklander 	years: and he died.
86074ba9b2SJens Wiklander     32. And  Noah  was five hundred years old:	and Noah begat Shem,  Ham,
87074ba9b2SJens Wiklander 	and Japheth.
88074ba9b2SJens Wiklander 
89074ba9b2SJens Wiklander     And buffers begat buffers, and links begat	links,	and  buffer  pools
90074ba9b2SJens Wiklander     begat  links  to chains of buffer pools containing buffers, and lo the
91074ba9b2SJens Wiklander     buffers and links and pools of buffers and pools of links to chains of
92074ba9b2SJens Wiklander     pools  of  buffers were fruitful and they multiplied and the Operating
93074ba9b2SJens Wiklander     System looked down upon them and said that it was Good.
94074ba9b2SJens Wiklander 
95074ba9b2SJens Wiklander 
96074ba9b2SJens Wiklander     INTRODUCTION
97074ba9b2SJens Wiklander     ============
98074ba9b2SJens Wiklander 
99074ba9b2SJens Wiklander     BGET  is a comprehensive memory allocation package which is easily
100074ba9b2SJens Wiklander     configured to the needs of an application.	BGET is  efficient  in
101074ba9b2SJens Wiklander     both  the  time  needed to allocate and release buffers and in the
102074ba9b2SJens Wiklander     memory  overhead  required	for  buffer   pool   management.    It
103074ba9b2SJens Wiklander     automatically    consolidates   contiguous	 space	 to   minimise
104074ba9b2SJens Wiklander     fragmentation.  BGET is configured	by  compile-time  definitions,
105074ba9b2SJens Wiklander     Major options include:
106074ba9b2SJens Wiklander 
107074ba9b2SJens Wiklander 	*   A  built-in  test  program	to  exercise  BGET   and
108074ba9b2SJens Wiklander 	    demonstrate how the various functions are used.
109074ba9b2SJens Wiklander 
110074ba9b2SJens Wiklander         *   Allocation  by  either the "first fit" or "best fit"
111074ba9b2SJens Wiklander 	    method.
112074ba9b2SJens Wiklander 
113074ba9b2SJens Wiklander 	*   Wiping buffers at release time to catch  code  which
114074ba9b2SJens Wiklander 	    references previously released storage.
115074ba9b2SJens Wiklander 
116074ba9b2SJens Wiklander 	*   Built-in  routines to dump individual buffers or the
117074ba9b2SJens Wiklander 	    entire buffer pool.
118074ba9b2SJens Wiklander 
119074ba9b2SJens Wiklander 	*   Retrieval of allocation and pool size statistics.
120074ba9b2SJens Wiklander 
121074ba9b2SJens Wiklander 	*   Quantisation of buffer sizes to a power  of  two  to
122074ba9b2SJens Wiklander 	    satisfy hardware alignment constraints.
123074ba9b2SJens Wiklander 
124074ba9b2SJens Wiklander 	*   Automatic  pool compaction, growth, and shrinkage by
125074ba9b2SJens Wiklander 	    means of call-backs to user defined functions.
126074ba9b2SJens Wiklander 
127074ba9b2SJens Wiklander     Applications  of  BGET  can  range	from  storage  management   in
128074ba9b2SJens Wiklander     ROM-based  embedded programs to providing the framework upon which
129074ba9b2SJens Wiklander     a  multitasking  system  incorporating   garbage   collection   is
130074ba9b2SJens Wiklander     constructed.   BGET  incorporates  extensive  internal consistency
131074ba9b2SJens Wiklander     checking using the <assert.h> mechanism; all these checks  can  be
132074ba9b2SJens Wiklander     turned off by compiling with NDEBUG defined, yielding a version of
133074ba9b2SJens Wiklander     BGET with minimal size and maximum speed.
134074ba9b2SJens Wiklander 
135074ba9b2SJens Wiklander     The  basic	algorithm  underlying  BGET  has withstood the test of
136074ba9b2SJens Wiklander     time;  more  than  25  years   have   passed   since   the	 first
137074ba9b2SJens Wiklander     implementation  of	this  code.  And yet, it is substantially more
138074ba9b2SJens Wiklander     efficient than the native allocation  schemes  of  many  operating
139074ba9b2SJens Wiklander     systems: the Macintosh and Microsoft Windows to name two, on which
140074ba9b2SJens Wiklander     programs have obtained substantial speed-ups by layering  BGET  as
141074ba9b2SJens Wiklander     an application level memory manager atop the underlying system's.
142074ba9b2SJens Wiklander 
143074ba9b2SJens Wiklander     BGET has been implemented on the largest mainframes and the lowest
144074ba9b2SJens Wiklander     of	microprocessors.   It  has served as the core for multitasking
145074ba9b2SJens Wiklander     operating systems, multi-thread applications, embedded software in
146074ba9b2SJens Wiklander     data  network switching processors, and a host of C programs.  And
147074ba9b2SJens Wiklander     while it has accreted flexibility and additional options over  the
148074ba9b2SJens Wiklander     years,  it	remains  fast, memory efficient, portable, and easy to
149074ba9b2SJens Wiklander     integrate into your program.
150074ba9b2SJens Wiklander 
151074ba9b2SJens Wiklander 
152074ba9b2SJens Wiklander     BGET IMPLEMENTATION ASSUMPTIONS
153074ba9b2SJens Wiklander     ===============================
154074ba9b2SJens Wiklander 
155074ba9b2SJens Wiklander     BGET is written in as portable a dialect of C  as  possible.   The
156074ba9b2SJens Wiklander     only   fundamental	 assumption   about  the  underlying  hardware
157074ba9b2SJens Wiklander     architecture is that memory is allocated is a linear  array  which
158074ba9b2SJens Wiklander     can  be  addressed  as a vector of C "char" objects.  On segmented
159074ba9b2SJens Wiklander     address space architectures, this generally means that BGET should
160074ba9b2SJens Wiklander     be used to allocate storage within a single segment (although some
161074ba9b2SJens Wiklander     compilers	simulate   linear   address   spaces   on    segmented
162074ba9b2SJens Wiklander     architectures).   On  segmented  architectures,  then, BGET buffer
163074ba9b2SJens Wiklander     pools  may not be larger than a segment, but since BGET allows any
164074ba9b2SJens Wiklander     number of separate buffer pools, there is no limit	on  the  total
165074ba9b2SJens Wiklander     storage  which  can  be  managed,  only  on the largest individual
166074ba9b2SJens Wiklander     object which can be allocated.  Machines  with  a  linear  address
167074ba9b2SJens Wiklander     architecture,  such  as  the VAX, 680x0, Sparc, MIPS, or the Intel
168074ba9b2SJens Wiklander     80386 and above in native mode, may use BGET without restriction.
169074ba9b2SJens Wiklander 
170074ba9b2SJens Wiklander 
171074ba9b2SJens Wiklander     GETTING STARTED WITH BGET
172074ba9b2SJens Wiklander     =========================
173074ba9b2SJens Wiklander 
174074ba9b2SJens Wiklander     Although BGET can be configured in a multitude of fashions,  there
175074ba9b2SJens Wiklander     are  three	basic  ways  of  working  with	BGET.	The  functions
176074ba9b2SJens Wiklander     mentioned below are documented in the following  section.	Please
177074ba9b2SJens Wiklander     excuse  the  forward  references which are made in the interest of
178074ba9b2SJens Wiklander     providing a roadmap to guide you  to  the  BGET  functions  you're
179074ba9b2SJens Wiklander     likely to need.
180074ba9b2SJens Wiklander 
181074ba9b2SJens Wiklander     Embedded Applications
182074ba9b2SJens Wiklander     ---------------------
183074ba9b2SJens Wiklander 
184074ba9b2SJens Wiklander     Embedded applications  typically  have  a  fixed  area  of	memory
185074ba9b2SJens Wiklander     dedicated  to  buffer  allocation (often in a separate RAM address
186074ba9b2SJens Wiklander     space distinct from the ROM that contains  the  executable	code).
187074ba9b2SJens Wiklander     To	use  BGET in such an environment, simply call bpool() with the
188074ba9b2SJens Wiklander     start address and length of the buffer  pool  area	in  RAM,  then
189074ba9b2SJens Wiklander     allocate  buffers  with  bget()  and  release  them  with  brel().
190074ba9b2SJens Wiklander     Embedded applications with very limited RAM but abundant CPU speed
191074ba9b2SJens Wiklander     may  benefit  by configuring BGET for BestFit allocation (which is
192074ba9b2SJens Wiklander     usually not worth it in other environments).
193074ba9b2SJens Wiklander 
194074ba9b2SJens Wiklander     Malloc() Emulation
195074ba9b2SJens Wiklander     ------------------
196074ba9b2SJens Wiklander 
197074ba9b2SJens Wiklander     If the C library malloc() function is too  slow,  not  present  in
198074ba9b2SJens Wiklander     your  development environment (for example, an a native Windows or
199074ba9b2SJens Wiklander     Macintosh program), or otherwise unsuitable, you  can  replace  it
200074ba9b2SJens Wiklander     with  BGET.  Initially define a buffer pool of an appropriate size
201074ba9b2SJens Wiklander     with bpool()--usually obtained by making a call to	the  operating
202074ba9b2SJens Wiklander     system's  low-level  memory allocator.  Then allocate buffers with
203074ba9b2SJens Wiklander     bget(), bgetz(), and bgetr() (the last two permit  the  allocation
204074ba9b2SJens Wiklander     of	buffers initialised to zero and [inefficient] re-allocation of
205074ba9b2SJens Wiklander     existing buffers for  compatibility  with  C  library  functions).
206074ba9b2SJens Wiklander     Release buffers by calling brel().	If a buffer allocation request
207074ba9b2SJens Wiklander     fails, obtain more storage from the underlying  operating  system,
208074ba9b2SJens Wiklander     add it to the buffer pool by another call to bpool(), and continue
209074ba9b2SJens Wiklander     execution.
210074ba9b2SJens Wiklander 
211074ba9b2SJens Wiklander     Automatic Storage Management
212074ba9b2SJens Wiklander     ----------------------------
213074ba9b2SJens Wiklander 
214074ba9b2SJens Wiklander     You can use BGET as your application's native memory  manager  and
215074ba9b2SJens Wiklander     implement  automatic  storage  pool  expansion,  contraction,  and
216074ba9b2SJens Wiklander     optionally application-specific  memory  compaction  by  compiling
217074ba9b2SJens Wiklander     BGET  with	the  BECtl  variable defined, then calling bectl() and
218074ba9b2SJens Wiklander     supplying  functions  for  storage	compaction,  acquisition,  and
219074ba9b2SJens Wiklander     release,  as  well as a standard pool expansion increment.	All of
220074ba9b2SJens Wiklander     these functions are optional (although it doesn't make much  sense
221074ba9b2SJens Wiklander     to	provide  a  release  function without an acquisition function,
222074ba9b2SJens Wiklander     does it?).	Once the call-back functions have  been  defined  with
223074ba9b2SJens Wiklander     bectl(),  you simply use bget() and brel() to allocate and release
224074ba9b2SJens Wiklander     storage as before.	You can supply an  initial  buffer  pool  with
225074ba9b2SJens Wiklander     bpool()  or  rely  on  automatic  allocation to acquire the entire
226074ba9b2SJens Wiklander     pool.  When a call on  bget()  cannot  be  satisfied,  BGET  first
227074ba9b2SJens Wiklander     checks  if	a compaction function has been supplied.  If so, it is
228074ba9b2SJens Wiklander     called (with the space required to satisfy the allocation  request
229074ba9b2SJens Wiklander     and a sequence number to allow the compaction routine to be called
230074ba9b2SJens Wiklander     successively without looping).  If the compaction function is able
231074ba9b2SJens Wiklander     to  free any storage (it needn't know whether the storage it freed
232074ba9b2SJens Wiklander     was adequate) it should return a  nonzero  value,  whereupon  BGET
233074ba9b2SJens Wiklander     will retry the allocation request and, if it fails again, call the
234074ba9b2SJens Wiklander     compaction function again with the next-higher sequence number.
235074ba9b2SJens Wiklander 
236074ba9b2SJens Wiklander     If	the  compaction  function  returns zero, indicating failure to
237074ba9b2SJens Wiklander     free space, or no compaction function is defined, BGET next  tests
238074ba9b2SJens Wiklander     whether  a	non-NULL  allocation function was supplied to bectl().
239074ba9b2SJens Wiklander     If so, that function is called with  an  argument  indicating  how
240074ba9b2SJens Wiklander     many  bytes  of  additional  space are required.  This will be the
241074ba9b2SJens Wiklander     standard pool expansion increment supplied in the call to  bectl()
242074ba9b2SJens Wiklander     unless  the  original  bget()  call requested a buffer larger than
243074ba9b2SJens Wiklander     this; buffers larger than the standard pool block can  be  managed
244074ba9b2SJens Wiklander     "off  the books" by BGET in this mode.  If the allocation function
245074ba9b2SJens Wiklander     succeeds in obtaining the storage, it returns a pointer to the new
246074ba9b2SJens Wiklander     block  and	BGET  expands  the  buffer  pool;  if  it  fails,  the
247074ba9b2SJens Wiklander     allocation request fails and returns NULL to  the  caller.	 If  a
248074ba9b2SJens Wiklander     non-NULL  release  function  is  supplied,	expansion blocks which
249074ba9b2SJens Wiklander     become totally empty are released  to  the	global	free  pool  by
250074ba9b2SJens Wiklander     passing their addresses to the release function.
251074ba9b2SJens Wiklander 
252074ba9b2SJens Wiklander     Equipped  with  appropriate  allocation,  release,	and compaction
253074ba9b2SJens Wiklander     functions, BGET can be used as part of very  sophisticated	memory
254074ba9b2SJens Wiklander     management	 strategies,  including  garbage  collection.	(Note,
255074ba9b2SJens Wiklander     however, that BGET is *not* a garbage  collector  by  itself,  and
256074ba9b2SJens Wiklander     that  developing  such a system requires much additional logic and
257074ba9b2SJens Wiklander     careful design of the application's memory allocation strategy.)
258074ba9b2SJens Wiklander 
259074ba9b2SJens Wiklander 
260074ba9b2SJens Wiklander     BGET FUNCTION DESCRIPTIONS
261074ba9b2SJens Wiklander     ==========================
262074ba9b2SJens Wiklander 
263074ba9b2SJens Wiklander     Functions implemented in this file (some are enabled by certain of
264074ba9b2SJens Wiklander     the optional settings below):
265074ba9b2SJens Wiklander 
266074ba9b2SJens Wiklander 	    void bpool(void *buffer, bufsize len);
267074ba9b2SJens Wiklander 
268074ba9b2SJens Wiklander     Create a buffer pool of <len> bytes, using the storage starting at
269074ba9b2SJens Wiklander     <buffer>.	You  can  call	bpool()  subsequently  to   contribute
270074ba9b2SJens Wiklander     additional storage to the overall buffer pool.
271074ba9b2SJens Wiklander 
272074ba9b2SJens Wiklander 	    void *bget(bufsize size);
273074ba9b2SJens Wiklander 
274074ba9b2SJens Wiklander     Allocate  a  buffer of <size> bytes.  The address of the buffer is
275074ba9b2SJens Wiklander     returned, or NULL if insufficient memory was available to allocate
276074ba9b2SJens Wiklander     the buffer.
277074ba9b2SJens Wiklander 
278074ba9b2SJens Wiklander 	    void *bgetz(bufsize size);
279074ba9b2SJens Wiklander 
280074ba9b2SJens Wiklander     Allocate a buffer of <size> bytes and clear it to all zeroes.  The
281074ba9b2SJens Wiklander     address of the buffer is returned, or NULL if insufficient	memory
282074ba9b2SJens Wiklander     was available to allocate the buffer.
283074ba9b2SJens Wiklander 
284074ba9b2SJens Wiklander 	    void *bgetr(void *buffer, bufsize newsize);
285074ba9b2SJens Wiklander 
286074ba9b2SJens Wiklander     Reallocate a buffer previously allocated by bget(),  changing  its
287074ba9b2SJens Wiklander     size  to  <newsize>  and  preserving  all  existing data.  NULL is
288074ba9b2SJens Wiklander     returned if insufficient memory is	available  to  reallocate  the
289074ba9b2SJens Wiklander     buffer, in which case the original buffer remains intact.
290074ba9b2SJens Wiklander 
291074ba9b2SJens Wiklander 	    void brel(void *buf);
292074ba9b2SJens Wiklander 
293074ba9b2SJens Wiklander     Return  the  buffer  <buf>, previously allocated by bget(), to the
294074ba9b2SJens Wiklander     free space pool.
295074ba9b2SJens Wiklander 
296074ba9b2SJens Wiklander 	    void bectl(int (*compact)(bufsize sizereq, int sequence),
297074ba9b2SJens Wiklander 		       void *(*acquire)(bufsize size),
298074ba9b2SJens Wiklander 		       void (*release)(void *buf),
299074ba9b2SJens Wiklander 		       bufsize pool_incr);
300074ba9b2SJens Wiklander 
301074ba9b2SJens Wiklander     Expansion control: specify functions through which the package may
302074ba9b2SJens Wiklander     compact  storage  (or  take  other	appropriate  action)  when  an
303074ba9b2SJens Wiklander     allocation	request  fails,  and  optionally automatically acquire
304074ba9b2SJens Wiklander     storage for expansion blocks  when	necessary,  and  release  such
305074ba9b2SJens Wiklander     blocks when they become empty.  If <compact> is non-NULL, whenever
306074ba9b2SJens Wiklander     a buffer allocation request fails, the <compact> function will  be
307074ba9b2SJens Wiklander     called with arguments specifying the number of bytes (total buffer
308074ba9b2SJens Wiklander     size,  including  header  overhead)  required   to	 satisfy   the
309074ba9b2SJens Wiklander     allocation request, and a sequence number indicating the number of
310074ba9b2SJens Wiklander     consecutive  calls	on  <compact>  attempting  to	satisfy   this
311074ba9b2SJens Wiklander     allocation	request.   The sequence number is 1 for the first call
312074ba9b2SJens Wiklander     on <compact> for a given allocation  request,  and	increments  on
313074ba9b2SJens Wiklander     subsequent	calls,	permitting  the  <compact>  function  to  take
314074ba9b2SJens Wiklander     increasingly dire measures in an attempt to free up  storage.   If
315074ba9b2SJens Wiklander     the  <compact>  function  returns  a nonzero value, the allocation
316074ba9b2SJens Wiklander     attempt is re-tried.  If <compact> returns 0 (as  it  must	if  it
317074ba9b2SJens Wiklander     isn't  able  to  release  any  space  or add storage to the buffer
318074ba9b2SJens Wiklander     pool), the allocation request fails, which can  trigger  automatic
319074ba9b2SJens Wiklander     pool expansion if the <acquire> argument is non-NULL.  At the time
320074ba9b2SJens Wiklander     the  <compact>  function  is  called,  the	state  of  the	buffer
321074ba9b2SJens Wiklander     allocator  is  identical  to  that	at  the  moment the allocation
322074ba9b2SJens Wiklander     request was made; consequently, the <compact>  function  may  call
323074ba9b2SJens Wiklander     brel(), bpool(), bstats(), and/or directly manipulate  the	buffer
324074ba9b2SJens Wiklander     pool  in  any  manner which would be valid were the application in
325074ba9b2SJens Wiklander     control.  This does not, however, relieve the  <compact>  function
326074ba9b2SJens Wiklander     of the need to ensure that whatever actions it takes do not change
327074ba9b2SJens Wiklander     things   underneath  the  application  that  made  the  allocation
328074ba9b2SJens Wiklander     request.  For example, a <compact> function that released a buffer
329074ba9b2SJens Wiklander     in	the  process  of  being reallocated with bgetr() would lead to
330074ba9b2SJens Wiklander     disaster.  Implementing a safe and effective  <compact>  mechanism
331074ba9b2SJens Wiklander     requires  careful  design of an application's memory architecture,
332074ba9b2SJens Wiklander     and cannot generally be easily retrofitted into existing code.
333074ba9b2SJens Wiklander 
334074ba9b2SJens Wiklander     If <acquire> is non-NULL, that function will be called whenever an
335074ba9b2SJens Wiklander     allocation	request  fails.  If the <acquire> function succeeds in
336074ba9b2SJens Wiklander     allocating the requested space and returns a pointer  to  the  new
337074ba9b2SJens Wiklander     area,  allocation will proceed using the expanded buffer pool.  If
338074ba9b2SJens Wiklander     <acquire> cannot obtain the requested space, it should return NULL
339074ba9b2SJens Wiklander     and   the	entire	allocation  process  will  fail.   <pool_incr>
340074ba9b2SJens Wiklander     specifies the normal expansion block size.	Providing an <acquire>
341074ba9b2SJens Wiklander     function will cause subsequent bget()  requests  for  buffers  too
342074ba9b2SJens Wiklander     large  to  be  managed in the linked-block scheme (in other words,
343074ba9b2SJens Wiklander     larger than <pool_incr> minus the buffer overhead) to be satisfied
344074ba9b2SJens Wiklander     directly by calls to the <acquire> function.  Automatic release of
345074ba9b2SJens Wiklander     empty pool blocks will occur only if all pool blocks in the system
346074ba9b2SJens Wiklander     are the size given by <pool_incr>.
347074ba9b2SJens Wiklander 
348074ba9b2SJens Wiklander 	    void bstats(bufsize *curalloc, bufsize *totfree,
349074ba9b2SJens Wiklander 			bufsize *maxfree, long *nget, long *nrel);
350074ba9b2SJens Wiklander 
351074ba9b2SJens Wiklander     The amount	of  space  currently  allocated  is  stored  into  the
352074ba9b2SJens Wiklander     variable  pointed  to by <curalloc>.  The total free space (sum of
353074ba9b2SJens Wiklander     all free blocks in the pool) is stored into the  variable  pointed
354074ba9b2SJens Wiklander     to	by  <totfree>, and the size of the largest single block in the
355074ba9b2SJens Wiklander     free space	pool  is  stored  into	the  variable  pointed	to  by
356074ba9b2SJens Wiklander     <maxfree>.	 The  variables  pointed  to  by <nget> and <nrel> are
357074ba9b2SJens Wiklander     filled, respectively, with	the  number  of  successful  (non-NULL
358074ba9b2SJens Wiklander     return) bget() calls and the number of brel() calls.
359074ba9b2SJens Wiklander 
360074ba9b2SJens Wiklander 	    void bstatse(bufsize *pool_incr, long *npool,
361074ba9b2SJens Wiklander 			 long *npget, long *nprel,
362074ba9b2SJens Wiklander 			 long *ndget, long *ndrel);
363074ba9b2SJens Wiklander 
364074ba9b2SJens Wiklander     Extended  statistics: The expansion block size will be stored into
365074ba9b2SJens Wiklander     the variable pointed to by <pool_incr>, or the negative thereof if
366074ba9b2SJens Wiklander     automatic  expansion  block  releases are disabled.  The number of
367074ba9b2SJens Wiklander     currently active pool blocks will  be  stored  into  the  variable
368074ba9b2SJens Wiklander     pointed  to  by  <npool>.  The variables pointed to by <npget> and
369074ba9b2SJens Wiklander     <nprel> will be filled with, respectively, the number of expansion
370074ba9b2SJens Wiklander     block   acquisitions   and	releases  which  have  occurred.   The
371074ba9b2SJens Wiklander     variables pointed to by <ndget> and <ndrel> will  be  filled  with
372074ba9b2SJens Wiklander     the  number  of  bget()  and  brel()  calls, respectively, managed
373074ba9b2SJens Wiklander     through blocks directly allocated by the acquisition  and  release
374074ba9b2SJens Wiklander     functions.
375074ba9b2SJens Wiklander 
376074ba9b2SJens Wiklander 	    void bufdump(void *buf);
377074ba9b2SJens Wiklander 
378074ba9b2SJens Wiklander     The buffer pointed to by <buf> is dumped on standard output.
379074ba9b2SJens Wiklander 
380074ba9b2SJens Wiklander 	    void bpoold(void *pool, int dumpalloc, int dumpfree);
381074ba9b2SJens Wiklander 
382074ba9b2SJens Wiklander     All buffers in the buffer pool <pool>, previously initialised by a
383074ba9b2SJens Wiklander     call on bpool(), are listed in ascending memory address order.  If
384074ba9b2SJens Wiklander     <dumpalloc> is nonzero, the  contents  of  allocated  buffers  are
385074ba9b2SJens Wiklander     dumped;  if <dumpfree> is nonzero, the contents of free blocks are
386074ba9b2SJens Wiklander     dumped.
387074ba9b2SJens Wiklander 
388074ba9b2SJens Wiklander 	    int bpoolv(void *pool);
389074ba9b2SJens Wiklander 
390074ba9b2SJens Wiklander     The  named	buffer	pool,  previously  initialised	by  a  call on
391074ba9b2SJens Wiklander     bpool(), is validated for bad pointers, overwritten data, etc.  If
392074ba9b2SJens Wiklander     compiled with NDEBUG not defined, any error generates an assertion
393074ba9b2SJens Wiklander     failure.  Otherwise 1 is returned if the pool is valid,  0	if  an
394074ba9b2SJens Wiklander     error is found.
395074ba9b2SJens Wiklander 
396074ba9b2SJens Wiklander 
397074ba9b2SJens Wiklander     BGET CONFIGURATION
398074ba9b2SJens Wiklander     ==================
399074ba9b2SJens Wiklander */
400074ba9b2SJens Wiklander 
401074ba9b2SJens Wiklander /*
402074ba9b2SJens Wiklander  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
403074ba9b2SJens Wiklander  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
404074ba9b2SJens Wiklander  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
405074ba9b2SJens Wiklander  * IN NO EVENT SHALL ST BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
406074ba9b2SJens Wiklander  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
407074ba9b2SJens Wiklander  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
408074ba9b2SJens Wiklander  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
409074ba9b2SJens Wiklander  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
410074ba9b2SJens Wiklander  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
411074ba9b2SJens Wiklander  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
412074ba9b2SJens Wiklander  */
413074ba9b2SJens Wiklander 
414074ba9b2SJens Wiklander /* #define BGET_ENABLE_ALL_OPTIONS */
415074ba9b2SJens Wiklander #ifdef BGET_ENABLE_OPTION
416074ba9b2SJens Wiklander #define TestProg    20000	      /* Generate built-in test program
417074ba9b2SJens Wiklander 					 if defined.  The value specifies
418074ba9b2SJens Wiklander 					 how many buffer allocation attempts
419074ba9b2SJens Wiklander 					 the test program should make. */
420074ba9b2SJens Wiklander 
421074ba9b2SJens Wiklander #define SizeQuant   4		      /* Buffer allocation size quantum:
422074ba9b2SJens Wiklander 					 all buffers allocated are a
423074ba9b2SJens Wiklander 					 multiple of this size.  This
424074ba9b2SJens Wiklander 					 MUST be a power of two. */
425074ba9b2SJens Wiklander 
426074ba9b2SJens Wiklander #define BufDump     1		      /* Define this symbol to enable the
427074ba9b2SJens Wiklander 					 bpoold() function which dumps the
428074ba9b2SJens Wiklander 					 buffers in a buffer pool. */
429074ba9b2SJens Wiklander 
430074ba9b2SJens Wiklander #define BufValid    1		      /* Define this symbol to enable the
431074ba9b2SJens Wiklander 					 bpoolv() function for validating
432074ba9b2SJens Wiklander 					 a buffer pool. */
433074ba9b2SJens Wiklander 
434074ba9b2SJens Wiklander #define DumpData    1		      /* Define this symbol to enable the
435074ba9b2SJens Wiklander 					 bufdump() function which allows
436074ba9b2SJens Wiklander 					 dumping the contents of an allocated
437074ba9b2SJens Wiklander 					 or free buffer. */
438074ba9b2SJens Wiklander 
439074ba9b2SJens Wiklander #define BufStats    1		      /* Define this symbol to enable the
440074ba9b2SJens Wiklander 					 bstats() function which calculates
441074ba9b2SJens Wiklander 					 the total free space in the buffer
442074ba9b2SJens Wiklander 					 pool, the largest available
443074ba9b2SJens Wiklander 					 buffer, and the total space
444074ba9b2SJens Wiklander 					 currently allocated. */
445074ba9b2SJens Wiklander 
446074ba9b2SJens Wiklander #define FreeWipe    1		      /* Wipe free buffers to a guaranteed
447074ba9b2SJens Wiklander 					 pattern of garbage to trip up
448074ba9b2SJens Wiklander 					 miscreants who attempt to use
449074ba9b2SJens Wiklander 					 pointers into released buffers. */
450074ba9b2SJens Wiklander 
451074ba9b2SJens Wiklander #define BestFit     1		      /* Use a best fit algorithm when
452074ba9b2SJens Wiklander 					 searching for space for an
453074ba9b2SJens Wiklander 					 allocation request.  This uses
454074ba9b2SJens Wiklander 					 memory more efficiently, but
455074ba9b2SJens Wiklander 					 allocation will be much slower. */
456074ba9b2SJens Wiklander 
457074ba9b2SJens Wiklander #define BECtl	    1		      /* Define this symbol to enable the
458074ba9b2SJens Wiklander 					 bectl() function for automatic
459074ba9b2SJens Wiklander 					 pool space control.  */
460074ba9b2SJens Wiklander #endif
461074ba9b2SJens Wiklander 
462074ba9b2SJens Wiklander #include <stdio.h>
4634e570655SJerome Forissier #include <stdbool.h>
464074ba9b2SJens Wiklander 
465074ba9b2SJens Wiklander #ifdef lint
466074ba9b2SJens Wiklander #define NDEBUG			      /* Exits in asserts confuse lint */
467074ba9b2SJens Wiklander /* LINTLIBRARY */                     /* Don't complain about def, no ref */
468074ba9b2SJens Wiklander extern char *sprintf();               /* Sun includes don't define sprintf */
469074ba9b2SJens Wiklander #endif
470074ba9b2SJens Wiklander 
471074ba9b2SJens Wiklander #include <assert.h>
472074ba9b2SJens Wiklander #include <memory.h>
473074ba9b2SJens Wiklander 
474074ba9b2SJens Wiklander #ifdef BufDump			      /* BufDump implies DumpData */
475074ba9b2SJens Wiklander #ifndef DumpData
476074ba9b2SJens Wiklander #define DumpData    1
477074ba9b2SJens Wiklander #endif
478074ba9b2SJens Wiklander #endif
479074ba9b2SJens Wiklander 
480074ba9b2SJens Wiklander #ifdef DumpData
481074ba9b2SJens Wiklander #include <ctype.h>
482074ba9b2SJens Wiklander #endif
483074ba9b2SJens Wiklander 
484bde8a250SJoakim Bech #ifdef __KERNEL__
485bde8a250SJoakim Bech #ifdef CFG_CORE_BGET_BESTFIT
486bde8a250SJoakim Bech #define BestFit 1
487bde8a250SJoakim Bech #endif
488bde8a250SJoakim Bech #endif
489bde8a250SJoakim Bech 
490074ba9b2SJens Wiklander /*  Declare the interface, including the requested buffer size type,
491074ba9b2SJens Wiklander     bufsize.  */
492074ba9b2SJens Wiklander 
493074ba9b2SJens Wiklander #include "bget.h"
494074ba9b2SJens Wiklander 
495074ba9b2SJens Wiklander #define MemSize     int 	      /* Type for size arguments to memxxx()
496074ba9b2SJens Wiklander 					 functions such as memcmp(). */
497074ba9b2SJens Wiklander 
498074ba9b2SJens Wiklander /* Queue links */
499074ba9b2SJens Wiklander 
500074ba9b2SJens Wiklander struct qlinks {
501074ba9b2SJens Wiklander     struct bfhead *flink;	      /* Forward link */
502074ba9b2SJens Wiklander     struct bfhead *blink;	      /* Backward link */
503074ba9b2SJens Wiklander };
504074ba9b2SJens Wiklander 
505074ba9b2SJens Wiklander /* Header in allocated and free buffers */
506074ba9b2SJens Wiklander 
507074ba9b2SJens Wiklander struct bhead {
508074ba9b2SJens Wiklander     bufsize prevfree;		      /* Relative link back to previous
509074ba9b2SJens Wiklander 					 free buffer in memory or 0 if
510074ba9b2SJens Wiklander 					 previous buffer is allocated.	*/
511074ba9b2SJens Wiklander     bufsize bsize;		      /* Buffer size: positive if free,
512074ba9b2SJens Wiklander 					 negative if allocated. */
513074ba9b2SJens Wiklander };
514074ba9b2SJens Wiklander #define BH(p)	((struct bhead *) (p))
515074ba9b2SJens Wiklander 
516074ba9b2SJens Wiklander /*  Header in directly allocated buffers (by acqfcn) */
517074ba9b2SJens Wiklander 
518074ba9b2SJens Wiklander struct bdhead {
519074ba9b2SJens Wiklander     bufsize tsize;		      /* Total size, including overhead */
520cc5981b2SJens Wiklander     bufsize offs;		      /* Offset from allocated buffer */
521074ba9b2SJens Wiklander     struct bhead bh;		      /* Common header */
522074ba9b2SJens Wiklander };
523074ba9b2SJens Wiklander #define BDH(p)	((struct bdhead *) (p))
524074ba9b2SJens Wiklander 
525074ba9b2SJens Wiklander /* Header in free buffers */
526074ba9b2SJens Wiklander 
527074ba9b2SJens Wiklander struct bfhead {
528074ba9b2SJens Wiklander     struct bhead bh;		      /* Common allocated/free header */
529074ba9b2SJens Wiklander     struct qlinks ql;		      /* Links on free list */
530074ba9b2SJens Wiklander };
531074ba9b2SJens Wiklander #define BFH(p)	((struct bfhead *) (p))
532074ba9b2SJens Wiklander 
533b7f0111dSVolodymyr Babchuk /* Poolset definition */
534b7f0111dSVolodymyr Babchuk struct bpoolset {
535b7f0111dSVolodymyr Babchuk     struct bfhead freelist;
536074ba9b2SJens Wiklander #ifdef BufStats
537b7f0111dSVolodymyr Babchuk     bufsize totalloc;		      /* Total space currently allocated */
538b7f0111dSVolodymyr Babchuk     long numget;		      /* Number of bget() calls */
539b7f0111dSVolodymyr Babchuk     long numrel;		      /* Number of brel() calls */
540074ba9b2SJens Wiklander #ifdef BECtl
541b7f0111dSVolodymyr Babchuk     long numpblk;		      /* Number of pool blocks */
542b7f0111dSVolodymyr Babchuk     long numpget;		      /* Number of block gets and rels */
543b7f0111dSVolodymyr Babchuk     long numprel;
544b7f0111dSVolodymyr Babchuk     long numdget;		      /* Number of direct gets and rels */
545b7f0111dSVolodymyr Babchuk     long numdrel;
546074ba9b2SJens Wiklander #endif /* BECtl */
547074ba9b2SJens Wiklander #endif /* BufStats */
548074ba9b2SJens Wiklander 
549074ba9b2SJens Wiklander #ifdef BECtl
550074ba9b2SJens Wiklander     /* Automatic expansion block management functions */
551074ba9b2SJens Wiklander 
552b7f0111dSVolodymyr Babchuk     int (*compfcn) _((bufsize sizereq, int sequence));
553b7f0111dSVolodymyr Babchuk     void *(*acqfcn) _((bufsize size));
554b7f0111dSVolodymyr Babchuk     void (*relfcn) _((void *buf));
555074ba9b2SJens Wiklander 
556b7f0111dSVolodymyr Babchuk     bufsize exp_incr;		      /* Expansion block size */
557b7f0111dSVolodymyr Babchuk     bufsize pool_len;		      /* 0: no bpool calls have been made
558074ba9b2SJens Wiklander 					 -1: not all pool blocks are
559074ba9b2SJens Wiklander 					     the same size
560074ba9b2SJens Wiklander 					 >0: (common) block size for all
561074ba9b2SJens Wiklander 					     bpool calls made so far
562074ba9b2SJens Wiklander 				      */
563074ba9b2SJens Wiklander #endif
564b7f0111dSVolodymyr Babchuk };
565074ba9b2SJens Wiklander 
566074ba9b2SJens Wiklander /*  Minimum allocation quantum: */
567074ba9b2SJens Wiklander 
568074ba9b2SJens Wiklander #define QLSize	(sizeof(struct qlinks))
569074ba9b2SJens Wiklander #define SizeQ	((SizeQuant > QLSize) ? SizeQuant : QLSize)
570074ba9b2SJens Wiklander 
571074ba9b2SJens Wiklander #define V   (void)		      /* To denote unwanted returned values */
572074ba9b2SJens Wiklander 
573074ba9b2SJens Wiklander /* End sentinel: value placed in bsize field of dummy block delimiting
574074ba9b2SJens Wiklander    end of pool block.  The most negative number which will  fit  in  a
575074ba9b2SJens Wiklander    bufsize, defined in a way that the compiler will accept. */
576074ba9b2SJens Wiklander 
577074ba9b2SJens Wiklander #define ESent	((bufsize) (-(((1L << (sizeof(bufsize) * 8 - 2)) - 1) * 2) - 2))
578074ba9b2SJens Wiklander 
579*17967299SJens Wiklander static bufsize buf_get_pos(struct bfhead *bf, bufsize align, bufsize hdr_size,
580*17967299SJens Wiklander                            bufsize size)
581cc5981b2SJens Wiklander {
582cc5981b2SJens Wiklander     unsigned long buf = 0;
583cc5981b2SJens Wiklander     bufsize pos = 0;
584cc5981b2SJens Wiklander 
585cc5981b2SJens Wiklander     if (bf->bh.bsize < size)
586cc5981b2SJens Wiklander        return -1;
587cc5981b2SJens Wiklander 
588cc5981b2SJens Wiklander     /*
589*17967299SJens Wiklander      * plus sizeof(struct bhead) and hdr_size since buf will follow just
590*17967299SJens Wiklander      * after a struct bhead and an eventual extra header.
591cc5981b2SJens Wiklander      */
592*17967299SJens Wiklander     buf = (unsigned long)bf + bf->bh.bsize - size + sizeof(struct bhead) +
593*17967299SJens Wiklander           hdr_size;
594cc5981b2SJens Wiklander     buf &= ~(align - 1);
595*17967299SJens Wiklander     pos = buf - (unsigned long)bf - sizeof(struct bhead) - hdr_size;
596cc5981b2SJens Wiklander 
597cc5981b2SJens Wiklander     if (pos == 0) /* exact match */
598cc5981b2SJens Wiklander         return pos;
599cc5981b2SJens Wiklander     if (pos >= SizeQ + sizeof(struct bhead)) /* room for an empty buffer */
600cc5981b2SJens Wiklander         return pos;
601cc5981b2SJens Wiklander 
602cc5981b2SJens Wiklander     return -1;
603cc5981b2SJens Wiklander }
604cc5981b2SJens Wiklander 
605074ba9b2SJens Wiklander /*  BGET  --  Allocate a buffer.  */
606074ba9b2SJens Wiklander 
607*17967299SJens Wiklander void *bget(requested_align, hdr_size, requested_size, poolset)
608cc5981b2SJens Wiklander   bufsize requested_align;
609*17967299SJens Wiklander   bufsize hdr_size;
610074ba9b2SJens Wiklander   bufsize requested_size;
611b7f0111dSVolodymyr Babchuk   struct bpoolset *poolset;
612074ba9b2SJens Wiklander {
613cc5981b2SJens Wiklander     bufsize align = requested_align;
614074ba9b2SJens Wiklander     bufsize size = requested_size;
615cc5981b2SJens Wiklander     bufsize pos;
616074ba9b2SJens Wiklander     struct bfhead *b;
617074ba9b2SJens Wiklander #ifdef BestFit
618074ba9b2SJens Wiklander     struct bfhead *best;
619074ba9b2SJens Wiklander #endif
620074ba9b2SJens Wiklander     void *buf;
621074ba9b2SJens Wiklander #ifdef BECtl
622074ba9b2SJens Wiklander     int compactseq = 0;
623074ba9b2SJens Wiklander #endif
624074ba9b2SJens Wiklander 
625074ba9b2SJens Wiklander     assert(size > 0);
626*17967299SJens Wiklander     COMPILE_TIME_ASSERT(BGET_HDR_QUANTUM == SizeQ);
627*17967299SJens Wiklander 
628cc5981b2SJens Wiklander     if (align < 0 || (align > 0 && !IS_POWER_OF_TWO((unsigned long)align)))
629cc5981b2SJens Wiklander         return NULL;
630*17967299SJens Wiklander     if (hdr_size % BGET_HDR_QUANTUM != 0)
631*17967299SJens Wiklander         return NULL;
632074ba9b2SJens Wiklander 
633074ba9b2SJens Wiklander     if (size < SizeQ) { 	      /* Need at least room for the */
634074ba9b2SJens Wiklander 	size = SizeQ;		      /*    queue links.  */
635074ba9b2SJens Wiklander     }
636cc5981b2SJens Wiklander     if (align < SizeQ)
637cc5981b2SJens Wiklander         align = SizeQ;
638074ba9b2SJens Wiklander #ifdef SizeQuant
639074ba9b2SJens Wiklander #if SizeQuant > 1
6407539e8c3SPeiKan Tsai     if (ADD_OVERFLOW(size, SizeQuant - 1, &size))
6417539e8c3SPeiKan Tsai         return NULL;
6427539e8c3SPeiKan Tsai 
6437539e8c3SPeiKan Tsai     size = ROUNDDOWN(size, SizeQuant);
644074ba9b2SJens Wiklander #endif
645074ba9b2SJens Wiklander #endif
646074ba9b2SJens Wiklander 
6477539e8c3SPeiKan Tsai     /* Add overhead in allocated buffer to size required. */
6487539e8c3SPeiKan Tsai     if (ADD_OVERFLOW(size, sizeof(struct bhead), &size))
6497539e8c3SPeiKan Tsai         return NULL;
650*17967299SJens Wiklander     if (ADD_OVERFLOW(size, hdr_size, &size))
651*17967299SJens Wiklander         return NULL;
652074ba9b2SJens Wiklander 
653074ba9b2SJens Wiklander #ifdef BECtl
654074ba9b2SJens Wiklander     /* If a compact function was provided in the call to bectl(), wrap
655074ba9b2SJens Wiklander        a loop around the allocation process  to  allow	compaction  to
656074ba9b2SJens Wiklander        intervene in case we don't find a suitable buffer in the chain. */
657074ba9b2SJens Wiklander 
658074ba9b2SJens Wiklander     while (1) {
659074ba9b2SJens Wiklander #endif
660b7f0111dSVolodymyr Babchuk 	b = poolset->freelist.ql.flink;
661074ba9b2SJens Wiklander #ifdef BestFit
662b7f0111dSVolodymyr Babchuk 	best = &poolset->freelist;
663074ba9b2SJens Wiklander #endif
664074ba9b2SJens Wiklander 
665074ba9b2SJens Wiklander 
666074ba9b2SJens Wiklander 	/* Scan the free list searching for the first buffer big enough
667074ba9b2SJens Wiklander 	   to hold the requested size buffer. */
668074ba9b2SJens Wiklander 
669074ba9b2SJens Wiklander #ifdef BestFit
670b7f0111dSVolodymyr Babchuk 	while (b != &poolset->freelist) {
671cc5981b2SJens Wiklander             assert(b->bh.prevfree == 0);
672*17967299SJens Wiklander             pos = buf_get_pos(b, align, hdr_size, size);
673cc5981b2SJens Wiklander             if (pos >= 0) {
674b7f0111dSVolodymyr Babchuk 		if ((best == &poolset->freelist) ||
675b7f0111dSVolodymyr Babchuk 		    (b->bh.bsize < best->bh.bsize)) {
676074ba9b2SJens Wiklander 		    best = b;
677074ba9b2SJens Wiklander 		}
678074ba9b2SJens Wiklander 	    }
679074ba9b2SJens Wiklander 	    b = b->ql.flink;		  /* Link to next buffer */
680074ba9b2SJens Wiklander 	}
681074ba9b2SJens Wiklander 	b = best;
682074ba9b2SJens Wiklander #endif /* BestFit */
683074ba9b2SJens Wiklander 
684b7f0111dSVolodymyr Babchuk 	while (b != &poolset->freelist) {
685*17967299SJens Wiklander             pos = buf_get_pos(b, align, hdr_size, size);
686cc5981b2SJens Wiklander             if (pos >= 0) {
687cc5981b2SJens Wiklander                 struct bhead *b_alloc = BH((char *)b + pos);
688cc5981b2SJens Wiklander                 struct bhead *b_next = BH((char *)b + b->bh.bsize);
689074ba9b2SJens Wiklander 
690cc5981b2SJens Wiklander                 assert(b_next->prevfree == b->bh.bsize);
691074ba9b2SJens Wiklander 
692cc5981b2SJens Wiklander                 /*
693cc5981b2SJens Wiklander                  * Zero the back pointer in the next buffer in memory
694cc5981b2SJens Wiklander                  * to indicate that this buffer is allocated.
695cc5981b2SJens Wiklander                  */
696cc5981b2SJens Wiklander                 b_next->prevfree = 0;
697074ba9b2SJens Wiklander 
698074ba9b2SJens Wiklander                 assert(b->ql.blink->ql.flink == b);
699074ba9b2SJens Wiklander                 assert(b->ql.flink->ql.blink == b);
700cc5981b2SJens Wiklander 
701cc5981b2SJens Wiklander                 if (pos == 0) {
702cc5981b2SJens Wiklander                     /*
703cc5981b2SJens Wiklander                      * Need to allocate from the beginning of this free block.
704cc5981b2SJens Wiklander                      * Unlink the block and mark it as allocated.
705cc5981b2SJens Wiklander                      */
706074ba9b2SJens Wiklander 		    b->ql.blink->ql.flink = b->ql.flink;
707074ba9b2SJens Wiklander 		    b->ql.flink->ql.blink = b->ql.blink;
708074ba9b2SJens Wiklander 
709cc5981b2SJens Wiklander 		    /* Negate size to mark buffer allocated. */
710cc5981b2SJens Wiklander 		    b->bh.bsize = -b->bh.bsize;
711cc5981b2SJens Wiklander                 } else {
712cc5981b2SJens Wiklander                     /*
713cc5981b2SJens Wiklander                      * Carve out the memory allocation from the end of this
714cc5981b2SJens Wiklander                      * free block. Negative size to mark buffer allocated.
715cc5981b2SJens Wiklander                      */
716cc5981b2SJens Wiklander                     b_alloc->bsize = -(b->bh.bsize - pos);
717cc5981b2SJens Wiklander                     b_alloc->prevfree = pos;
718cc5981b2SJens Wiklander                     b->bh.bsize = pos;
719cc5981b2SJens Wiklander                 }
720cc5981b2SJens Wiklander 
721cc5981b2SJens Wiklander                 assert(b_alloc->bsize < 0);
722cc5981b2SJens Wiklander                 /*
723cc5981b2SJens Wiklander                  * At this point is b_alloc pointing to the allocated
724cc5981b2SJens Wiklander                  * buffer and b_next at the buffer following. b might be a
725cc5981b2SJens Wiklander                  * free block or a used block now.
726cc5981b2SJens Wiklander                  */
727cc5981b2SJens Wiklander                 if (-b_alloc->bsize - size > SizeQ + sizeof(struct bhead)) {
728cc5981b2SJens Wiklander                     /*
729cc5981b2SJens Wiklander                      * b_alloc has too much unused memory at the
730cc5981b2SJens Wiklander                      * end we need to split the block and register that
731cc5981b2SJens Wiklander                      * last part as free.
732cc5981b2SJens Wiklander                      */
733cc5981b2SJens Wiklander                     b = BFH((char *)b_alloc + size);
734cc5981b2SJens Wiklander                     b->bh.bsize = -b_alloc->bsize - size;
735cc5981b2SJens Wiklander                     b->bh.prevfree = 0;
736cc5981b2SJens Wiklander                     b_alloc->bsize += b->bh.bsize;
737cc5981b2SJens Wiklander 
738cc5981b2SJens Wiklander                     assert(poolset->freelist.ql.blink->ql.flink ==
739cc5981b2SJens Wiklander 			   &poolset->freelist);
740cc5981b2SJens Wiklander                     assert(poolset->freelist.ql.flink->ql.blink ==
741cc5981b2SJens Wiklander 			   &poolset->freelist);
742cc5981b2SJens Wiklander                     b->ql.flink = &poolset->freelist;
743cc5981b2SJens Wiklander                     b->ql.blink = poolset->freelist.ql.blink;
744cc5981b2SJens Wiklander                     poolset->freelist.ql.blink = b;
745cc5981b2SJens Wiklander                     b->ql.blink->ql.flink = b;
746cc5981b2SJens Wiklander 
747cc5981b2SJens Wiklander                     assert(BH((char *)b + b->bh.bsize) == b_next);
748cc5981b2SJens Wiklander                     b_next->prevfree = b->bh.bsize;
749cc5981b2SJens Wiklander                 }
750cc5981b2SJens Wiklander 
751074ba9b2SJens Wiklander #ifdef BufStats
752cc5981b2SJens Wiklander 		poolset->totalloc -= b_alloc->bsize;
753b7f0111dSVolodymyr Babchuk 		poolset->numget++;		  /* Increment number of bget() calls */
754074ba9b2SJens Wiklander #endif
755cc5981b2SJens Wiklander                 buf = (char *)b_alloc + sizeof(struct bhead);
7561d171f95SJens Wiklander 		tag_asan_alloced(buf, size);
757074ba9b2SJens Wiklander                 return buf;
758074ba9b2SJens Wiklander 	    }
759074ba9b2SJens Wiklander 	    b = b->ql.flink;		  /* Link to next buffer */
760074ba9b2SJens Wiklander 	}
761074ba9b2SJens Wiklander #ifdef BECtl
762074ba9b2SJens Wiklander 
763074ba9b2SJens Wiklander         /* We failed to find a buffer.  If there's a compact  function
764074ba9b2SJens Wiklander 	   defined,  notify  it  of the size requested.  If it returns
765074ba9b2SJens Wiklander 	   TRUE, try the allocation again. */
766074ba9b2SJens Wiklander 
767b7f0111dSVolodymyr Babchuk 	if ((poolset->compfcn == NULL) ||
768b7f0111dSVolodymyr Babchuk 	    (!(poolset->compfcn)(size, ++compactseq))) {
769074ba9b2SJens Wiklander 	    break;
770074ba9b2SJens Wiklander 	}
771074ba9b2SJens Wiklander     }
772074ba9b2SJens Wiklander 
773074ba9b2SJens Wiklander     /* No buffer available with requested size free. */
774074ba9b2SJens Wiklander 
775074ba9b2SJens Wiklander     /* Don't give up yet -- look in the reserve supply. */
776074ba9b2SJens Wiklander 
777b7f0111dSVolodymyr Babchuk     if (poolset->acqfcn != NULL) {
778cc5981b2SJens Wiklander 	if (size > exp_incr - sizeof(struct bfhead) - align) {
779074ba9b2SJens Wiklander 
780074ba9b2SJens Wiklander 	    /* Request	is  too  large	to  fit in a single expansion
781074ba9b2SJens Wiklander 	       block.  Try to satisy it by a direct buffer acquisition. */
782cc5981b2SJens Wiklander             char *p;
783074ba9b2SJens Wiklander 
784074ba9b2SJens Wiklander 	    size += sizeof(struct bdhead) - sizeof(struct bhead);
785cc5981b2SJens Wiklander             if (align > QLSize)
786cc5981b2SJens Wiklander                 size += align;
787cc5981b2SJens Wiklander 	    p = poolset->acqfcn(size);
788cc5981b2SJens Wiklander             if (p != NULL) {
789cc5981b2SJens Wiklander 	        struct bdhead *bdh;
790cc5981b2SJens Wiklander 
791cc5981b2SJens Wiklander                 if (align <= QLSize) {
792cc5981b2SJens Wiklander                     bdh = BDH(p);
793cc5981b2SJens Wiklander 		    buf = bdh + 1;
794cc5981b2SJens Wiklander                 } else {
795*17967299SJens Wiklander                     unsigned long tp = (unsigned long)p;
796*17967299SJens Wiklander 
797*17967299SJens Wiklander                     tp += sizeof(*bdh) + hdr_size + align;
798*17967299SJens Wiklander                     tp &= ~(align - 1);
799*17967299SJens Wiklander                     tp -= hdr_size;
800*17967299SJens Wiklander 		    buf = (void *)tp;
801cc5981b2SJens Wiklander                     bdh = BDH((char *)buf - sizeof(*bdh));
802cc5981b2SJens Wiklander                 }
803074ba9b2SJens Wiklander 
804074ba9b2SJens Wiklander 		/*  Mark the buffer special by setting the size field
805074ba9b2SJens Wiklander 		    of its header to zero.  */
806074ba9b2SJens Wiklander 		bdh->bh.bsize = 0;
807074ba9b2SJens Wiklander 		bdh->bh.prevfree = 0;
808074ba9b2SJens Wiklander 		bdh->tsize = size;
809cc5981b2SJens Wiklander 		bdh->offs = (unsigned long)bdh - (unsigned long)p;
810074ba9b2SJens Wiklander #ifdef BufStats
811b7f0111dSVolodymyr Babchuk 		poolset->totalloc += size;
812b7f0111dSVolodymyr Babchuk 		poolset->numget++;	  /* Increment number of bget() calls */
813b7f0111dSVolodymyr Babchuk 		poolset->numdget++;	  /* Direct bget() call count */
814074ba9b2SJens Wiklander #endif
8151d171f95SJens Wiklander 		tag_asan_alloced(buf, size);
816074ba9b2SJens Wiklander 		return buf;
817074ba9b2SJens Wiklander 	    }
818074ba9b2SJens Wiklander 
819074ba9b2SJens Wiklander 	} else {
820074ba9b2SJens Wiklander 
821074ba9b2SJens Wiklander 	    /*	Try to obtain a new expansion block */
822074ba9b2SJens Wiklander 
823074ba9b2SJens Wiklander 	    void *newpool;
824074ba9b2SJens Wiklander 
825b7f0111dSVolodymyr Babchuk 	    if ((newpool = poolset->acqfcn((bufsize) exp_incr)) != NULL) {
826b7f0111dSVolodymyr Babchuk 		bpool(newpool, exp_incr, poolset);
827*17967299SJens Wiklander                 buf =  bget(align, hdr_size, requested_size, pool);  /* This can't, I say, can't
828074ba9b2SJens Wiklander 						       get into a loop. */
829074ba9b2SJens Wiklander 		return buf;
830074ba9b2SJens Wiklander 	    }
831074ba9b2SJens Wiklander 	}
832074ba9b2SJens Wiklander     }
833074ba9b2SJens Wiklander 
834074ba9b2SJens Wiklander     /*	Still no buffer available */
835074ba9b2SJens Wiklander 
836074ba9b2SJens Wiklander #endif /* BECtl */
837074ba9b2SJens Wiklander 
838074ba9b2SJens Wiklander     return NULL;
839074ba9b2SJens Wiklander }
840074ba9b2SJens Wiklander 
841074ba9b2SJens Wiklander /*  BGETZ  --  Allocate a buffer and clear its contents to zero.  We clear
842074ba9b2SJens Wiklander 	       the  entire  contents  of  the buffer to zero, not just the
843074ba9b2SJens Wiklander 	       region requested by the caller. */
844074ba9b2SJens Wiklander 
845*17967299SJens Wiklander void *bgetz(align, hdr_size, size, poolset)
846cc5981b2SJens Wiklander   bufsize align;
847*17967299SJens Wiklander   bufsize hdr_size;
848074ba9b2SJens Wiklander   bufsize size;
849b7f0111dSVolodymyr Babchuk   struct bpoolset *poolset;
850074ba9b2SJens Wiklander {
851*17967299SJens Wiklander     char *buf = (char *) bget(align, hdr_size, size, poolset);
852074ba9b2SJens Wiklander 
853074ba9b2SJens Wiklander     if (buf != NULL) {
854074ba9b2SJens Wiklander 	struct bhead *b;
855074ba9b2SJens Wiklander 	bufsize rsize;
856074ba9b2SJens Wiklander 
857074ba9b2SJens Wiklander 	b = BH(buf - sizeof(struct bhead));
858074ba9b2SJens Wiklander 	rsize = -(b->bsize);
859074ba9b2SJens Wiklander 	if (rsize == 0) {
860074ba9b2SJens Wiklander 	    struct bdhead *bd;
861074ba9b2SJens Wiklander 
862074ba9b2SJens Wiklander 	    bd = BDH(buf - sizeof(struct bdhead));
863cc5981b2SJens Wiklander 	    rsize = bd->tsize - sizeof(struct bdhead) - bd->offs;
864074ba9b2SJens Wiklander 	} else {
865074ba9b2SJens Wiklander 	    rsize -= sizeof(struct bhead);
866074ba9b2SJens Wiklander 	}
867074ba9b2SJens Wiklander 	assert(rsize >= size);
868e103c301SJens Wiklander 	V memset_unchecked(buf, 0, (MemSize) rsize);
869074ba9b2SJens Wiklander     }
870074ba9b2SJens Wiklander     return ((void *) buf);
871074ba9b2SJens Wiklander }
872074ba9b2SJens Wiklander 
873074ba9b2SJens Wiklander /*  BGETR  --  Reallocate a buffer.  This is a minimal implementation,
874074ba9b2SJens Wiklander 	       simply in terms of brel()  and  bget().	 It  could  be
875074ba9b2SJens Wiklander 	       enhanced to allow the buffer to grow into adjacent free
876074ba9b2SJens Wiklander 	       blocks and to avoid moving data unnecessarily.  */
877074ba9b2SJens Wiklander 
878*17967299SJens Wiklander void *bgetr(buf, align, hdr_size, size, poolset)
879074ba9b2SJens Wiklander   void *buf;
880cc5981b2SJens Wiklander   bufsize align;
881*17967299SJens Wiklander   bufsize hdr_size;
882074ba9b2SJens Wiklander   bufsize size;
883b7f0111dSVolodymyr Babchuk   struct bpoolset *poolset;
884074ba9b2SJens Wiklander {
885074ba9b2SJens Wiklander     void *nbuf;
886074ba9b2SJens Wiklander     bufsize osize;		      /* Old size of buffer */
887074ba9b2SJens Wiklander     struct bhead *b;
888074ba9b2SJens Wiklander 
889*17967299SJens Wiklander     if ((nbuf = bget(align, hdr_size, size, poolset)) == NULL) { /* Acquire new buffer */
890074ba9b2SJens Wiklander 	return NULL;
891074ba9b2SJens Wiklander     }
892074ba9b2SJens Wiklander     if (buf == NULL) {
893074ba9b2SJens Wiklander 	return nbuf;
894074ba9b2SJens Wiklander     }
895074ba9b2SJens Wiklander     b = BH(((char *) buf) - sizeof(struct bhead));
896074ba9b2SJens Wiklander     osize = -b->bsize;
897074ba9b2SJens Wiklander #ifdef BECtl
898074ba9b2SJens Wiklander     if (osize == 0) {
899074ba9b2SJens Wiklander 	/*  Buffer acquired directly through acqfcn. */
900074ba9b2SJens Wiklander 	struct bdhead *bd;
901074ba9b2SJens Wiklander 
902074ba9b2SJens Wiklander 	bd = BDH(((char *) buf) - sizeof(struct bdhead));
903cc5981b2SJens Wiklander 	osize = bd->tsize - sizeof(struct bdhead) - bd->offs;
904074ba9b2SJens Wiklander     } else
905074ba9b2SJens Wiklander #endif
906074ba9b2SJens Wiklander 	osize -= sizeof(struct bhead);
907074ba9b2SJens Wiklander     assert(osize > 0);
908074ba9b2SJens Wiklander     V memcpy((char *) nbuf, (char *) buf, /* Copy the data */
909074ba9b2SJens Wiklander 	     (MemSize) ((size < osize) ? size : osize));
91096c1d8c5SJens Wiklander #ifndef __KERNEL__
91196c1d8c5SJens Wiklander     /* User space reallocations are always zeroed */
91296c1d8c5SJens Wiklander     if (size > osize)
91396c1d8c5SJens Wiklander          V memset((char *) nbuf + osize, 0, size - osize);
91496c1d8c5SJens Wiklander #endif
9154e570655SJerome Forissier     brel(buf, poolset, false /* !wipe */);
916074ba9b2SJens Wiklander     return nbuf;
917074ba9b2SJens Wiklander }
918074ba9b2SJens Wiklander 
919074ba9b2SJens Wiklander /*  BREL  --  Release a buffer.  */
920074ba9b2SJens Wiklander 
9214e570655SJerome Forissier void brel(buf, poolset, wipe)
922074ba9b2SJens Wiklander   void *buf;
923b7f0111dSVolodymyr Babchuk   struct bpoolset *poolset;
9244e570655SJerome Forissier   int wipe;
925074ba9b2SJens Wiklander {
926074ba9b2SJens Wiklander     struct bfhead *b, *bn;
9271d171f95SJens Wiklander     bufsize bs;
928074ba9b2SJens Wiklander 
929074ba9b2SJens Wiklander     b = BFH(((char *) buf) - sizeof(struct bhead));
930074ba9b2SJens Wiklander #ifdef BufStats
931b7f0111dSVolodymyr Babchuk     poolset->numrel++;		      /* Increment number of brel() calls */
932074ba9b2SJens Wiklander #endif
933074ba9b2SJens Wiklander     assert(buf != NULL);
934074ba9b2SJens Wiklander 
9354e570655SJerome Forissier #ifdef FreeWipe
9364e570655SJerome Forissier     wipe = true;
9374e570655SJerome Forissier #endif
938074ba9b2SJens Wiklander #ifdef BECtl
939074ba9b2SJens Wiklander     if (b->bh.bsize == 0) {	      /* Directly-acquired buffer? */
940074ba9b2SJens Wiklander 	struct bdhead *bdh;
941074ba9b2SJens Wiklander 
942074ba9b2SJens Wiklander 	bdh = BDH(((char *) buf) - sizeof(struct bdhead));
943074ba9b2SJens Wiklander 	assert(b->bh.prevfree == 0);
944074ba9b2SJens Wiklander #ifdef BufStats
945b7f0111dSVolodymyr Babchuk 	poolset->totalloc -= bdh->tsize;
946b7f0111dSVolodymyr Babchuk 	assert(poolset->totalloc >= 0);
947b7f0111dSVolodymyr Babchuk 	poolset->numdrel++;	       /* Number of direct releases */
948074ba9b2SJens Wiklander #endif /* BufStats */
9494e570655SJerome Forissier 	if (wipe) {
950e103c301SJens Wiklander 		V memset_unchecked((char *) buf, 0x55,
9514e570655SJerome Forissier 				   (MemSize) (bdh->tsize -
9524e570655SJerome Forissier 					      sizeof(struct bdhead)));
9534e570655SJerome Forissier 	}
9541d171f95SJens Wiklander 	bs = bdh->tsize - sizeof(struct bdhead);
955b7f0111dSVolodymyr Babchuk 	assert(poolset->relfcn != NULL);
956cc5981b2SJens Wiklander 	poolset->relfcn((char *)buf - sizeof(struct bdhead) - bdh->offs);      /* Release it directly. */
9571d171f95SJens Wiklander 	tag_asan_free(buf, bs);
958074ba9b2SJens Wiklander 	return;
959074ba9b2SJens Wiklander     }
960074ba9b2SJens Wiklander #endif /* BECtl */
961074ba9b2SJens Wiklander 
962074ba9b2SJens Wiklander     /* Buffer size must be negative, indicating that the buffer is
963074ba9b2SJens Wiklander        allocated. */
964074ba9b2SJens Wiklander 
965074ba9b2SJens Wiklander     if (b->bh.bsize >= 0) {
966074ba9b2SJens Wiklander 	bn = NULL;
967074ba9b2SJens Wiklander     }
968074ba9b2SJens Wiklander     assert(b->bh.bsize < 0);
9691d171f95SJens Wiklander     bs = -b->bh.bsize;
970074ba9b2SJens Wiklander 
971074ba9b2SJens Wiklander     /*	Back pointer in next buffer must be zero, indicating the
972074ba9b2SJens Wiklander 	same thing: */
973074ba9b2SJens Wiklander 
974074ba9b2SJens Wiklander     assert(BH((char *) b - b->bh.bsize)->prevfree == 0);
975074ba9b2SJens Wiklander 
976074ba9b2SJens Wiklander #ifdef BufStats
977b7f0111dSVolodymyr Babchuk     poolset->totalloc += b->bh.bsize;
978b7f0111dSVolodymyr Babchuk     assert(poolset->totalloc >= 0);
979074ba9b2SJens Wiklander #endif
980074ba9b2SJens Wiklander 
981074ba9b2SJens Wiklander     /* If the back link is nonzero, the previous buffer is free.  */
982074ba9b2SJens Wiklander 
983074ba9b2SJens Wiklander     if (b->bh.prevfree != 0) {
984074ba9b2SJens Wiklander 
985074ba9b2SJens Wiklander 	/* The previous buffer is free.  Consolidate this buffer  with	it
986074ba9b2SJens Wiklander 	   by  adding  the  length  of	this  buffer  to the previous free
987074ba9b2SJens Wiklander 	   buffer.  Note that we subtract the size  in	the  buffer  being
988074ba9b2SJens Wiklander            released,  since  it's  negative to indicate that the buffer is
989074ba9b2SJens Wiklander 	   allocated. */
990074ba9b2SJens Wiklander 
991074ba9b2SJens Wiklander 	register bufsize size = b->bh.bsize;
992074ba9b2SJens Wiklander 
993074ba9b2SJens Wiklander         /* Make the previous buffer the one we're working on. */
994074ba9b2SJens Wiklander 	assert(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree);
995074ba9b2SJens Wiklander 	b = BFH(((char *) b) - b->bh.prevfree);
996074ba9b2SJens Wiklander 	b->bh.bsize -= size;
997074ba9b2SJens Wiklander     } else {
998074ba9b2SJens Wiklander 
999074ba9b2SJens Wiklander         /* The previous buffer isn't allocated.  Insert this buffer
1000074ba9b2SJens Wiklander 	   on the free list as an isolated free block. */
1001074ba9b2SJens Wiklander 
1002b7f0111dSVolodymyr Babchuk 	assert(poolset->freelist.ql.blink->ql.flink == &poolset->freelist);
1003b7f0111dSVolodymyr Babchuk 	assert(poolset->freelist.ql.flink->ql.blink == &poolset->freelist);
1004b7f0111dSVolodymyr Babchuk 	b->ql.flink = &poolset->freelist;
1005b7f0111dSVolodymyr Babchuk 	b->ql.blink = poolset->freelist.ql.blink;
1006b7f0111dSVolodymyr Babchuk 	poolset->freelist.ql.blink = b;
1007074ba9b2SJens Wiklander 	b->ql.blink->ql.flink = b;
1008074ba9b2SJens Wiklander 	b->bh.bsize = -b->bh.bsize;
1009074ba9b2SJens Wiklander     }
1010074ba9b2SJens Wiklander 
1011074ba9b2SJens Wiklander     /* Now we look at the next buffer in memory, located by advancing from
1012074ba9b2SJens Wiklander        the  start  of  this  buffer  by its size, to see if that buffer is
1013074ba9b2SJens Wiklander        free.  If it is, we combine  this  buffer  with	the  next  one	in
1014074ba9b2SJens Wiklander        memory, dechaining the second buffer from the free list. */
1015074ba9b2SJens Wiklander 
1016074ba9b2SJens Wiklander     bn =  BFH(((char *) b) + b->bh.bsize);
1017074ba9b2SJens Wiklander     if (bn->bh.bsize > 0) {
1018074ba9b2SJens Wiklander 
1019074ba9b2SJens Wiklander 	/* The buffer is free.	Remove it from the free list and add
1020074ba9b2SJens Wiklander 	   its size to that of our buffer. */
1021074ba9b2SJens Wiklander 
1022074ba9b2SJens Wiklander 	assert(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize);
1023074ba9b2SJens Wiklander 	assert(bn->ql.blink->ql.flink == bn);
1024074ba9b2SJens Wiklander 	assert(bn->ql.flink->ql.blink == bn);
1025074ba9b2SJens Wiklander 	bn->ql.blink->ql.flink = bn->ql.flink;
1026074ba9b2SJens Wiklander 	bn->ql.flink->ql.blink = bn->ql.blink;
1027074ba9b2SJens Wiklander 	b->bh.bsize += bn->bh.bsize;
1028074ba9b2SJens Wiklander 
1029074ba9b2SJens Wiklander 	/* Finally,  advance  to   the	buffer	that   follows	the  newly
1030074ba9b2SJens Wiklander 	   consolidated free block.  We must set its  backpointer  to  the
1031074ba9b2SJens Wiklander 	   head  of  the  consolidated free block.  We know the next block
1032074ba9b2SJens Wiklander 	   must be an allocated block because the process of recombination
1033074ba9b2SJens Wiklander 	   guarantees  that  two  free	blocks will never be contiguous in
1034074ba9b2SJens Wiklander 	   memory.  */
1035074ba9b2SJens Wiklander 
1036074ba9b2SJens Wiklander 	bn = BFH(((char *) b) + b->bh.bsize);
1037074ba9b2SJens Wiklander     }
10384e570655SJerome Forissier     if (wipe) {
1039e103c301SJens Wiklander 	V memset_unchecked(((char *) b) + sizeof(struct bfhead), 0x55,
1040074ba9b2SJens Wiklander 			   (MemSize) (b->bh.bsize - sizeof(struct bfhead)));
10414e570655SJerome Forissier     }
1042074ba9b2SJens Wiklander     assert(bn->bh.bsize < 0);
1043074ba9b2SJens Wiklander 
1044074ba9b2SJens Wiklander     /* The next buffer is allocated.  Set the backpointer in it  to  point
1045074ba9b2SJens Wiklander        to this buffer; the previous free buffer in memory. */
1046074ba9b2SJens Wiklander 
1047074ba9b2SJens Wiklander     bn->bh.prevfree = b->bh.bsize;
1048074ba9b2SJens Wiklander 
1049074ba9b2SJens Wiklander #ifdef BECtl
1050074ba9b2SJens Wiklander 
1051074ba9b2SJens Wiklander     /*	If  a  block-release function is defined, and this free buffer
1052074ba9b2SJens Wiklander 	constitutes the entire block, release it.  Note that  pool_len
1053074ba9b2SJens Wiklander 	is  defined  in  such a way that the test will fail unless all
1054074ba9b2SJens Wiklander 	pool blocks are the same size.	*/
1055074ba9b2SJens Wiklander 
1056b7f0111dSVolodymyr Babchuk     if (poolset->relfcn != NULL &&
1057074ba9b2SJens Wiklander 	((bufsize) b->bh.bsize) == (pool_len - sizeof(struct bhead))) {
1058074ba9b2SJens Wiklander 
1059074ba9b2SJens Wiklander 	assert(b->bh.prevfree == 0);
1060074ba9b2SJens Wiklander 	assert(BH((char *) b + b->bh.bsize)->bsize == ESent);
1061074ba9b2SJens Wiklander 	assert(BH((char *) b + b->bh.bsize)->prevfree == b->bh.bsize);
1062074ba9b2SJens Wiklander 	/*  Unlink the buffer from the free list  */
1063074ba9b2SJens Wiklander 	b->ql.blink->ql.flink = b->ql.flink;
1064074ba9b2SJens Wiklander 	b->ql.flink->ql.blink = b->ql.blink;
1065074ba9b2SJens Wiklander 
1066b7f0111dSVolodymyr Babchuk 	poolset->relfcn(b);
1067074ba9b2SJens Wiklander #ifdef BufStats
1068b7f0111dSVolodymyr Babchuk 	poolset->numprel++;	       /* Nr of expansion block releases */
1069b7f0111dSVolodymyr Babchuk 	poolset->numpblk--;	       /* Total number of blocks */
1070074ba9b2SJens Wiklander 	assert(numpblk == numpget - numprel);
1071074ba9b2SJens Wiklander #endif /* BufStats */
1072074ba9b2SJens Wiklander     }
1073074ba9b2SJens Wiklander #endif /* BECtl */
10741d171f95SJens Wiklander     tag_asan_free(buf, bs);
1075074ba9b2SJens Wiklander }
1076074ba9b2SJens Wiklander 
1077074ba9b2SJens Wiklander #ifdef BECtl
1078074ba9b2SJens Wiklander 
1079074ba9b2SJens Wiklander /*  BECTL  --  Establish automatic pool expansion control  */
1080074ba9b2SJens Wiklander 
1081b7f0111dSVolodymyr Babchuk void bectl(compact, acquire, release, pool_incr, poolset)
1082074ba9b2SJens Wiklander   int (*compact) _((bufsize sizereq, int sequence));
1083074ba9b2SJens Wiklander   void *(*acquire) _((bufsize size));
1084074ba9b2SJens Wiklander   void (*release) _((void *buf));
1085074ba9b2SJens Wiklander   bufsize pool_incr;
1086b7f0111dSVolodymyr Babchuk   struct bpoolset *poolset;
1087074ba9b2SJens Wiklander {
1088b7f0111dSVolodymyr Babchuk     poolset->compfcn = compact;
1089b7f0111dSVolodymyr Babchuk     poolset->acqfcn = acquire;
1090b7f0111dSVolodymyr Babchuk     poolset->relfcn = release;
1091b7f0111dSVolodymyr Babchuk     poolset->exp_incr = pool_incr;
1092074ba9b2SJens Wiklander }
1093074ba9b2SJens Wiklander #endif
1094074ba9b2SJens Wiklander 
1095074ba9b2SJens Wiklander /*  BPOOL  --  Add a region of memory to the buffer pool.  */
1096074ba9b2SJens Wiklander 
1097b7f0111dSVolodymyr Babchuk void bpool(buf, len, poolset)
1098074ba9b2SJens Wiklander   void *buf;
1099074ba9b2SJens Wiklander   bufsize len;
1100b7f0111dSVolodymyr Babchuk   struct bpoolset *poolset;
1101074ba9b2SJens Wiklander {
1102074ba9b2SJens Wiklander     struct bfhead *b = BFH(buf);
1103074ba9b2SJens Wiklander     struct bhead *bn;
1104074ba9b2SJens Wiklander 
1105074ba9b2SJens Wiklander #ifdef SizeQuant
1106074ba9b2SJens Wiklander     len &= ~(SizeQuant - 1);
1107074ba9b2SJens Wiklander #endif
1108074ba9b2SJens Wiklander #ifdef BECtl
1109b7f0111dSVolodymyr Babchuk     if (poolset->pool_len == 0) {
1110074ba9b2SJens Wiklander 	pool_len = len;
1111b7f0111dSVolodymyr Babchuk     } else if (len != poolset->pool_len) {
1112b7f0111dSVolodymyr Babchuk 	poolset->pool_len = -1;
1113074ba9b2SJens Wiklander     }
1114074ba9b2SJens Wiklander #ifdef BufStats
1115b7f0111dSVolodymyr Babchuk     poolset->numpget++;		       /* Number of block acquisitions */
1116b7f0111dSVolodymyr Babchuk     poolset->numpblk++;		       /* Number of blocks total */
1117b7f0111dSVolodymyr Babchuk     assert(poolset->numpblk == poolset->numpget - poolset->numprel);
1118074ba9b2SJens Wiklander #endif /* BufStats */
1119074ba9b2SJens Wiklander #endif /* BECtl */
1120074ba9b2SJens Wiklander 
1121074ba9b2SJens Wiklander     /* Since the block is initially occupied by a single free  buffer,
1122074ba9b2SJens Wiklander        it  had	better	not  be  (much) larger than the largest buffer
1123074ba9b2SJens Wiklander        whose size we can store in bhead.bsize. */
1124074ba9b2SJens Wiklander 
1125074ba9b2SJens Wiklander     assert(len - sizeof(struct bhead) <= -((bufsize) ESent + 1));
1126074ba9b2SJens Wiklander 
1127074ba9b2SJens Wiklander     /* Clear  the  backpointer at  the start of the block to indicate that
1128074ba9b2SJens Wiklander        there  is  no  free  block  prior  to  this   one.    That   blocks
1129074ba9b2SJens Wiklander        recombination when the first block in memory is released. */
1130074ba9b2SJens Wiklander 
1131074ba9b2SJens Wiklander     b->bh.prevfree = 0;
1132074ba9b2SJens Wiklander 
1133074ba9b2SJens Wiklander     /* Chain the new block to the free list. */
1134074ba9b2SJens Wiklander 
1135b7f0111dSVolodymyr Babchuk     assert(poolset->freelist.ql.blink->ql.flink == &poolset->freelist);
1136b7f0111dSVolodymyr Babchuk     assert(poolset->freelist.ql.flink->ql.blink == &poolset->freelist);
1137b7f0111dSVolodymyr Babchuk     b->ql.flink = &poolset->freelist;
1138b7f0111dSVolodymyr Babchuk     b->ql.blink = poolset->freelist.ql.blink;
1139b7f0111dSVolodymyr Babchuk     poolset->freelist.ql.blink = b;
1140074ba9b2SJens Wiklander     b->ql.blink->ql.flink = b;
1141074ba9b2SJens Wiklander 
1142074ba9b2SJens Wiklander     /* Create a dummy allocated buffer at the end of the pool.	This dummy
1143074ba9b2SJens Wiklander        buffer is seen when a buffer at the end of the pool is released and
1144074ba9b2SJens Wiklander        blocks  recombination  of  the last buffer with the dummy buffer at
1145074ba9b2SJens Wiklander        the end.  The length in the dummy buffer  is  set  to  the  largest
1146074ba9b2SJens Wiklander        negative  number  to  denote  the  end  of  the pool for diagnostic
1147074ba9b2SJens Wiklander        routines (this specific value is  not  counted  on  by  the  actual
1148074ba9b2SJens Wiklander        allocation and release functions). */
1149074ba9b2SJens Wiklander 
1150074ba9b2SJens Wiklander     len -= sizeof(struct bhead);
1151074ba9b2SJens Wiklander     b->bh.bsize = (bufsize) len;
1152074ba9b2SJens Wiklander #ifdef FreeWipe
1153e103c301SJens Wiklander     V memset_unchecked(((char *) b) + sizeof(struct bfhead), 0x55,
1154074ba9b2SJens Wiklander 		       (MemSize) (len - sizeof(struct bfhead)));
1155074ba9b2SJens Wiklander #endif
1156074ba9b2SJens Wiklander     bn = BH(((char *) b) + len);
1157074ba9b2SJens Wiklander     bn->prevfree = (bufsize) len;
1158074ba9b2SJens Wiklander     /* Definition of ESent assumes two's complement! */
1159074ba9b2SJens Wiklander     assert((~0) == -1);
1160074ba9b2SJens Wiklander     bn->bsize = ESent;
1161074ba9b2SJens Wiklander }
1162074ba9b2SJens Wiklander 
1163074ba9b2SJens Wiklander #ifdef BufStats
1164074ba9b2SJens Wiklander 
1165074ba9b2SJens Wiklander /*  BSTATS  --	Return buffer allocation free space statistics.  */
1166074ba9b2SJens Wiklander 
1167b7f0111dSVolodymyr Babchuk void bstats(curalloc, totfree, maxfree, nget, nrel, poolset)
1168074ba9b2SJens Wiklander   bufsize *curalloc, *totfree, *maxfree;
1169074ba9b2SJens Wiklander   long *nget, *nrel;
1170b7f0111dSVolodymyr Babchuk   struct bpoolset *poolset;
1171074ba9b2SJens Wiklander {
1172b7f0111dSVolodymyr Babchuk     struct bfhead *b = poolset->freelist.ql.flink;
1173074ba9b2SJens Wiklander 
1174b7f0111dSVolodymyr Babchuk     *nget = poolset->numget;
1175b7f0111dSVolodymyr Babchuk     *nrel = poolset->numrel;
1176b7f0111dSVolodymyr Babchuk     *curalloc = poolset->totalloc;
1177074ba9b2SJens Wiklander     *totfree = 0;
1178074ba9b2SJens Wiklander     *maxfree = -1;
1179b7f0111dSVolodymyr Babchuk     while (b != &poolset->freelist) {
1180074ba9b2SJens Wiklander 	assert(b->bh.bsize > 0);
1181074ba9b2SJens Wiklander 	*totfree += b->bh.bsize;
1182074ba9b2SJens Wiklander 	if (b->bh.bsize > *maxfree) {
1183074ba9b2SJens Wiklander 	    *maxfree = b->bh.bsize;
1184074ba9b2SJens Wiklander 	}
1185074ba9b2SJens Wiklander 	b = b->ql.flink;	      /* Link to next buffer */
1186074ba9b2SJens Wiklander     }
1187074ba9b2SJens Wiklander }
1188074ba9b2SJens Wiklander 
1189074ba9b2SJens Wiklander #ifdef BECtl
1190074ba9b2SJens Wiklander 
1191074ba9b2SJens Wiklander /*  BSTATSE  --  Return extended statistics  */
1192074ba9b2SJens Wiklander 
1193b7f0111dSVolodymyr Babchuk void bstatse(pool_incr, npool, npget, nprel, ndget, ndrel, poolset)
1194074ba9b2SJens Wiklander   bufsize *pool_incr;
1195074ba9b2SJens Wiklander   long *npool, *npget, *nprel, *ndget, *ndrel;
1196b7f0111dSVolodymyr Babchuk   struct bpoolset *poolset;
1197074ba9b2SJens Wiklander {
1198b7f0111dSVolodymyr Babchuk     *pool_incr = (poolset->pool_len < 0) ?
1199b7f0111dSVolodymyr Babchuk 	    -poolset->exp_incr : poolset->exp_incr;
1200b7f0111dSVolodymyr Babchuk     *npool = poolset->numpblk;
1201b7f0111dSVolodymyr Babchuk     *npget = poolset->numpget;
1202b7f0111dSVolodymyr Babchuk     *nprel = poolset->numprel;
1203b7f0111dSVolodymyr Babchuk     *ndget = poolset->numdget;
1204b7f0111dSVolodymyr Babchuk     *ndrel = poolset->numdrel;
1205074ba9b2SJens Wiklander }
1206074ba9b2SJens Wiklander #endif /* BECtl */
1207074ba9b2SJens Wiklander #endif /* BufStats */
1208074ba9b2SJens Wiklander 
1209074ba9b2SJens Wiklander #ifdef DumpData
1210074ba9b2SJens Wiklander 
1211074ba9b2SJens Wiklander /*  BUFDUMP  --  Dump the data in a buffer.  This is called with the  user
1212074ba9b2SJens Wiklander 		 data pointer, and backs up to the buffer header.  It will
1213074ba9b2SJens Wiklander 		 dump either a free block or an allocated one.	*/
1214074ba9b2SJens Wiklander 
1215074ba9b2SJens Wiklander void bufdump(buf)
1216074ba9b2SJens Wiklander   void *buf;
1217074ba9b2SJens Wiklander {
1218074ba9b2SJens Wiklander     struct bfhead *b;
1219074ba9b2SJens Wiklander     unsigned char *bdump;
1220074ba9b2SJens Wiklander     bufsize bdlen;
1221074ba9b2SJens Wiklander 
1222074ba9b2SJens Wiklander     b = BFH(((char *) buf) - sizeof(struct bhead));
1223074ba9b2SJens Wiklander     assert(b->bh.bsize != 0);
1224074ba9b2SJens Wiklander     if (b->bh.bsize < 0) {
1225074ba9b2SJens Wiklander 	bdump = (unsigned char *) buf;
1226074ba9b2SJens Wiklander 	bdlen = (-b->bh.bsize) - sizeof(struct bhead);
1227074ba9b2SJens Wiklander     } else {
1228074ba9b2SJens Wiklander 	bdump = (unsigned char *) (((char *) b) + sizeof(struct bfhead));
1229074ba9b2SJens Wiklander 	bdlen = b->bh.bsize - sizeof(struct bfhead);
1230074ba9b2SJens Wiklander     }
1231074ba9b2SJens Wiklander 
1232074ba9b2SJens Wiklander     while (bdlen > 0) {
1233074ba9b2SJens Wiklander 	int i, dupes = 0;
1234074ba9b2SJens Wiklander 	bufsize l = bdlen;
1235074ba9b2SJens Wiklander 	char bhex[50], bascii[20];
1236074ba9b2SJens Wiklander 
1237074ba9b2SJens Wiklander 	if (l > 16) {
1238074ba9b2SJens Wiklander 	    l = 16;
1239074ba9b2SJens Wiklander 	}
1240074ba9b2SJens Wiklander 
1241074ba9b2SJens Wiklander 	for (i = 0; i < l; i++) {
1242074ba9b2SJens Wiklander 			V snprintf(bhex + i * 3, sizeof(bhex) - i * 3, "%02X ",
1243074ba9b2SJens Wiklander 				   bdump[i]);
1244074ba9b2SJens Wiklander             bascii[i] = isprint(bdump[i]) ? bdump[i] : ' ';
1245074ba9b2SJens Wiklander 	}
1246074ba9b2SJens Wiklander 	bascii[i] = 0;
1247074ba9b2SJens Wiklander         V printf("%-48s   %s\n", bhex, bascii);
1248074ba9b2SJens Wiklander 	bdump += l;
1249074ba9b2SJens Wiklander 	bdlen -= l;
1250074ba9b2SJens Wiklander 	while ((bdlen > 16) && (memcmp((char *) (bdump - 16),
1251074ba9b2SJens Wiklander 				       (char *) bdump, 16) == 0)) {
1252074ba9b2SJens Wiklander 	    dupes++;
1253074ba9b2SJens Wiklander 	    bdump += 16;
1254074ba9b2SJens Wiklander 	    bdlen -= 16;
1255074ba9b2SJens Wiklander 	}
1256074ba9b2SJens Wiklander 	if (dupes > 1) {
1257074ba9b2SJens Wiklander 	    V printf(
1258074ba9b2SJens Wiklander                 "     (%d lines [%d bytes] identical to above line skipped)\n",
1259074ba9b2SJens Wiklander 		dupes, dupes * 16);
1260074ba9b2SJens Wiklander 	} else if (dupes == 1) {
1261074ba9b2SJens Wiklander 	    bdump -= 16;
1262074ba9b2SJens Wiklander 	    bdlen += 16;
1263074ba9b2SJens Wiklander 	}
1264074ba9b2SJens Wiklander     }
1265074ba9b2SJens Wiklander }
1266074ba9b2SJens Wiklander #endif
1267074ba9b2SJens Wiklander 
1268074ba9b2SJens Wiklander #ifdef BufDump
1269074ba9b2SJens Wiklander 
1270074ba9b2SJens Wiklander /*  BPOOLD  --	Dump a buffer pool.  The buffer headers are always listed.
1271074ba9b2SJens Wiklander 		If DUMPALLOC is nonzero, the contents of allocated buffers
1272074ba9b2SJens Wiklander 		are  dumped.   If  DUMPFREE  is  nonzero,  free blocks are
1273074ba9b2SJens Wiklander 		dumped as well.  If FreeWipe  checking	is  enabled,  free
1274074ba9b2SJens Wiklander 		blocks	which  have  been clobbered will always be dumped. */
1275074ba9b2SJens Wiklander 
1276074ba9b2SJens Wiklander void bpoold(buf, dumpalloc, dumpfree)
1277074ba9b2SJens Wiklander   void *buf;
1278074ba9b2SJens Wiklander   int dumpalloc, dumpfree;
1279074ba9b2SJens Wiklander {
1280074ba9b2SJens Wiklander     struct bfhead *b = BFH(buf);
1281074ba9b2SJens Wiklander 
1282074ba9b2SJens Wiklander     while (b->bh.bsize != ESent) {
1283074ba9b2SJens Wiklander 	bufsize bs = b->bh.bsize;
1284074ba9b2SJens Wiklander 
1285074ba9b2SJens Wiklander 	if (bs < 0) {
1286074ba9b2SJens Wiklander 	    bs = -bs;
1287074ba9b2SJens Wiklander             V printf("Allocated buffer: size %6ld bytes.\n", (long) bs);
1288074ba9b2SJens Wiklander 	    if (dumpalloc) {
1289074ba9b2SJens Wiklander 		bufdump((void *) (((char *) b) + sizeof(struct bhead)));
1290074ba9b2SJens Wiklander 	    }
1291074ba9b2SJens Wiklander 	} else {
1292074ba9b2SJens Wiklander             char *lerr = "";
1293074ba9b2SJens Wiklander 
1294074ba9b2SJens Wiklander 	    assert(bs > 0);
1295074ba9b2SJens Wiklander 	    if ((b->ql.blink->ql.flink != b) ||
1296074ba9b2SJens Wiklander 		(b->ql.flink->ql.blink != b)) {
1297074ba9b2SJens Wiklander                 lerr = "  (Bad free list links)";
1298074ba9b2SJens Wiklander 	    }
1299074ba9b2SJens Wiklander             V printf("Free block:       size %6ld bytes.%s\n",
1300074ba9b2SJens Wiklander 		(long) bs, lerr);
1301074ba9b2SJens Wiklander #ifdef FreeWipe
1302074ba9b2SJens Wiklander 	    lerr = ((char *) b) + sizeof(struct bfhead);
1303074ba9b2SJens Wiklander 	    if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) ||
1304074ba9b2SJens Wiklander 		(memcmp(lerr, lerr + 1,
1305074ba9b2SJens Wiklander 		  (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) {
1306074ba9b2SJens Wiklander 		V printf(
1307074ba9b2SJens Wiklander                     "(Contents of above free block have been overstored.)\n");
1308074ba9b2SJens Wiklander 		bufdump((void *) (((char *) b) + sizeof(struct bhead)));
1309074ba9b2SJens Wiklander 	    } else
1310074ba9b2SJens Wiklander #endif
1311074ba9b2SJens Wiklander 	    if (dumpfree) {
1312074ba9b2SJens Wiklander 		bufdump((void *) (((char *) b) + sizeof(struct bhead)));
1313074ba9b2SJens Wiklander 	    }
1314074ba9b2SJens Wiklander 	}
1315074ba9b2SJens Wiklander 	b = BFH(((char *) b) + bs);
1316074ba9b2SJens Wiklander     }
1317074ba9b2SJens Wiklander }
1318074ba9b2SJens Wiklander #endif /* BufDump */
1319074ba9b2SJens Wiklander 
1320074ba9b2SJens Wiklander #ifdef BufValid
1321074ba9b2SJens Wiklander 
1322074ba9b2SJens Wiklander /*  BPOOLV  --  Validate a buffer pool.  If NDEBUG isn't defined,
1323074ba9b2SJens Wiklander 		any error generates an assertion failure.  */
1324074ba9b2SJens Wiklander 
1325074ba9b2SJens Wiklander int bpoolv(buf)
1326074ba9b2SJens Wiklander   void *buf;
1327074ba9b2SJens Wiklander {
1328074ba9b2SJens Wiklander     struct bfhead *b = BFH(buf);
1329074ba9b2SJens Wiklander 
1330074ba9b2SJens Wiklander     while (b->bh.bsize != ESent) {
1331074ba9b2SJens Wiklander 	bufsize bs = b->bh.bsize;
1332074ba9b2SJens Wiklander 
1333074ba9b2SJens Wiklander 	if (bs < 0) {
1334074ba9b2SJens Wiklander 	    bs = -bs;
1335074ba9b2SJens Wiklander 	} else {
1336074ba9b2SJens Wiklander 			const char *lerr = "";
1337074ba9b2SJens Wiklander 
1338074ba9b2SJens Wiklander 	    assert(bs > 0);
1339074ba9b2SJens Wiklander 	    if (bs <= 0) {
1340074ba9b2SJens Wiklander 		return 0;
1341074ba9b2SJens Wiklander 	    }
1342074ba9b2SJens Wiklander 	    if ((b->ql.blink->ql.flink != b) ||
1343074ba9b2SJens Wiklander 		(b->ql.flink->ql.blink != b)) {
1344074ba9b2SJens Wiklander                 V printf("Free block: size %6ld bytes.  (Bad free list links)\n",
1345074ba9b2SJens Wiklander 		     (long) bs);
1346074ba9b2SJens Wiklander 		assert(0);
1347074ba9b2SJens Wiklander 		return 0;
1348074ba9b2SJens Wiklander 	    }
1349074ba9b2SJens Wiklander #ifdef FreeWipe
1350074ba9b2SJens Wiklander 	    lerr = ((char *) b) + sizeof(struct bfhead);
1351074ba9b2SJens Wiklander 	    if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) ||
1352074ba9b2SJens Wiklander 		(memcmp(lerr, lerr + 1,
1353074ba9b2SJens Wiklander 		  (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) {
1354074ba9b2SJens Wiklander 		V printf(
1355074ba9b2SJens Wiklander                     "(Contents of above free block have been overstored.)\n");
1356074ba9b2SJens Wiklander 		bufdump((void *) (((char *) b) + sizeof(struct bhead)));
1357074ba9b2SJens Wiklander 		assert(0);
1358074ba9b2SJens Wiklander 		return 0;
1359074ba9b2SJens Wiklander 	    }
1360074ba9b2SJens Wiklander #endif
1361074ba9b2SJens Wiklander 	}
1362074ba9b2SJens Wiklander 	b = BFH(((char *) b) + bs);
1363074ba9b2SJens Wiklander     }
1364074ba9b2SJens Wiklander     return 1;
1365074ba9b2SJens Wiklander }
1366074ba9b2SJens Wiklander #endif /* BufValid */
1367074ba9b2SJens Wiklander 
1368074ba9b2SJens Wiklander         /***********************\
1369074ba9b2SJens Wiklander 	*			*
1370074ba9b2SJens Wiklander 	* Built-in test program *
1371074ba9b2SJens Wiklander 	*			*
1372074ba9b2SJens Wiklander         \***********************/
1373074ba9b2SJens Wiklander 
137427e8d08dSJens Wiklander #if !defined(__KERNEL__) && !defined(__LDELF__) && defined(CFG_TA_BGET_TEST)
1375074ba9b2SJens Wiklander 
137627e8d08dSJens Wiklander #define TestProg 20000
1377074ba9b2SJens Wiklander 
1378074ba9b2SJens Wiklander #ifdef BECtl
1379074ba9b2SJens Wiklander #define PoolSize    300000	      /* Test buffer pool size */
1380074ba9b2SJens Wiklander #else
1381074ba9b2SJens Wiklander #define PoolSize    50000	      /* Test buffer pool size */
1382074ba9b2SJens Wiklander #endif
1383074ba9b2SJens Wiklander #define ExpIncr     32768	      /* Test expansion block size */
1384074ba9b2SJens Wiklander #define CompactTries 10 	      /* Maximum tries at compacting */
1385074ba9b2SJens Wiklander 
1386074ba9b2SJens Wiklander #define dumpAlloc   0		      /* Dump allocated buffers ? */
1387074ba9b2SJens Wiklander #define dumpFree    0		      /* Dump free buffers ? */
1388074ba9b2SJens Wiklander 
1389074ba9b2SJens Wiklander static char *bchain = NULL;	      /* Our private buffer chain */
1390074ba9b2SJens Wiklander static char *bp = NULL; 	      /* Our initial buffer pool */
1391074ba9b2SJens Wiklander 
139227e8d08dSJens Wiklander #ifdef UsingFloat
1393074ba9b2SJens Wiklander #include <math.h>
139427e8d08dSJens Wiklander #endif
1395074ba9b2SJens Wiklander 
1396074ba9b2SJens Wiklander static unsigned long int next = 1;
1397074ba9b2SJens Wiklander 
139827e8d08dSJens Wiklander static void *(*mymalloc)(size_t size);
139927e8d08dSJens Wiklander static void (*myfree)(void *ptr);
140027e8d08dSJens Wiklander 
140127e8d08dSJens Wiklander static struct bpoolset mypoolset = {
140227e8d08dSJens Wiklander 	.freelist = {
140327e8d08dSJens Wiklander 		.bh = { 0, 0},
140427e8d08dSJens Wiklander 		.ql = { &mypoolset.freelist, &mypoolset.freelist},
140527e8d08dSJens Wiklander 	}
140627e8d08dSJens Wiklander };
140727e8d08dSJens Wiklander 
1408074ba9b2SJens Wiklander /* Return next random integer */
1409074ba9b2SJens Wiklander 
141027e8d08dSJens Wiklander static int myrand(void)
1411074ba9b2SJens Wiklander {
1412074ba9b2SJens Wiklander 	next = next * 1103515245L + 12345;
1413074ba9b2SJens Wiklander 	return (unsigned int) (next / 65536L) % 32768L;
1414074ba9b2SJens Wiklander }
1415074ba9b2SJens Wiklander 
1416074ba9b2SJens Wiklander /* Set seed for random generator */
1417074ba9b2SJens Wiklander 
141827e8d08dSJens Wiklander static void mysrand(unsigned int seed)
1419074ba9b2SJens Wiklander {
1420074ba9b2SJens Wiklander 	next = seed;
1421074ba9b2SJens Wiklander }
1422074ba9b2SJens Wiklander 
1423074ba9b2SJens Wiklander /*  STATS  --  Edit statistics returned by bstats() or bstatse().  */
1424074ba9b2SJens Wiklander 
142527e8d08dSJens Wiklander static void stats(const char *when __maybe_unused,
142627e8d08dSJens Wiklander 		  struct bpoolset *poolset __maybe_unused)
1427074ba9b2SJens Wiklander {
142827e8d08dSJens Wiklander #ifdef BufStats
1429074ba9b2SJens Wiklander     bufsize cural, totfree, maxfree;
1430074ba9b2SJens Wiklander     long nget, nfree;
143127e8d08dSJens Wiklander #endif
1432074ba9b2SJens Wiklander #ifdef BECtl
1433074ba9b2SJens Wiklander     bufsize pincr;
1434074ba9b2SJens Wiklander     long totblocks, npget, nprel, ndget, ndrel;
1435074ba9b2SJens Wiklander #endif
1436074ba9b2SJens Wiklander 
143727e8d08dSJens Wiklander #ifdef BufStats
143827e8d08dSJens Wiklander     bstats(&cural, &totfree, &maxfree, &nget, &nfree, poolset);
1439074ba9b2SJens Wiklander     V printf(
1440074ba9b2SJens Wiklander         "%s: %ld gets, %ld releases.  %ld in use, %ld free, largest = %ld\n",
1441074ba9b2SJens Wiklander 	when, nget, nfree, (long) cural, (long) totfree, (long) maxfree);
144227e8d08dSJens Wiklander #endif
1443074ba9b2SJens Wiklander #ifdef BECtl
144427e8d08dSJens Wiklander     bstatse(&pincr, &totblocks, &npget, &nprel, &ndget, &ndrel, poolset);
1445074ba9b2SJens Wiklander     V printf(
1446074ba9b2SJens Wiklander          "  Blocks: size = %ld, %ld (%ld bytes) in use, %ld gets, %ld frees\n",
1447074ba9b2SJens Wiklander 	 (long)pincr, totblocks, pincr * totblocks, npget, nprel);
1448074ba9b2SJens Wiklander     V printf("  %ld direct gets, %ld direct frees\n", ndget, ndrel);
1449074ba9b2SJens Wiklander #endif /* BECtl */
1450074ba9b2SJens Wiklander }
1451074ba9b2SJens Wiklander 
1452074ba9b2SJens Wiklander #ifdef BECtl
1453074ba9b2SJens Wiklander static int protect = 0; 	      /* Disable compaction during bgetr() */
1454074ba9b2SJens Wiklander 
1455074ba9b2SJens Wiklander /*  BCOMPACT  --  Compaction call-back function.  */
1456074ba9b2SJens Wiklander 
1457074ba9b2SJens Wiklander static int bcompact(bsize, seq)
1458074ba9b2SJens Wiklander   bufsize bsize;
1459074ba9b2SJens Wiklander   int seq;
1460074ba9b2SJens Wiklander {
1461074ba9b2SJens Wiklander #ifdef CompactTries
1462074ba9b2SJens Wiklander     char *bc = bchain;
1463cc5981b2SJens Wiklander     int i = myrand() & 0x3;
1464074ba9b2SJens Wiklander 
1465074ba9b2SJens Wiklander #ifdef COMPACTRACE
1466074ba9b2SJens Wiklander     V printf("Compaction requested.  %ld bytes needed, sequence %d.\n",
1467074ba9b2SJens Wiklander 	(long) bsize, seq);
1468074ba9b2SJens Wiklander #endif
1469074ba9b2SJens Wiklander 
1470074ba9b2SJens Wiklander     if (protect || (seq > CompactTries)) {
1471074ba9b2SJens Wiklander #ifdef COMPACTRACE
1472074ba9b2SJens Wiklander         V printf("Compaction gave up.\n");
1473074ba9b2SJens Wiklander #endif
1474074ba9b2SJens Wiklander 	return 0;
1475074ba9b2SJens Wiklander     }
1476074ba9b2SJens Wiklander 
1477074ba9b2SJens Wiklander     /* Based on a random cast, release a random buffer in the list
1478074ba9b2SJens Wiklander        of allocated buffers. */
1479074ba9b2SJens Wiklander 
1480074ba9b2SJens Wiklander     while (i > 0 && bc != NULL) {
1481074ba9b2SJens Wiklander 	bc = *((char **) bc);
1482074ba9b2SJens Wiklander 	i--;
1483074ba9b2SJens Wiklander     }
1484074ba9b2SJens Wiklander     if (bc != NULL) {
1485074ba9b2SJens Wiklander 	char *fb;
1486074ba9b2SJens Wiklander 
1487074ba9b2SJens Wiklander 	fb = *((char **) bc);
1488074ba9b2SJens Wiklander 	if (fb != NULL) {
1489074ba9b2SJens Wiklander 	    *((char **) bc) = *((char **) fb);
1490074ba9b2SJens Wiklander 	    brel((void *) fb);
1491074ba9b2SJens Wiklander 	    return 1;
1492074ba9b2SJens Wiklander 	}
1493074ba9b2SJens Wiklander     }
1494074ba9b2SJens Wiklander 
1495074ba9b2SJens Wiklander #ifdef COMPACTRACE
1496074ba9b2SJens Wiklander     V printf("Compaction bailed out.\n");
1497074ba9b2SJens Wiklander #endif
1498074ba9b2SJens Wiklander #endif /* CompactTries */
1499074ba9b2SJens Wiklander     return 0;
1500074ba9b2SJens Wiklander }
1501074ba9b2SJens Wiklander 
1502074ba9b2SJens Wiklander /*  BEXPAND  --  Expand pool call-back function.  */
1503074ba9b2SJens Wiklander 
1504074ba9b2SJens Wiklander static void *bexpand(size)
1505074ba9b2SJens Wiklander   bufsize size;
1506074ba9b2SJens Wiklander {
1507074ba9b2SJens Wiklander     void *np = NULL;
1508074ba9b2SJens Wiklander     bufsize cural, totfree, maxfree;
1509074ba9b2SJens Wiklander     long nget, nfree;
1510074ba9b2SJens Wiklander 
1511074ba9b2SJens Wiklander     /* Don't expand beyond the total allocated size given by PoolSize. */
1512074ba9b2SJens Wiklander 
1513074ba9b2SJens Wiklander     bstats(&cural, &totfree, &maxfree, &nget, &nfree);
1514074ba9b2SJens Wiklander 
1515074ba9b2SJens Wiklander     if (cural < PoolSize) {
151627e8d08dSJens Wiklander 	np = (void *) mymalloc((unsigned) size);
1517074ba9b2SJens Wiklander     }
1518074ba9b2SJens Wiklander #ifdef EXPTRACE
1519074ba9b2SJens Wiklander     V printf("Expand pool by %ld -- %s.\n", (long) size,
1520074ba9b2SJens Wiklander         np == NULL ? "failed" : "succeeded");
1521074ba9b2SJens Wiklander #endif
1522074ba9b2SJens Wiklander     return np;
1523074ba9b2SJens Wiklander }
1524074ba9b2SJens Wiklander 
1525074ba9b2SJens Wiklander /*  BSHRINK  --  Shrink buffer pool call-back function.  */
1526074ba9b2SJens Wiklander 
1527074ba9b2SJens Wiklander static void bshrink(buf)
1528074ba9b2SJens Wiklander   void *buf;
1529074ba9b2SJens Wiklander {
1530074ba9b2SJens Wiklander     if (((char *) buf) == bp) {
1531074ba9b2SJens Wiklander #ifdef EXPTRACE
1532074ba9b2SJens Wiklander         V printf("Initial pool released.\n");
1533074ba9b2SJens Wiklander #endif
1534074ba9b2SJens Wiklander 	bp = NULL;
1535074ba9b2SJens Wiklander     }
1536074ba9b2SJens Wiklander #ifdef EXPTRACE
1537074ba9b2SJens Wiklander     V printf("Shrink pool.\n");
1538074ba9b2SJens Wiklander #endif
153927e8d08dSJens Wiklander     myfree((char *) buf);
1540074ba9b2SJens Wiklander }
1541074ba9b2SJens Wiklander 
1542074ba9b2SJens Wiklander #endif /* BECtl */
1543074ba9b2SJens Wiklander 
1544074ba9b2SJens Wiklander /*  Restrict buffer requests to those large enough to contain our pointer and
1545074ba9b2SJens Wiklander     small enough for the CPU architecture.  */
1546074ba9b2SJens Wiklander 
154727e8d08dSJens Wiklander static bufsize blimit(bufsize bs)
1548074ba9b2SJens Wiklander {
1549074ba9b2SJens Wiklander     if (bs < sizeof(char *)) {
1550074ba9b2SJens Wiklander 	bs = sizeof(char *);
1551074ba9b2SJens Wiklander     }
1552074ba9b2SJens Wiklander 
1553074ba9b2SJens Wiklander     /* This is written out in this ugly fashion because the
1554074ba9b2SJens Wiklander        cool expression in sizeof(int) that auto-configured
1555074ba9b2SJens Wiklander        to any length int befuddled some compilers. */
1556074ba9b2SJens Wiklander 
1557074ba9b2SJens Wiklander     if (sizeof(int) == 2) {
1558074ba9b2SJens Wiklander 	if (bs > 32767) {
1559074ba9b2SJens Wiklander 	    bs = 32767;
1560074ba9b2SJens Wiklander 	}
1561074ba9b2SJens Wiklander     } else {
1562074ba9b2SJens Wiklander 	if (bs > 200000) {
1563074ba9b2SJens Wiklander 	    bs = 200000;
1564074ba9b2SJens Wiklander 	}
1565074ba9b2SJens Wiklander     }
1566074ba9b2SJens Wiklander     return bs;
1567074ba9b2SJens Wiklander }
1568074ba9b2SJens Wiklander 
156927e8d08dSJens Wiklander int bget_main_test(void *(*malloc_func)(size_t), void (*free_func)(void *))
1570074ba9b2SJens Wiklander {
1571074ba9b2SJens Wiklander     int i;
157227e8d08dSJens Wiklander #ifdef UsingFloat
1573074ba9b2SJens Wiklander     double x;
157427e8d08dSJens Wiklander #endif
157527e8d08dSJens Wiklander 
157627e8d08dSJens Wiklander     mymalloc = malloc_func;
157727e8d08dSJens Wiklander     myfree = free_func;
1578074ba9b2SJens Wiklander 
1579074ba9b2SJens Wiklander     /* Seed the random number generator.  If Repeatable is defined, we
1580074ba9b2SJens Wiklander        always use the same seed.  Otherwise, we seed from the clock to
1581074ba9b2SJens Wiklander        shake things up from run to run. */
1582074ba9b2SJens Wiklander 
158327e8d08dSJens Wiklander     mysrand(1234);
1584074ba9b2SJens Wiklander 
1585074ba9b2SJens Wiklander     /*	Compute x such that pow(x, p) ranges between 1 and 4*ExpIncr as
1586074ba9b2SJens Wiklander 	p ranges from 0 to ExpIncr-1, with a concentration in the lower
1587074ba9b2SJens Wiklander 	numbers.  */
1588074ba9b2SJens Wiklander 
158927e8d08dSJens Wiklander #ifdef UsingFloat
1590074ba9b2SJens Wiklander     x = 4.0 * ExpIncr;
1591074ba9b2SJens Wiklander     x = log(x);
1592074ba9b2SJens Wiklander     x = exp(log(4.0 * ExpIncr) / (ExpIncr - 1.0));
159327e8d08dSJens Wiklander #endif
1594074ba9b2SJens Wiklander 
1595074ba9b2SJens Wiklander #ifdef BECtl
159627e8d08dSJens Wiklander     bectl(bcompact, bexpand, bshrink, (bufsize) ExpIncr, &mypoolset);
159727e8d08dSJens Wiklander     bp = mymalloc(ExpIncr);
1598074ba9b2SJens Wiklander     assert(bp != NULL);
1599074ba9b2SJens Wiklander     bpool((void *) bp, (bufsize) ExpIncr);
1600074ba9b2SJens Wiklander #else
160127e8d08dSJens Wiklander     bp = mymalloc(PoolSize);
1602074ba9b2SJens Wiklander     assert(bp != NULL);
160327e8d08dSJens Wiklander     bpool((void *) bp, (bufsize) PoolSize, &mypoolset);
1604074ba9b2SJens Wiklander #endif
1605074ba9b2SJens Wiklander 
160627e8d08dSJens Wiklander     stats("Create pool", &mypoolset);
160727e8d08dSJens Wiklander #ifdef BufValid
1608074ba9b2SJens Wiklander     V bpoolv((void *) bp);
160927e8d08dSJens Wiklander #endif
161027e8d08dSJens Wiklander #ifdef BufDump
1611074ba9b2SJens Wiklander     bpoold((void *) bp, dumpAlloc, dumpFree);
161227e8d08dSJens Wiklander #endif
1613074ba9b2SJens Wiklander 
1614074ba9b2SJens Wiklander     for (i = 0; i < TestProg; i++) {
1615074ba9b2SJens Wiklander 	char *cb;
161627e8d08dSJens Wiklander #ifdef UsingFloat
161727e8d08dSJens Wiklander 	bufsize bs = pow(x, (double) (myrand() & (ExpIncr - 1)));
161827e8d08dSJens Wiklander #else
1619cc5981b2SJens Wiklander 	bufsize bs = (myrand() & (ExpIncr * 4 - 1)) / (1 << (myrand() & 0x7));
162027e8d08dSJens Wiklander #endif
1621cc5981b2SJens Wiklander 	bufsize align = 0;
1622*17967299SJens Wiklander 	bufsize hdr_size = 0;
1623cc5981b2SJens Wiklander 
1624cc5981b2SJens Wiklander         switch (rand() & 0x3) {
1625cc5981b2SJens Wiklander         case 1:
1626cc5981b2SJens Wiklander             align = 32;
1627cc5981b2SJens Wiklander             break;
1628cc5981b2SJens Wiklander         case 2:
1629cc5981b2SJens Wiklander             align = 64;
1630cc5981b2SJens Wiklander             break;
1631cc5981b2SJens Wiklander         case 3:
1632cc5981b2SJens Wiklander             align = 128;
1633cc5981b2SJens Wiklander             break;
1634cc5981b2SJens Wiklander         default:
1635cc5981b2SJens Wiklander             break;
1636cc5981b2SJens Wiklander         }
1637074ba9b2SJens Wiklander 
1638*17967299SJens Wiklander         hdr_size = (rand() & 0x3) * BGET_HDR_QUANTUM;
1639*17967299SJens Wiklander 
1640074ba9b2SJens Wiklander 	assert(bs <= (((bufsize) 4) * ExpIncr));
1641074ba9b2SJens Wiklander 	bs = blimit(bs);
164227e8d08dSJens Wiklander 	if (myrand() & 0x400) {
1643*17967299SJens Wiklander 	    cb = (char *) bgetz(align, hdr_size, bs, &mypoolset);
1644074ba9b2SJens Wiklander 	} else {
1645*17967299SJens Wiklander 	    cb = (char *) bget(align, hdr_size, bs, &mypoolset);
1646074ba9b2SJens Wiklander 	}
1647074ba9b2SJens Wiklander 	if (cb == NULL) {
1648074ba9b2SJens Wiklander #ifdef EasyOut
1649074ba9b2SJens Wiklander 	    break;
1650074ba9b2SJens Wiklander #else
1651074ba9b2SJens Wiklander 	    char *bc = bchain;
1652074ba9b2SJens Wiklander 
1653074ba9b2SJens Wiklander 	    if (bc != NULL) {
1654074ba9b2SJens Wiklander 		char *fb;
1655074ba9b2SJens Wiklander 
1656074ba9b2SJens Wiklander 		fb = *((char **) bc);
1657074ba9b2SJens Wiklander 		if (fb != NULL) {
1658074ba9b2SJens Wiklander 		    *((char **) bc) = *((char **) fb);
165927e8d08dSJens Wiklander 		    brel((void *) fb, &mypoolset, true/*wipe*/);
1660074ba9b2SJens Wiklander 		}
1661074ba9b2SJens Wiklander 	    }
1662cc5981b2SJens Wiklander 	    continue;
1663074ba9b2SJens Wiklander #endif
1664074ba9b2SJens Wiklander 	}
1665*17967299SJens Wiklander         assert(!align || !(((unsigned long)cb + hdr_size) & (align - 1)));
1666074ba9b2SJens Wiklander 	*((char **) cb) = (char *) bchain;
1667074ba9b2SJens Wiklander 	bchain = cb;
1668074ba9b2SJens Wiklander 
1669074ba9b2SJens Wiklander 	/* Based on a random cast, release a random buffer in the list
1670074ba9b2SJens Wiklander 	   of allocated buffers. */
1671074ba9b2SJens Wiklander 
167227e8d08dSJens Wiklander 	if ((myrand() & 0x10) == 0) {
1673074ba9b2SJens Wiklander 	    char *bc = bchain;
167427e8d08dSJens Wiklander 	    int j = myrand() & 0x3;
1675074ba9b2SJens Wiklander 
167627e8d08dSJens Wiklander 	    while (j > 0 && bc != NULL) {
1677074ba9b2SJens Wiklander 		bc = *((char **) bc);
167827e8d08dSJens Wiklander 		j--;
1679074ba9b2SJens Wiklander 	    }
1680074ba9b2SJens Wiklander 	    if (bc != NULL) {
1681074ba9b2SJens Wiklander 		char *fb;
1682074ba9b2SJens Wiklander 
1683074ba9b2SJens Wiklander 		fb = *((char **) bc);
1684074ba9b2SJens Wiklander 		if (fb != NULL) {
1685074ba9b2SJens Wiklander 		    *((char **) bc) = *((char **) fb);
168627e8d08dSJens Wiklander 		    brel((void *) fb, &mypoolset, true/*wipe*/);
1687074ba9b2SJens Wiklander 		}
1688074ba9b2SJens Wiklander 	    }
1689074ba9b2SJens Wiklander 	}
1690074ba9b2SJens Wiklander 
1691074ba9b2SJens Wiklander 	/* Based on a random cast, reallocate a random buffer in the list
1692074ba9b2SJens Wiklander 	   to a random size */
1693074ba9b2SJens Wiklander 
169427e8d08dSJens Wiklander 	if ((myrand() & 0x20) == 0) {
1695074ba9b2SJens Wiklander 	    char *bc = bchain;
169627e8d08dSJens Wiklander 	    int j = myrand() & 0x3;
1697074ba9b2SJens Wiklander 
169827e8d08dSJens Wiklander 	    while (j > 0 && bc != NULL) {
1699074ba9b2SJens Wiklander 		bc = *((char **) bc);
170027e8d08dSJens Wiklander 		j--;
1701074ba9b2SJens Wiklander 	    }
1702074ba9b2SJens Wiklander 	    if (bc != NULL) {
1703074ba9b2SJens Wiklander 		char *fb;
1704074ba9b2SJens Wiklander 
1705074ba9b2SJens Wiklander 		fb = *((char **) bc);
1706074ba9b2SJens Wiklander 		if (fb != NULL) {
1707074ba9b2SJens Wiklander 		    char *newb;
1708074ba9b2SJens Wiklander 
170927e8d08dSJens Wiklander #ifdef UsingFloat
171027e8d08dSJens Wiklander 		    bs = pow(x, (double) (myrand() & (ExpIncr - 1)));
171127e8d08dSJens Wiklander #else
171227e8d08dSJens Wiklander 		    bs = (rand() & (ExpIncr * 4 - 1)) / (1 << (rand() & 0x7));
171327e8d08dSJens Wiklander #endif
1714074ba9b2SJens Wiklander 		    bs = blimit(bs);
1715074ba9b2SJens Wiklander #ifdef BECtl
1716074ba9b2SJens Wiklander 		    protect = 1;      /* Protect against compaction */
1717074ba9b2SJens Wiklander #endif
1718*17967299SJens Wiklander 		    newb = (char *) bgetr((void *) fb, align, hdr_size, bs, &mypoolset);
1719074ba9b2SJens Wiklander #ifdef BECtl
1720074ba9b2SJens Wiklander 		    protect = 0;
1721074ba9b2SJens Wiklander #endif
1722074ba9b2SJens Wiklander 		    if (newb != NULL) {
1723*17967299SJens Wiklander                         assert(!align || !(((unsigned long)newb + hdr_size) &
1724*17967299SJens Wiklander                                            (align - 1)));
1725074ba9b2SJens Wiklander 			*((char **) bc) = newb;
1726074ba9b2SJens Wiklander 		    }
1727074ba9b2SJens Wiklander 		}
1728074ba9b2SJens Wiklander 	    }
1729074ba9b2SJens Wiklander 	}
1730074ba9b2SJens Wiklander     }
173127e8d08dSJens Wiklander     stats("\nAfter allocation", &mypoolset);
1732074ba9b2SJens Wiklander     if (bp != NULL) {
173327e8d08dSJens Wiklander #ifdef BufValid
1734074ba9b2SJens Wiklander 	V bpoolv((void *) bp);
173527e8d08dSJens Wiklander #endif
173627e8d08dSJens Wiklander #ifdef BufDump
1737074ba9b2SJens Wiklander 	bpoold((void *) bp, dumpAlloc, dumpFree);
173827e8d08dSJens Wiklander #endif
1739074ba9b2SJens Wiklander     }
1740074ba9b2SJens Wiklander 
1741074ba9b2SJens Wiklander     while (bchain != NULL) {
1742074ba9b2SJens Wiklander 	char *buf = bchain;
1743074ba9b2SJens Wiklander 
1744074ba9b2SJens Wiklander 	bchain = *((char **) buf);
174527e8d08dSJens Wiklander 	brel((void *) buf, &mypoolset, true/*wipe*/);
1746074ba9b2SJens Wiklander     }
174727e8d08dSJens Wiklander     stats("\nAfter release", &mypoolset);
1748074ba9b2SJens Wiklander #ifndef BECtl
1749074ba9b2SJens Wiklander     if (bp != NULL) {
175027e8d08dSJens Wiklander #ifdef BufValid
1751074ba9b2SJens Wiklander 	V bpoolv((void *) bp);
175227e8d08dSJens Wiklander #endif
175327e8d08dSJens Wiklander #ifdef BufDump
1754074ba9b2SJens Wiklander 	bpoold((void *) bp, dumpAlloc, dumpFree);
175527e8d08dSJens Wiklander #endif
1756074ba9b2SJens Wiklander     }
1757074ba9b2SJens Wiklander #endif
1758074ba9b2SJens Wiklander 
1759074ba9b2SJens Wiklander     return 0;
1760074ba9b2SJens Wiklander }
1761074ba9b2SJens Wiklander #endif
1762