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 */
540*f288234fSJens Wiklander uint64_t free2_sum; /* Sum of size^2 of each free chunk */
541074ba9b2SJens Wiklander #ifdef BECtl
542b7f0111dSVolodymyr Babchuk long numpblk; /* Number of pool blocks */
543b7f0111dSVolodymyr Babchuk long numpget; /* Number of block gets and rels */
544b7f0111dSVolodymyr Babchuk long numprel;
545b7f0111dSVolodymyr Babchuk long numdget; /* Number of direct gets and rels */
546b7f0111dSVolodymyr Babchuk long numdrel;
547074ba9b2SJens Wiklander #endif /* BECtl */
548074ba9b2SJens Wiklander #endif /* BufStats */
549074ba9b2SJens Wiklander
550074ba9b2SJens Wiklander #ifdef BECtl
551074ba9b2SJens Wiklander /* Automatic expansion block management functions */
552074ba9b2SJens Wiklander
553b7f0111dSVolodymyr Babchuk int (*compfcn) _((bufsize sizereq, int sequence));
554b7f0111dSVolodymyr Babchuk void *(*acqfcn) _((bufsize size));
555b7f0111dSVolodymyr Babchuk void (*relfcn) _((void *buf));
556074ba9b2SJens Wiklander
557b7f0111dSVolodymyr Babchuk bufsize exp_incr; /* Expansion block size */
558b7f0111dSVolodymyr Babchuk bufsize pool_len; /* 0: no bpool calls have been made
559074ba9b2SJens Wiklander -1: not all pool blocks are
560074ba9b2SJens Wiklander the same size
561074ba9b2SJens Wiklander >0: (common) block size for all
562074ba9b2SJens Wiklander bpool calls made so far
563074ba9b2SJens Wiklander */
564074ba9b2SJens Wiklander #endif
565b7f0111dSVolodymyr Babchuk };
566074ba9b2SJens Wiklander
567074ba9b2SJens Wiklander /* Minimum allocation quantum: */
568074ba9b2SJens Wiklander
569074ba9b2SJens Wiklander #define QLSize (sizeof(struct qlinks))
570074ba9b2SJens Wiklander #define SizeQ ((SizeQuant > QLSize) ? SizeQuant : QLSize)
571074ba9b2SJens Wiklander
572074ba9b2SJens Wiklander #define V (void) /* To denote unwanted returned values */
573074ba9b2SJens Wiklander
574074ba9b2SJens Wiklander /* End sentinel: value placed in bsize field of dummy block delimiting
575074ba9b2SJens Wiklander end of pool block. The most negative number which will fit in a
576074ba9b2SJens Wiklander bufsize, defined in a way that the compiler will accept. */
577074ba9b2SJens Wiklander
578074ba9b2SJens Wiklander #define ESent ((bufsize) (-(((1L << (sizeof(bufsize) * 8 - 2)) - 1) * 2) - 2))
579074ba9b2SJens Wiklander
buf_get_pos(struct bfhead * bf,bufsize align,bufsize hdr_size,bufsize size)58017967299SJens Wiklander static bufsize buf_get_pos(struct bfhead *bf, bufsize align, bufsize hdr_size,
58117967299SJens Wiklander bufsize size)
582cc5981b2SJens Wiklander {
583cc5981b2SJens Wiklander unsigned long buf = 0;
584cc5981b2SJens Wiklander bufsize pos = 0;
585cc5981b2SJens Wiklander
586cc5981b2SJens Wiklander if (bf->bh.bsize < size)
587cc5981b2SJens Wiklander return -1;
588cc5981b2SJens Wiklander
589cc5981b2SJens Wiklander /*
59017967299SJens Wiklander * plus sizeof(struct bhead) and hdr_size since buf will follow just
59117967299SJens Wiklander * after a struct bhead and an eventual extra header.
592cc5981b2SJens Wiklander */
59317967299SJens Wiklander buf = (unsigned long)bf + bf->bh.bsize - size + sizeof(struct bhead) +
59417967299SJens Wiklander hdr_size;
595cc5981b2SJens Wiklander buf &= ~(align - 1);
59617967299SJens Wiklander pos = buf - (unsigned long)bf - sizeof(struct bhead) - hdr_size;
597cc5981b2SJens Wiklander
598cc5981b2SJens Wiklander if (pos == 0) /* exact match */
599cc5981b2SJens Wiklander return pos;
600cc5981b2SJens Wiklander if (pos >= SizeQ + sizeof(struct bhead)) /* room for an empty buffer */
601cc5981b2SJens Wiklander return pos;
602cc5981b2SJens Wiklander
603cc5981b2SJens Wiklander return -1;
604cc5981b2SJens Wiklander }
605cc5981b2SJens Wiklander
get_free2_sum(struct bpoolset * poolset)606*f288234fSJens Wiklander static uint64_t __maybe_unused get_free2_sum(struct bpoolset *poolset)
607*f288234fSJens Wiklander {
608*f288234fSJens Wiklander struct bfhead *b = poolset->freelist.ql.flink;
609*f288234fSJens Wiklander uint64_t free2_sum = 0;
610*f288234fSJens Wiklander uint64_t bs = 0;
611*f288234fSJens Wiklander
612*f288234fSJens Wiklander while (b != &poolset->freelist) {
613*f288234fSJens Wiklander bs = b->bh.bsize;
614*f288234fSJens Wiklander free2_sum += bs * bs;
615*f288234fSJens Wiklander b = b->ql.flink; /* Link to next buffer */
616*f288234fSJens Wiklander }
617*f288234fSJens Wiklander
618*f288234fSJens Wiklander return free2_sum;
619*f288234fSJens Wiklander }
620*f288234fSJens Wiklander
621*f288234fSJens Wiklander /*
622*f288234fSJens Wiklander * update_free2_sum() - cumulative update of the free^2 sum
623*f288234fSJens Wiklander * @poolset: The addressed poolset
624*f288234fSJens Wiklander * @rem_sz: Size of a removed free block, 0 if unused
625*f288234fSJens Wiklander * @rem_sz2: Size of one more removed free block, 0 if unused
626*f288234fSJens Wiklander * @add_sz: Size of an added free block, 0 if unused
627*f288234fSJens Wiklander *
628*f288234fSJens Wiklander * As free blocks are removed, added, or merged the sum of the size ^ 2 of
629*f288234fSJens Wiklander * all free blocks needs to be updated. The most complicated case is where
630*f288234fSJens Wiklander * two free blocks are merged into one free block, both the old sizes must be
631*f288234fSJens Wiklander * supplied and the new size.
632*f288234fSJens Wiklander */
update_free2_sum(struct bpoolset * poolset __maybe_unused,uint64_t rem_sz __maybe_unused,uint64_t rem_sz2 __maybe_unused,uint64_t add_sz __maybe_unused)633*f288234fSJens Wiklander static void update_free2_sum(struct bpoolset *poolset __maybe_unused,
634*f288234fSJens Wiklander uint64_t rem_sz __maybe_unused,
635*f288234fSJens Wiklander uint64_t rem_sz2 __maybe_unused,
636*f288234fSJens Wiklander uint64_t add_sz __maybe_unused)
637*f288234fSJens Wiklander {
638*f288234fSJens Wiklander #ifdef BufStats
639*f288234fSJens Wiklander uint64_t r2 = rem_sz * rem_sz + rem_sz2 * rem_sz2;
640*f288234fSJens Wiklander uint64_t a2 = add_sz * add_sz;
641*f288234fSJens Wiklander uint64_t f2s __maybe_unused = get_free2_sum(poolset);
642*f288234fSJens Wiklander
643*f288234fSJens Wiklander assert(f2s == poolset->free2_sum - r2 + a2);
644*f288234fSJens Wiklander assert(poolset->free2_sum >= r2);
645*f288234fSJens Wiklander poolset->free2_sum -= r2;
646*f288234fSJens Wiklander poolset->free2_sum += a2;
647*f288234fSJens Wiklander #endif
648*f288234fSJens Wiklander }
649*f288234fSJens Wiklander
650074ba9b2SJens Wiklander /* BGET -- Allocate a buffer. */
651074ba9b2SJens Wiklander
bget(requested_align,hdr_size,requested_size,poolset)65217967299SJens Wiklander void *bget(requested_align, hdr_size, requested_size, poolset)
653cc5981b2SJens Wiklander bufsize requested_align;
65417967299SJens Wiklander bufsize hdr_size;
655074ba9b2SJens Wiklander bufsize requested_size;
656b7f0111dSVolodymyr Babchuk struct bpoolset *poolset;
657074ba9b2SJens Wiklander {
658cc5981b2SJens Wiklander bufsize align = requested_align;
659074ba9b2SJens Wiklander bufsize size = requested_size;
660cc5981b2SJens Wiklander bufsize pos;
661074ba9b2SJens Wiklander struct bfhead *b;
662074ba9b2SJens Wiklander #ifdef BestFit
663074ba9b2SJens Wiklander struct bfhead *best;
664074ba9b2SJens Wiklander #endif
665074ba9b2SJens Wiklander void *buf;
666074ba9b2SJens Wiklander #ifdef BECtl
667074ba9b2SJens Wiklander int compactseq = 0;
668074ba9b2SJens Wiklander #endif
669074ba9b2SJens Wiklander
670074ba9b2SJens Wiklander assert(size > 0);
67117967299SJens Wiklander COMPILE_TIME_ASSERT(BGET_HDR_QUANTUM == SizeQ);
67217967299SJens Wiklander
673cc5981b2SJens Wiklander if (align < 0 || (align > 0 && !IS_POWER_OF_TWO((unsigned long)align)))
674cc5981b2SJens Wiklander return NULL;
67517967299SJens Wiklander if (hdr_size % BGET_HDR_QUANTUM != 0)
67617967299SJens Wiklander return NULL;
677074ba9b2SJens Wiklander
678074ba9b2SJens Wiklander if (size < SizeQ) { /* Need at least room for the */
679074ba9b2SJens Wiklander size = SizeQ; /* queue links. */
680074ba9b2SJens Wiklander }
681cc5981b2SJens Wiklander if (align < SizeQ)
682cc5981b2SJens Wiklander align = SizeQ;
683074ba9b2SJens Wiklander #ifdef SizeQuant
684074ba9b2SJens Wiklander #if SizeQuant > 1
6857539e8c3SPeiKan Tsai if (ADD_OVERFLOW(size, SizeQuant - 1, &size))
6867539e8c3SPeiKan Tsai return NULL;
6877539e8c3SPeiKan Tsai
6887539e8c3SPeiKan Tsai size = ROUNDDOWN(size, SizeQuant);
689074ba9b2SJens Wiklander #endif
690074ba9b2SJens Wiklander #endif
691074ba9b2SJens Wiklander
6927539e8c3SPeiKan Tsai /* Add overhead in allocated buffer to size required. */
6937539e8c3SPeiKan Tsai if (ADD_OVERFLOW(size, sizeof(struct bhead), &size))
6947539e8c3SPeiKan Tsai return NULL;
69517967299SJens Wiklander if (ADD_OVERFLOW(size, hdr_size, &size))
69617967299SJens Wiklander return NULL;
697074ba9b2SJens Wiklander
698074ba9b2SJens Wiklander #ifdef BECtl
699074ba9b2SJens Wiklander /* If a compact function was provided in the call to bectl(), wrap
700074ba9b2SJens Wiklander a loop around the allocation process to allow compaction to
701074ba9b2SJens Wiklander intervene in case we don't find a suitable buffer in the chain. */
702074ba9b2SJens Wiklander
703074ba9b2SJens Wiklander while (1) {
704074ba9b2SJens Wiklander #endif
705b7f0111dSVolodymyr Babchuk b = poolset->freelist.ql.flink;
706074ba9b2SJens Wiklander #ifdef BestFit
707b7f0111dSVolodymyr Babchuk best = &poolset->freelist;
708074ba9b2SJens Wiklander #endif
709074ba9b2SJens Wiklander
710074ba9b2SJens Wiklander
711074ba9b2SJens Wiklander /* Scan the free list searching for the first buffer big enough
712074ba9b2SJens Wiklander to hold the requested size buffer. */
713074ba9b2SJens Wiklander
714074ba9b2SJens Wiklander #ifdef BestFit
715b7f0111dSVolodymyr Babchuk while (b != &poolset->freelist) {
716cc5981b2SJens Wiklander assert(b->bh.prevfree == 0);
71717967299SJens Wiklander pos = buf_get_pos(b, align, hdr_size, size);
718cc5981b2SJens Wiklander if (pos >= 0) {
719b7f0111dSVolodymyr Babchuk if ((best == &poolset->freelist) ||
720b7f0111dSVolodymyr Babchuk (b->bh.bsize < best->bh.bsize)) {
721074ba9b2SJens Wiklander best = b;
722074ba9b2SJens Wiklander }
723074ba9b2SJens Wiklander }
724074ba9b2SJens Wiklander b = b->ql.flink; /* Link to next buffer */
725074ba9b2SJens Wiklander }
726074ba9b2SJens Wiklander b = best;
727074ba9b2SJens Wiklander #endif /* BestFit */
728074ba9b2SJens Wiklander
729b7f0111dSVolodymyr Babchuk while (b != &poolset->freelist) {
73017967299SJens Wiklander pos = buf_get_pos(b, align, hdr_size, size);
731cc5981b2SJens Wiklander if (pos >= 0) {
732cc5981b2SJens Wiklander struct bhead *b_alloc = BH((char *)b + pos);
733cc5981b2SJens Wiklander struct bhead *b_next = BH((char *)b + b->bh.bsize);
734*f288234fSJens Wiklander bufsize rem_sz = b->bh.bsize;
735*f288234fSJens Wiklander bufsize add_sz = pos;
736074ba9b2SJens Wiklander
737cc5981b2SJens Wiklander assert(b_next->prevfree == b->bh.bsize);
738074ba9b2SJens Wiklander
739cc5981b2SJens Wiklander /*
740cc5981b2SJens Wiklander * Zero the back pointer in the next buffer in memory
741cc5981b2SJens Wiklander * to indicate that this buffer is allocated.
742cc5981b2SJens Wiklander */
743cc5981b2SJens Wiklander b_next->prevfree = 0;
744074ba9b2SJens Wiklander
745074ba9b2SJens Wiklander assert(b->ql.blink->ql.flink == b);
746074ba9b2SJens Wiklander assert(b->ql.flink->ql.blink == b);
747cc5981b2SJens Wiklander
748cc5981b2SJens Wiklander if (pos == 0) {
749cc5981b2SJens Wiklander /*
750cc5981b2SJens Wiklander * Need to allocate from the beginning of this free block.
751cc5981b2SJens Wiklander * Unlink the block and mark it as allocated.
752cc5981b2SJens Wiklander */
753074ba9b2SJens Wiklander b->ql.blink->ql.flink = b->ql.flink;
754074ba9b2SJens Wiklander b->ql.flink->ql.blink = b->ql.blink;
755074ba9b2SJens Wiklander
756cc5981b2SJens Wiklander /* Negate size to mark buffer allocated. */
757cc5981b2SJens Wiklander b->bh.bsize = -b->bh.bsize;
758cc5981b2SJens Wiklander } else {
759cc5981b2SJens Wiklander /*
760cc5981b2SJens Wiklander * Carve out the memory allocation from the end of this
761cc5981b2SJens Wiklander * free block. Negative size to mark buffer allocated.
762cc5981b2SJens Wiklander */
763cc5981b2SJens Wiklander b_alloc->bsize = -(b->bh.bsize - pos);
764cc5981b2SJens Wiklander b_alloc->prevfree = pos;
765cc5981b2SJens Wiklander b->bh.bsize = pos;
766cc5981b2SJens Wiklander }
767*f288234fSJens Wiklander update_free2_sum(poolset, rem_sz, 0, add_sz);
768cc5981b2SJens Wiklander
769cc5981b2SJens Wiklander assert(b_alloc->bsize < 0);
770cc5981b2SJens Wiklander /*
771cc5981b2SJens Wiklander * At this point is b_alloc pointing to the allocated
772cc5981b2SJens Wiklander * buffer and b_next at the buffer following. b might be a
773cc5981b2SJens Wiklander * free block or a used block now.
774cc5981b2SJens Wiklander */
775cc5981b2SJens Wiklander if (-b_alloc->bsize - size > SizeQ + sizeof(struct bhead)) {
776cc5981b2SJens Wiklander /*
777cc5981b2SJens Wiklander * b_alloc has too much unused memory at the
778cc5981b2SJens Wiklander * end we need to split the block and register that
779cc5981b2SJens Wiklander * last part as free.
780cc5981b2SJens Wiklander */
781cc5981b2SJens Wiklander b = BFH((char *)b_alloc + size);
782cc5981b2SJens Wiklander b->bh.bsize = -b_alloc->bsize - size;
783cc5981b2SJens Wiklander b->bh.prevfree = 0;
784cc5981b2SJens Wiklander b_alloc->bsize += b->bh.bsize;
785cc5981b2SJens Wiklander
786cc5981b2SJens Wiklander assert(poolset->freelist.ql.blink->ql.flink ==
787cc5981b2SJens Wiklander &poolset->freelist);
788cc5981b2SJens Wiklander assert(poolset->freelist.ql.flink->ql.blink ==
789cc5981b2SJens Wiklander &poolset->freelist);
790cc5981b2SJens Wiklander b->ql.flink = &poolset->freelist;
791cc5981b2SJens Wiklander b->ql.blink = poolset->freelist.ql.blink;
792cc5981b2SJens Wiklander poolset->freelist.ql.blink = b;
793cc5981b2SJens Wiklander b->ql.blink->ql.flink = b;
794cc5981b2SJens Wiklander
795cc5981b2SJens Wiklander assert(BH((char *)b + b->bh.bsize) == b_next);
796cc5981b2SJens Wiklander b_next->prevfree = b->bh.bsize;
797*f288234fSJens Wiklander update_free2_sum(poolset, 0, 0, b->bh.bsize);
798cc5981b2SJens Wiklander }
799cc5981b2SJens Wiklander
800074ba9b2SJens Wiklander #ifdef BufStats
801cc5981b2SJens Wiklander poolset->totalloc -= b_alloc->bsize;
802b7f0111dSVolodymyr Babchuk poolset->numget++; /* Increment number of bget() calls */
803074ba9b2SJens Wiklander #endif
804cc5981b2SJens Wiklander buf = (char *)b_alloc + sizeof(struct bhead);
805074ba9b2SJens Wiklander return buf;
806074ba9b2SJens Wiklander }
807074ba9b2SJens Wiklander b = b->ql.flink; /* Link to next buffer */
808074ba9b2SJens Wiklander }
809074ba9b2SJens Wiklander #ifdef BECtl
810074ba9b2SJens Wiklander
811074ba9b2SJens Wiklander /* We failed to find a buffer. If there's a compact function
812074ba9b2SJens Wiklander defined, notify it of the size requested. If it returns
813074ba9b2SJens Wiklander TRUE, try the allocation again. */
814074ba9b2SJens Wiklander
815b7f0111dSVolodymyr Babchuk if ((poolset->compfcn == NULL) ||
816b7f0111dSVolodymyr Babchuk (!(poolset->compfcn)(size, ++compactseq))) {
817074ba9b2SJens Wiklander break;
818074ba9b2SJens Wiklander }
819074ba9b2SJens Wiklander }
820074ba9b2SJens Wiklander
821074ba9b2SJens Wiklander /* No buffer available with requested size free. */
822074ba9b2SJens Wiklander
823074ba9b2SJens Wiklander /* Don't give up yet -- look in the reserve supply. */
824074ba9b2SJens Wiklander
825b7f0111dSVolodymyr Babchuk if (poolset->acqfcn != NULL) {
826cc5981b2SJens Wiklander if (size > exp_incr - sizeof(struct bfhead) - align) {
827074ba9b2SJens Wiklander
828074ba9b2SJens Wiklander /* Request is too large to fit in a single expansion
829074ba9b2SJens Wiklander block. Try to satisy it by a direct buffer acquisition. */
830cc5981b2SJens Wiklander char *p;
831074ba9b2SJens Wiklander
832074ba9b2SJens Wiklander size += sizeof(struct bdhead) - sizeof(struct bhead);
833cc5981b2SJens Wiklander if (align > QLSize)
834cc5981b2SJens Wiklander size += align;
835cc5981b2SJens Wiklander p = poolset->acqfcn(size);
836cc5981b2SJens Wiklander if (p != NULL) {
837cc5981b2SJens Wiklander struct bdhead *bdh;
838cc5981b2SJens Wiklander
839cc5981b2SJens Wiklander if (align <= QLSize) {
840cc5981b2SJens Wiklander bdh = BDH(p);
841cc5981b2SJens Wiklander buf = bdh + 1;
842cc5981b2SJens Wiklander } else {
84317967299SJens Wiklander unsigned long tp = (unsigned long)p;
84417967299SJens Wiklander
84517967299SJens Wiklander tp += sizeof(*bdh) + hdr_size + align;
84617967299SJens Wiklander tp &= ~(align - 1);
84717967299SJens Wiklander tp -= hdr_size;
84817967299SJens Wiklander buf = (void *)tp;
849cc5981b2SJens Wiklander bdh = BDH((char *)buf - sizeof(*bdh));
850cc5981b2SJens Wiklander }
851074ba9b2SJens Wiklander
852074ba9b2SJens Wiklander /* Mark the buffer special by setting the size field
853074ba9b2SJens Wiklander of its header to zero. */
854074ba9b2SJens Wiklander bdh->bh.bsize = 0;
855074ba9b2SJens Wiklander bdh->bh.prevfree = 0;
856074ba9b2SJens Wiklander bdh->tsize = size;
857cc5981b2SJens Wiklander bdh->offs = (unsigned long)bdh - (unsigned long)p;
858074ba9b2SJens Wiklander #ifdef BufStats
859b7f0111dSVolodymyr Babchuk poolset->totalloc += size;
860b7f0111dSVolodymyr Babchuk poolset->numget++; /* Increment number of bget() calls */
861b7f0111dSVolodymyr Babchuk poolset->numdget++; /* Direct bget() call count */
862074ba9b2SJens Wiklander #endif
863074ba9b2SJens Wiklander return buf;
864074ba9b2SJens Wiklander }
865074ba9b2SJens Wiklander
866074ba9b2SJens Wiklander } else {
867074ba9b2SJens Wiklander
868074ba9b2SJens Wiklander /* Try to obtain a new expansion block */
869074ba9b2SJens Wiklander
870074ba9b2SJens Wiklander void *newpool;
871074ba9b2SJens Wiklander
872b7f0111dSVolodymyr Babchuk if ((newpool = poolset->acqfcn((bufsize) exp_incr)) != NULL) {
873b7f0111dSVolodymyr Babchuk bpool(newpool, exp_incr, poolset);
87417967299SJens Wiklander buf = bget(align, hdr_size, requested_size, pool); /* This can't, I say, can't
875074ba9b2SJens Wiklander get into a loop. */
876074ba9b2SJens Wiklander return buf;
877074ba9b2SJens Wiklander }
878074ba9b2SJens Wiklander }
879074ba9b2SJens Wiklander }
880074ba9b2SJens Wiklander
881074ba9b2SJens Wiklander /* Still no buffer available */
882074ba9b2SJens Wiklander
883074ba9b2SJens Wiklander #endif /* BECtl */
884074ba9b2SJens Wiklander
885074ba9b2SJens Wiklander return NULL;
886074ba9b2SJens Wiklander }
887074ba9b2SJens Wiklander
888074ba9b2SJens Wiklander /* BGETZ -- Allocate a buffer and clear its contents to zero. We clear
889074ba9b2SJens Wiklander the entire contents of the buffer to zero, not just the
890074ba9b2SJens Wiklander region requested by the caller. */
891074ba9b2SJens Wiklander
bgetz(align,hdr_size,size,poolset)89217967299SJens Wiklander void *bgetz(align, hdr_size, size, poolset)
893cc5981b2SJens Wiklander bufsize align;
89417967299SJens Wiklander bufsize hdr_size;
895074ba9b2SJens Wiklander bufsize size;
896b7f0111dSVolodymyr Babchuk struct bpoolset *poolset;
897074ba9b2SJens Wiklander {
89817967299SJens Wiklander char *buf = (char *) bget(align, hdr_size, size, poolset);
899074ba9b2SJens Wiklander
900074ba9b2SJens Wiklander if (buf != NULL) {
901074ba9b2SJens Wiklander struct bhead *b;
902074ba9b2SJens Wiklander bufsize rsize;
903074ba9b2SJens Wiklander
904074ba9b2SJens Wiklander b = BH(buf - sizeof(struct bhead));
905074ba9b2SJens Wiklander rsize = -(b->bsize);
906074ba9b2SJens Wiklander if (rsize == 0) {
907074ba9b2SJens Wiklander struct bdhead *bd;
908074ba9b2SJens Wiklander
909074ba9b2SJens Wiklander bd = BDH(buf - sizeof(struct bdhead));
910cc5981b2SJens Wiklander rsize = bd->tsize - sizeof(struct bdhead) - bd->offs;
911074ba9b2SJens Wiklander } else {
912074ba9b2SJens Wiklander rsize -= sizeof(struct bhead);
913074ba9b2SJens Wiklander }
914074ba9b2SJens Wiklander assert(rsize >= size);
915e103c301SJens Wiklander V memset_unchecked(buf, 0, (MemSize) rsize);
916074ba9b2SJens Wiklander }
917074ba9b2SJens Wiklander return ((void *) buf);
918074ba9b2SJens Wiklander }
919074ba9b2SJens Wiklander
920074ba9b2SJens Wiklander /* BGETR -- Reallocate a buffer. This is a minimal implementation,
921074ba9b2SJens Wiklander simply in terms of brel() and bget(). It could be
922074ba9b2SJens Wiklander enhanced to allow the buffer to grow into adjacent free
923074ba9b2SJens Wiklander blocks and to avoid moving data unnecessarily. */
924074ba9b2SJens Wiklander
bgetr(buf,align,hdr_size,size,poolset)92517967299SJens Wiklander void *bgetr(buf, align, hdr_size, size, poolset)
926074ba9b2SJens Wiklander void *buf;
927cc5981b2SJens Wiklander bufsize align;
92817967299SJens Wiklander bufsize hdr_size;
929074ba9b2SJens Wiklander bufsize size;
930b7f0111dSVolodymyr Babchuk struct bpoolset *poolset;
931074ba9b2SJens Wiklander {
932074ba9b2SJens Wiklander void *nbuf;
933074ba9b2SJens Wiklander bufsize osize; /* Old size of buffer */
934074ba9b2SJens Wiklander struct bhead *b;
935074ba9b2SJens Wiklander
93617967299SJens Wiklander if ((nbuf = bget(align, hdr_size, size, poolset)) == NULL) { /* Acquire new buffer */
937074ba9b2SJens Wiklander return NULL;
938074ba9b2SJens Wiklander }
939074ba9b2SJens Wiklander if (buf == NULL) {
940074ba9b2SJens Wiklander return nbuf;
941074ba9b2SJens Wiklander }
942074ba9b2SJens Wiklander b = BH(((char *) buf) - sizeof(struct bhead));
943074ba9b2SJens Wiklander osize = -b->bsize;
944074ba9b2SJens Wiklander #ifdef BECtl
945074ba9b2SJens Wiklander if (osize == 0) {
946074ba9b2SJens Wiklander /* Buffer acquired directly through acqfcn. */
947074ba9b2SJens Wiklander struct bdhead *bd;
948074ba9b2SJens Wiklander
949074ba9b2SJens Wiklander bd = BDH(((char *) buf) - sizeof(struct bdhead));
950cc5981b2SJens Wiklander osize = bd->tsize - sizeof(struct bdhead) - bd->offs;
951074ba9b2SJens Wiklander } else
952074ba9b2SJens Wiklander #endif
953074ba9b2SJens Wiklander osize -= sizeof(struct bhead);
954074ba9b2SJens Wiklander assert(osize > 0);
955466162e2SJens Wiklander V memcpy_unchecked((char *) nbuf, (char *) buf, /* Copy the data */
956074ba9b2SJens Wiklander (MemSize) ((size < osize) ? size : osize));
95796c1d8c5SJens Wiklander #ifndef __KERNEL__
95896c1d8c5SJens Wiklander /* User space reallocations are always zeroed */
95996c1d8c5SJens Wiklander if (size > osize)
960466162e2SJens Wiklander V memset_unchecked((char *) nbuf + osize, 0, size - osize);
96196c1d8c5SJens Wiklander #endif
9624e570655SJerome Forissier brel(buf, poolset, false /* !wipe */);
963074ba9b2SJens Wiklander return nbuf;
964074ba9b2SJens Wiklander }
965074ba9b2SJens Wiklander
966074ba9b2SJens Wiklander /* BREL -- Release a buffer. */
967074ba9b2SJens Wiklander
brel(buf,poolset,wipe)9684e570655SJerome Forissier void brel(buf, poolset, wipe)
969074ba9b2SJens Wiklander void *buf;
970b7f0111dSVolodymyr Babchuk struct bpoolset *poolset;
9714e570655SJerome Forissier int wipe;
972074ba9b2SJens Wiklander {
973074ba9b2SJens Wiklander struct bfhead *b, *bn;
9740d4767a9SZengxx char *wipe_start;
9750d4767a9SZengxx bufsize wipe_size;
976*f288234fSJens Wiklander bufsize add_sz;
977*f288234fSJens Wiklander bufsize rem_sz;
978*f288234fSJens Wiklander bufsize rem_sz2;
979074ba9b2SJens Wiklander
980074ba9b2SJens Wiklander b = BFH(((char *) buf) - sizeof(struct bhead));
981074ba9b2SJens Wiklander #ifdef BufStats
982b7f0111dSVolodymyr Babchuk poolset->numrel++; /* Increment number of brel() calls */
983074ba9b2SJens Wiklander #endif
984074ba9b2SJens Wiklander assert(buf != NULL);
985074ba9b2SJens Wiklander
9864e570655SJerome Forissier #ifdef FreeWipe
9874e570655SJerome Forissier wipe = true;
9884e570655SJerome Forissier #endif
989074ba9b2SJens Wiklander #ifdef BECtl
990074ba9b2SJens Wiklander if (b->bh.bsize == 0) { /* Directly-acquired buffer? */
991074ba9b2SJens Wiklander struct bdhead *bdh;
992074ba9b2SJens Wiklander
993074ba9b2SJens Wiklander bdh = BDH(((char *) buf) - sizeof(struct bdhead));
994074ba9b2SJens Wiklander assert(b->bh.prevfree == 0);
995074ba9b2SJens Wiklander #ifdef BufStats
996b7f0111dSVolodymyr Babchuk poolset->totalloc -= bdh->tsize;
997b7f0111dSVolodymyr Babchuk assert(poolset->totalloc >= 0);
998b7f0111dSVolodymyr Babchuk poolset->numdrel++; /* Number of direct releases */
999074ba9b2SJens Wiklander #endif /* BufStats */
10004e570655SJerome Forissier if (wipe) {
1001e103c301SJens Wiklander V memset_unchecked((char *) buf, 0x55,
10024e570655SJerome Forissier (MemSize) (bdh->tsize -
10034e570655SJerome Forissier sizeof(struct bdhead)));
10044e570655SJerome Forissier }
1005b7f0111dSVolodymyr Babchuk assert(poolset->relfcn != NULL);
1006cc5981b2SJens Wiklander poolset->relfcn((char *)buf - sizeof(struct bdhead) - bdh->offs); /* Release it directly. */
1007074ba9b2SJens Wiklander return;
1008074ba9b2SJens Wiklander }
1009074ba9b2SJens Wiklander #endif /* BECtl */
1010074ba9b2SJens Wiklander
1011074ba9b2SJens Wiklander /* Buffer size must be negative, indicating that the buffer is
1012074ba9b2SJens Wiklander allocated. */
1013074ba9b2SJens Wiklander
1014074ba9b2SJens Wiklander if (b->bh.bsize >= 0) {
1015074ba9b2SJens Wiklander bn = NULL;
1016074ba9b2SJens Wiklander }
1017074ba9b2SJens Wiklander assert(b->bh.bsize < 0);
1018074ba9b2SJens Wiklander
1019074ba9b2SJens Wiklander /* Back pointer in next buffer must be zero, indicating the
1020074ba9b2SJens Wiklander same thing: */
1021074ba9b2SJens Wiklander
1022074ba9b2SJens Wiklander assert(BH((char *) b - b->bh.bsize)->prevfree == 0);
1023074ba9b2SJens Wiklander
1024074ba9b2SJens Wiklander #ifdef BufStats
1025b7f0111dSVolodymyr Babchuk poolset->totalloc += b->bh.bsize;
1026b7f0111dSVolodymyr Babchuk assert(poolset->totalloc >= 0);
1027074ba9b2SJens Wiklander #endif
1028074ba9b2SJens Wiklander
1029074ba9b2SJens Wiklander /* If the back link is nonzero, the previous buffer is free. */
1030074ba9b2SJens Wiklander
1031074ba9b2SJens Wiklander if (b->bh.prevfree != 0) {
1032074ba9b2SJens Wiklander
1033074ba9b2SJens Wiklander /* The previous buffer is free. Consolidate this buffer with it
1034074ba9b2SJens Wiklander by adding the length of this buffer to the previous free
1035074ba9b2SJens Wiklander buffer. Note that we subtract the size in the buffer being
1036074ba9b2SJens Wiklander released, since it's negative to indicate that the buffer is
1037074ba9b2SJens Wiklander allocated. */
1038074ba9b2SJens Wiklander
1039074ba9b2SJens Wiklander register bufsize size = b->bh.bsize;
1040074ba9b2SJens Wiklander
10410d4767a9SZengxx /* Only wipe the current buffer, including bfhead. */
10420d4767a9SZengxx wipe_start = (char *)b;
10430d4767a9SZengxx wipe_size = -size;
10440d4767a9SZengxx
1045074ba9b2SJens Wiklander /* Make the previous buffer the one we're working on. */
1046074ba9b2SJens Wiklander assert(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree);
1047074ba9b2SJens Wiklander b = BFH(((char *) b) - b->bh.prevfree);
1048*f288234fSJens Wiklander rem_sz = b->bh.bsize;
1049074ba9b2SJens Wiklander b->bh.bsize -= size;
1050*f288234fSJens Wiklander add_sz = b->bh.bsize;
1051*f288234fSJens Wiklander update_free2_sum(poolset, rem_sz, 0, add_sz);
1052074ba9b2SJens Wiklander } else {
1053074ba9b2SJens Wiklander
1054074ba9b2SJens Wiklander /* The previous buffer isn't allocated. Insert this buffer
1055074ba9b2SJens Wiklander on the free list as an isolated free block. */
1056074ba9b2SJens Wiklander
1057b7f0111dSVolodymyr Babchuk assert(poolset->freelist.ql.blink->ql.flink == &poolset->freelist);
1058b7f0111dSVolodymyr Babchuk assert(poolset->freelist.ql.flink->ql.blink == &poolset->freelist);
1059b7f0111dSVolodymyr Babchuk b->ql.flink = &poolset->freelist;
1060b7f0111dSVolodymyr Babchuk b->ql.blink = poolset->freelist.ql.blink;
1061b7f0111dSVolodymyr Babchuk poolset->freelist.ql.blink = b;
1062074ba9b2SJens Wiklander b->ql.blink->ql.flink = b;
1063074ba9b2SJens Wiklander b->bh.bsize = -b->bh.bsize;
1064*f288234fSJens Wiklander update_free2_sum(poolset, 0, 0, b->bh.bsize);
10650d4767a9SZengxx
10660d4767a9SZengxx wipe_start = (char *)b + sizeof(struct bfhead);
10670d4767a9SZengxx wipe_size = b->bh.bsize - sizeof(struct bfhead);
1068074ba9b2SJens Wiklander }
1069074ba9b2SJens Wiklander
1070074ba9b2SJens Wiklander /* Now we look at the next buffer in memory, located by advancing from
1071074ba9b2SJens Wiklander the start of this buffer by its size, to see if that buffer is
1072074ba9b2SJens Wiklander free. If it is, we combine this buffer with the next one in
1073074ba9b2SJens Wiklander memory, dechaining the second buffer from the free list. */
1074074ba9b2SJens Wiklander
1075074ba9b2SJens Wiklander bn = BFH(((char *) b) + b->bh.bsize);
1076074ba9b2SJens Wiklander if (bn->bh.bsize > 0) {
1077074ba9b2SJens Wiklander
1078074ba9b2SJens Wiklander /* The buffer is free. Remove it from the free list and add
1079074ba9b2SJens Wiklander its size to that of our buffer. */
1080074ba9b2SJens Wiklander
1081074ba9b2SJens Wiklander assert(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize);
1082074ba9b2SJens Wiklander assert(bn->ql.blink->ql.flink == bn);
1083074ba9b2SJens Wiklander assert(bn->ql.flink->ql.blink == bn);
1084074ba9b2SJens Wiklander bn->ql.blink->ql.flink = bn->ql.flink;
1085074ba9b2SJens Wiklander bn->ql.flink->ql.blink = bn->ql.blink;
1086*f288234fSJens Wiklander rem_sz = b->bh.bsize;
1087*f288234fSJens Wiklander rem_sz2 = bn->bh.bsize;
1088074ba9b2SJens Wiklander b->bh.bsize += bn->bh.bsize;
1089*f288234fSJens Wiklander add_sz = b->bh.bsize;
1090*f288234fSJens Wiklander update_free2_sum(poolset, rem_sz, rem_sz2, add_sz);
1091074ba9b2SJens Wiklander
1092074ba9b2SJens Wiklander /* Finally, advance to the buffer that follows the newly
1093074ba9b2SJens Wiklander consolidated free block. We must set its backpointer to the
1094074ba9b2SJens Wiklander head of the consolidated free block. We know the next block
1095074ba9b2SJens Wiklander must be an allocated block because the process of recombination
1096074ba9b2SJens Wiklander guarantees that two free blocks will never be contiguous in
1097074ba9b2SJens Wiklander memory. */
1098074ba9b2SJens Wiklander
1099074ba9b2SJens Wiklander bn = BFH(((char *) b) + b->bh.bsize);
11000d4767a9SZengxx /* Only bfhead of next buffer needs to be wiped */
11010d4767a9SZengxx wipe_size += sizeof(struct bfhead);
1102074ba9b2SJens Wiklander }
11034e570655SJerome Forissier if (wipe) {
11040d4767a9SZengxx V memset_unchecked(wipe_start, 0x55, wipe_size);
11054e570655SJerome Forissier }
1106074ba9b2SJens Wiklander assert(bn->bh.bsize < 0);
1107074ba9b2SJens Wiklander
1108074ba9b2SJens Wiklander /* The next buffer is allocated. Set the backpointer in it to point
1109074ba9b2SJens Wiklander to this buffer; the previous free buffer in memory. */
1110074ba9b2SJens Wiklander
1111074ba9b2SJens Wiklander bn->bh.prevfree = b->bh.bsize;
1112074ba9b2SJens Wiklander
1113074ba9b2SJens Wiklander #ifdef BECtl
1114074ba9b2SJens Wiklander
1115074ba9b2SJens Wiklander /* If a block-release function is defined, and this free buffer
1116074ba9b2SJens Wiklander constitutes the entire block, release it. Note that pool_len
1117074ba9b2SJens Wiklander is defined in such a way that the test will fail unless all
1118074ba9b2SJens Wiklander pool blocks are the same size. */
1119074ba9b2SJens Wiklander
1120b7f0111dSVolodymyr Babchuk if (poolset->relfcn != NULL &&
1121074ba9b2SJens Wiklander ((bufsize) b->bh.bsize) == (pool_len - sizeof(struct bhead))) {
1122074ba9b2SJens Wiklander
1123074ba9b2SJens Wiklander assert(b->bh.prevfree == 0);
1124074ba9b2SJens Wiklander assert(BH((char *) b + b->bh.bsize)->bsize == ESent);
1125074ba9b2SJens Wiklander assert(BH((char *) b + b->bh.bsize)->prevfree == b->bh.bsize);
1126074ba9b2SJens Wiklander /* Unlink the buffer from the free list */
1127074ba9b2SJens Wiklander b->ql.blink->ql.flink = b->ql.flink;
1128074ba9b2SJens Wiklander b->ql.flink->ql.blink = b->ql.blink;
1129074ba9b2SJens Wiklander
1130b7f0111dSVolodymyr Babchuk poolset->relfcn(b);
1131074ba9b2SJens Wiklander #ifdef BufStats
1132b7f0111dSVolodymyr Babchuk poolset->numprel++; /* Nr of expansion block releases */
1133b7f0111dSVolodymyr Babchuk poolset->numpblk--; /* Total number of blocks */
1134074ba9b2SJens Wiklander assert(numpblk == numpget - numprel);
1135074ba9b2SJens Wiklander #endif /* BufStats */
1136074ba9b2SJens Wiklander }
1137074ba9b2SJens Wiklander #endif /* BECtl */
1138074ba9b2SJens Wiklander }
1139074ba9b2SJens Wiklander
1140074ba9b2SJens Wiklander #ifdef BECtl
1141074ba9b2SJens Wiklander
1142074ba9b2SJens Wiklander /* BECTL -- Establish automatic pool expansion control */
1143074ba9b2SJens Wiklander
1144b7f0111dSVolodymyr Babchuk void bectl(compact, acquire, release, pool_incr, poolset)
1145074ba9b2SJens Wiklander int (*compact) _((bufsize sizereq, int sequence));
1146074ba9b2SJens Wiklander void *(*acquire) _((bufsize size));
1147074ba9b2SJens Wiklander void (*release) _((void *buf));
1148074ba9b2SJens Wiklander bufsize pool_incr;
1149b7f0111dSVolodymyr Babchuk struct bpoolset *poolset;
1150074ba9b2SJens Wiklander {
1151b7f0111dSVolodymyr Babchuk poolset->compfcn = compact;
1152b7f0111dSVolodymyr Babchuk poolset->acqfcn = acquire;
1153b7f0111dSVolodymyr Babchuk poolset->relfcn = release;
1154b7f0111dSVolodymyr Babchuk poolset->exp_incr = pool_incr;
1155074ba9b2SJens Wiklander }
1156074ba9b2SJens Wiklander #endif
1157074ba9b2SJens Wiklander
1158074ba9b2SJens Wiklander /* BPOOL -- Add a region of memory to the buffer pool. */
1159074ba9b2SJens Wiklander
bpool(buf,len,poolset)1160b7f0111dSVolodymyr Babchuk void bpool(buf, len, poolset)
1161074ba9b2SJens Wiklander void *buf;
1162074ba9b2SJens Wiklander bufsize len;
1163b7f0111dSVolodymyr Babchuk struct bpoolset *poolset;
1164074ba9b2SJens Wiklander {
1165074ba9b2SJens Wiklander struct bfhead *b = BFH(buf);
1166074ba9b2SJens Wiklander struct bhead *bn;
1167074ba9b2SJens Wiklander
1168074ba9b2SJens Wiklander #ifdef SizeQuant
1169074ba9b2SJens Wiklander len &= ~(SizeQuant - 1);
1170074ba9b2SJens Wiklander #endif
1171074ba9b2SJens Wiklander #ifdef BECtl
1172b7f0111dSVolodymyr Babchuk if (poolset->pool_len == 0) {
1173074ba9b2SJens Wiklander pool_len = len;
1174b7f0111dSVolodymyr Babchuk } else if (len != poolset->pool_len) {
1175b7f0111dSVolodymyr Babchuk poolset->pool_len = -1;
1176074ba9b2SJens Wiklander }
1177074ba9b2SJens Wiklander #ifdef BufStats
1178b7f0111dSVolodymyr Babchuk poolset->numpget++; /* Number of block acquisitions */
1179b7f0111dSVolodymyr Babchuk poolset->numpblk++; /* Number of blocks total */
1180b7f0111dSVolodymyr Babchuk assert(poolset->numpblk == poolset->numpget - poolset->numprel);
1181074ba9b2SJens Wiklander #endif /* BufStats */
1182074ba9b2SJens Wiklander #endif /* BECtl */
1183074ba9b2SJens Wiklander
1184074ba9b2SJens Wiklander /* Since the block is initially occupied by a single free buffer,
1185074ba9b2SJens Wiklander it had better not be (much) larger than the largest buffer
1186074ba9b2SJens Wiklander whose size we can store in bhead.bsize. */
1187074ba9b2SJens Wiklander
1188074ba9b2SJens Wiklander assert(len - sizeof(struct bhead) <= -((bufsize) ESent + 1));
1189074ba9b2SJens Wiklander
1190074ba9b2SJens Wiklander /* Clear the backpointer at the start of the block to indicate that
1191074ba9b2SJens Wiklander there is no free block prior to this one. That blocks
1192074ba9b2SJens Wiklander recombination when the first block in memory is released. */
1193074ba9b2SJens Wiklander
1194074ba9b2SJens Wiklander b->bh.prevfree = 0;
1195074ba9b2SJens Wiklander
1196074ba9b2SJens Wiklander /* Chain the new block to the free list. */
1197074ba9b2SJens Wiklander
1198b7f0111dSVolodymyr Babchuk assert(poolset->freelist.ql.blink->ql.flink == &poolset->freelist);
1199b7f0111dSVolodymyr Babchuk assert(poolset->freelist.ql.flink->ql.blink == &poolset->freelist);
1200b7f0111dSVolodymyr Babchuk b->ql.flink = &poolset->freelist;
1201b7f0111dSVolodymyr Babchuk b->ql.blink = poolset->freelist.ql.blink;
1202b7f0111dSVolodymyr Babchuk poolset->freelist.ql.blink = b;
1203074ba9b2SJens Wiklander b->ql.blink->ql.flink = b;
1204074ba9b2SJens Wiklander
1205074ba9b2SJens Wiklander /* Create a dummy allocated buffer at the end of the pool. This dummy
1206074ba9b2SJens Wiklander buffer is seen when a buffer at the end of the pool is released and
1207074ba9b2SJens Wiklander blocks recombination of the last buffer with the dummy buffer at
1208074ba9b2SJens Wiklander the end. The length in the dummy buffer is set to the largest
1209074ba9b2SJens Wiklander negative number to denote the end of the pool for diagnostic
1210074ba9b2SJens Wiklander routines (this specific value is not counted on by the actual
1211074ba9b2SJens Wiklander allocation and release functions). */
1212074ba9b2SJens Wiklander
1213074ba9b2SJens Wiklander len -= sizeof(struct bhead);
1214074ba9b2SJens Wiklander b->bh.bsize = (bufsize) len;
1215*f288234fSJens Wiklander update_free2_sum(poolset, 0, 0, b->bh.bsize);
1216074ba9b2SJens Wiklander #ifdef FreeWipe
1217e103c301SJens Wiklander V memset_unchecked(((char *) b) + sizeof(struct bfhead), 0x55,
1218074ba9b2SJens Wiklander (MemSize) (len - sizeof(struct bfhead)));
1219074ba9b2SJens Wiklander #endif
1220074ba9b2SJens Wiklander bn = BH(((char *) b) + len);
1221074ba9b2SJens Wiklander bn->prevfree = (bufsize) len;
1222074ba9b2SJens Wiklander /* Definition of ESent assumes two's complement! */
1223074ba9b2SJens Wiklander assert((~0) == -1);
1224074ba9b2SJens Wiklander bn->bsize = ESent;
1225074ba9b2SJens Wiklander }
1226074ba9b2SJens Wiklander
1227074ba9b2SJens Wiklander #ifdef BufStats
1228074ba9b2SJens Wiklander
1229074ba9b2SJens Wiklander /* BSTATS -- Return buffer allocation free space statistics. */
1230074ba9b2SJens Wiklander
bstats(curalloc,totfree,maxfree,nget,nrel,poolset)1231b7f0111dSVolodymyr Babchuk void bstats(curalloc, totfree, maxfree, nget, nrel, poolset)
1232074ba9b2SJens Wiklander bufsize *curalloc, *totfree, *maxfree;
1233074ba9b2SJens Wiklander long *nget, *nrel;
1234b7f0111dSVolodymyr Babchuk struct bpoolset *poolset;
1235074ba9b2SJens Wiklander {
1236b7f0111dSVolodymyr Babchuk struct bfhead *b = poolset->freelist.ql.flink;
1237074ba9b2SJens Wiklander
1238b7f0111dSVolodymyr Babchuk *nget = poolset->numget;
1239b7f0111dSVolodymyr Babchuk *nrel = poolset->numrel;
1240b7f0111dSVolodymyr Babchuk *curalloc = poolset->totalloc;
1241074ba9b2SJens Wiklander *totfree = 0;
1242074ba9b2SJens Wiklander *maxfree = -1;
1243b7f0111dSVolodymyr Babchuk while (b != &poolset->freelist) {
1244074ba9b2SJens Wiklander assert(b->bh.bsize > 0);
1245074ba9b2SJens Wiklander *totfree += b->bh.bsize;
1246074ba9b2SJens Wiklander if (b->bh.bsize > *maxfree) {
1247074ba9b2SJens Wiklander *maxfree = b->bh.bsize;
1248074ba9b2SJens Wiklander }
1249074ba9b2SJens Wiklander b = b->ql.flink; /* Link to next buffer */
1250074ba9b2SJens Wiklander }
1251074ba9b2SJens Wiklander }
1252074ba9b2SJens Wiklander
1253074ba9b2SJens Wiklander #ifdef BECtl
1254074ba9b2SJens Wiklander
1255074ba9b2SJens Wiklander /* BSTATSE -- Return extended statistics */
1256074ba9b2SJens Wiklander
bstatse(pool_incr,npool,npget,nprel,ndget,ndrel,poolset)1257b7f0111dSVolodymyr Babchuk void bstatse(pool_incr, npool, npget, nprel, ndget, ndrel, poolset)
1258074ba9b2SJens Wiklander bufsize *pool_incr;
1259074ba9b2SJens Wiklander long *npool, *npget, *nprel, *ndget, *ndrel;
1260b7f0111dSVolodymyr Babchuk struct bpoolset *poolset;
1261074ba9b2SJens Wiklander {
1262b7f0111dSVolodymyr Babchuk *pool_incr = (poolset->pool_len < 0) ?
1263b7f0111dSVolodymyr Babchuk -poolset->exp_incr : poolset->exp_incr;
1264b7f0111dSVolodymyr Babchuk *npool = poolset->numpblk;
1265b7f0111dSVolodymyr Babchuk *npget = poolset->numpget;
1266b7f0111dSVolodymyr Babchuk *nprel = poolset->numprel;
1267b7f0111dSVolodymyr Babchuk *ndget = poolset->numdget;
1268b7f0111dSVolodymyr Babchuk *ndrel = poolset->numdrel;
1269074ba9b2SJens Wiklander }
1270074ba9b2SJens Wiklander #endif /* BECtl */
1271074ba9b2SJens Wiklander #endif /* BufStats */
1272074ba9b2SJens Wiklander
1273074ba9b2SJens Wiklander #ifdef DumpData
1274074ba9b2SJens Wiklander
1275074ba9b2SJens Wiklander /* BUFDUMP -- Dump the data in a buffer. This is called with the user
1276074ba9b2SJens Wiklander data pointer, and backs up to the buffer header. It will
1277074ba9b2SJens Wiklander dump either a free block or an allocated one. */
1278074ba9b2SJens Wiklander
bufdump(buf)1279074ba9b2SJens Wiklander void bufdump(buf)
1280074ba9b2SJens Wiklander void *buf;
1281074ba9b2SJens Wiklander {
1282074ba9b2SJens Wiklander struct bfhead *b;
1283074ba9b2SJens Wiklander unsigned char *bdump;
1284074ba9b2SJens Wiklander bufsize bdlen;
1285074ba9b2SJens Wiklander
1286074ba9b2SJens Wiklander b = BFH(((char *) buf) - sizeof(struct bhead));
1287074ba9b2SJens Wiklander assert(b->bh.bsize != 0);
1288074ba9b2SJens Wiklander if (b->bh.bsize < 0) {
1289074ba9b2SJens Wiklander bdump = (unsigned char *) buf;
1290074ba9b2SJens Wiklander bdlen = (-b->bh.bsize) - sizeof(struct bhead);
1291074ba9b2SJens Wiklander } else {
1292074ba9b2SJens Wiklander bdump = (unsigned char *) (((char *) b) + sizeof(struct bfhead));
1293074ba9b2SJens Wiklander bdlen = b->bh.bsize - sizeof(struct bfhead);
1294074ba9b2SJens Wiklander }
1295074ba9b2SJens Wiklander
1296074ba9b2SJens Wiklander while (bdlen > 0) {
1297074ba9b2SJens Wiklander int i, dupes = 0;
1298074ba9b2SJens Wiklander bufsize l = bdlen;
1299074ba9b2SJens Wiklander char bhex[50], bascii[20];
1300074ba9b2SJens Wiklander
1301074ba9b2SJens Wiklander if (l > 16) {
1302074ba9b2SJens Wiklander l = 16;
1303074ba9b2SJens Wiklander }
1304074ba9b2SJens Wiklander
1305074ba9b2SJens Wiklander for (i = 0; i < l; i++) {
1306074ba9b2SJens Wiklander V snprintf(bhex + i * 3, sizeof(bhex) - i * 3, "%02X ",
1307074ba9b2SJens Wiklander bdump[i]);
1308074ba9b2SJens Wiklander bascii[i] = isprint(bdump[i]) ? bdump[i] : ' ';
1309074ba9b2SJens Wiklander }
1310074ba9b2SJens Wiklander bascii[i] = 0;
1311074ba9b2SJens Wiklander V printf("%-48s %s\n", bhex, bascii);
1312074ba9b2SJens Wiklander bdump += l;
1313074ba9b2SJens Wiklander bdlen -= l;
1314074ba9b2SJens Wiklander while ((bdlen > 16) && (memcmp((char *) (bdump - 16),
1315074ba9b2SJens Wiklander (char *) bdump, 16) == 0)) {
1316074ba9b2SJens Wiklander dupes++;
1317074ba9b2SJens Wiklander bdump += 16;
1318074ba9b2SJens Wiklander bdlen -= 16;
1319074ba9b2SJens Wiklander }
1320074ba9b2SJens Wiklander if (dupes > 1) {
1321074ba9b2SJens Wiklander V printf(
1322074ba9b2SJens Wiklander " (%d lines [%d bytes] identical to above line skipped)\n",
1323074ba9b2SJens Wiklander dupes, dupes * 16);
1324074ba9b2SJens Wiklander } else if (dupes == 1) {
1325074ba9b2SJens Wiklander bdump -= 16;
1326074ba9b2SJens Wiklander bdlen += 16;
1327074ba9b2SJens Wiklander }
1328074ba9b2SJens Wiklander }
1329074ba9b2SJens Wiklander }
1330074ba9b2SJens Wiklander #endif
1331074ba9b2SJens Wiklander
1332074ba9b2SJens Wiklander #ifdef BufDump
1333074ba9b2SJens Wiklander
1334074ba9b2SJens Wiklander /* BPOOLD -- Dump a buffer pool. The buffer headers are always listed.
1335074ba9b2SJens Wiklander If DUMPALLOC is nonzero, the contents of allocated buffers
1336074ba9b2SJens Wiklander are dumped. If DUMPFREE is nonzero, free blocks are
1337074ba9b2SJens Wiklander dumped as well. If FreeWipe checking is enabled, free
1338074ba9b2SJens Wiklander blocks which have been clobbered will always be dumped. */
1339074ba9b2SJens Wiklander
bpoold(buf,dumpalloc,dumpfree)1340074ba9b2SJens Wiklander void bpoold(buf, dumpalloc, dumpfree)
1341074ba9b2SJens Wiklander void *buf;
1342074ba9b2SJens Wiklander int dumpalloc, dumpfree;
1343074ba9b2SJens Wiklander {
1344074ba9b2SJens Wiklander struct bfhead *b = BFH(buf);
1345074ba9b2SJens Wiklander
1346074ba9b2SJens Wiklander while (b->bh.bsize != ESent) {
1347074ba9b2SJens Wiklander bufsize bs = b->bh.bsize;
1348074ba9b2SJens Wiklander
1349074ba9b2SJens Wiklander if (bs < 0) {
1350074ba9b2SJens Wiklander bs = -bs;
1351074ba9b2SJens Wiklander V printf("Allocated buffer: size %6ld bytes.\n", (long) bs);
1352074ba9b2SJens Wiklander if (dumpalloc) {
1353074ba9b2SJens Wiklander bufdump((void *) (((char *) b) + sizeof(struct bhead)));
1354074ba9b2SJens Wiklander }
1355074ba9b2SJens Wiklander } else {
1356074ba9b2SJens Wiklander char *lerr = "";
1357074ba9b2SJens Wiklander
1358074ba9b2SJens Wiklander assert(bs > 0);
1359074ba9b2SJens Wiklander if ((b->ql.blink->ql.flink != b) ||
1360074ba9b2SJens Wiklander (b->ql.flink->ql.blink != b)) {
1361074ba9b2SJens Wiklander lerr = " (Bad free list links)";
1362074ba9b2SJens Wiklander }
1363074ba9b2SJens Wiklander V printf("Free block: size %6ld bytes.%s\n",
1364074ba9b2SJens Wiklander (long) bs, lerr);
1365074ba9b2SJens Wiklander #ifdef FreeWipe
1366074ba9b2SJens Wiklander lerr = ((char *) b) + sizeof(struct bfhead);
1367074ba9b2SJens Wiklander if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) ||
1368074ba9b2SJens Wiklander (memcmp(lerr, lerr + 1,
1369074ba9b2SJens Wiklander (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) {
1370074ba9b2SJens Wiklander V printf(
1371074ba9b2SJens Wiklander "(Contents of above free block have been overstored.)\n");
1372074ba9b2SJens Wiklander bufdump((void *) (((char *) b) + sizeof(struct bhead)));
1373074ba9b2SJens Wiklander } else
1374074ba9b2SJens Wiklander #endif
1375074ba9b2SJens Wiklander if (dumpfree) {
1376074ba9b2SJens Wiklander bufdump((void *) (((char *) b) + sizeof(struct bhead)));
1377074ba9b2SJens Wiklander }
1378074ba9b2SJens Wiklander }
1379074ba9b2SJens Wiklander b = BFH(((char *) b) + bs);
1380074ba9b2SJens Wiklander }
1381074ba9b2SJens Wiklander }
1382074ba9b2SJens Wiklander #endif /* BufDump */
1383074ba9b2SJens Wiklander
1384074ba9b2SJens Wiklander #ifdef BufValid
1385074ba9b2SJens Wiklander
1386074ba9b2SJens Wiklander /* BPOOLV -- Validate a buffer pool. If NDEBUG isn't defined,
1387074ba9b2SJens Wiklander any error generates an assertion failure. */
1388074ba9b2SJens Wiklander
bpoolv(buf)1389074ba9b2SJens Wiklander int bpoolv(buf)
1390074ba9b2SJens Wiklander void *buf;
1391074ba9b2SJens Wiklander {
1392074ba9b2SJens Wiklander struct bfhead *b = BFH(buf);
1393074ba9b2SJens Wiklander
1394074ba9b2SJens Wiklander while (b->bh.bsize != ESent) {
1395074ba9b2SJens Wiklander bufsize bs = b->bh.bsize;
1396074ba9b2SJens Wiklander
1397074ba9b2SJens Wiklander if (bs < 0) {
1398074ba9b2SJens Wiklander bs = -bs;
1399074ba9b2SJens Wiklander } else {
1400074ba9b2SJens Wiklander const char *lerr = "";
1401074ba9b2SJens Wiklander
1402074ba9b2SJens Wiklander assert(bs > 0);
1403074ba9b2SJens Wiklander if (bs <= 0) {
1404074ba9b2SJens Wiklander return 0;
1405074ba9b2SJens Wiklander }
1406074ba9b2SJens Wiklander if ((b->ql.blink->ql.flink != b) ||
1407074ba9b2SJens Wiklander (b->ql.flink->ql.blink != b)) {
1408074ba9b2SJens Wiklander V printf("Free block: size %6ld bytes. (Bad free list links)\n",
1409074ba9b2SJens Wiklander (long) bs);
1410074ba9b2SJens Wiklander assert(0);
1411074ba9b2SJens Wiklander return 0;
1412074ba9b2SJens Wiklander }
1413074ba9b2SJens Wiklander #ifdef FreeWipe
1414074ba9b2SJens Wiklander lerr = ((char *) b) + sizeof(struct bfhead);
1415074ba9b2SJens Wiklander if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) ||
1416074ba9b2SJens Wiklander (memcmp(lerr, lerr + 1,
1417074ba9b2SJens Wiklander (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) {
1418074ba9b2SJens Wiklander V printf(
1419074ba9b2SJens Wiklander "(Contents of above free block have been overstored.)\n");
1420074ba9b2SJens Wiklander bufdump((void *) (((char *) b) + sizeof(struct bhead)));
1421074ba9b2SJens Wiklander assert(0);
1422074ba9b2SJens Wiklander return 0;
1423074ba9b2SJens Wiklander }
1424074ba9b2SJens Wiklander #endif
1425074ba9b2SJens Wiklander }
1426074ba9b2SJens Wiklander b = BFH(((char *) b) + bs);
1427074ba9b2SJens Wiklander }
1428074ba9b2SJens Wiklander return 1;
1429074ba9b2SJens Wiklander }
1430074ba9b2SJens Wiklander #endif /* BufValid */
1431074ba9b2SJens Wiklander
1432074ba9b2SJens Wiklander /***********************\
1433074ba9b2SJens Wiklander * *
1434074ba9b2SJens Wiklander * Built-in test program *
1435074ba9b2SJens Wiklander * *
1436074ba9b2SJens Wiklander \***********************/
1437074ba9b2SJens Wiklander
143827e8d08dSJens Wiklander #if !defined(__KERNEL__) && !defined(__LDELF__) && defined(CFG_TA_BGET_TEST)
1439074ba9b2SJens Wiklander
144027e8d08dSJens Wiklander #define TestProg 20000
1441074ba9b2SJens Wiklander
1442074ba9b2SJens Wiklander #ifdef BECtl
1443074ba9b2SJens Wiklander #define PoolSize 300000 /* Test buffer pool size */
1444074ba9b2SJens Wiklander #else
1445074ba9b2SJens Wiklander #define PoolSize 50000 /* Test buffer pool size */
1446074ba9b2SJens Wiklander #endif
1447074ba9b2SJens Wiklander #define ExpIncr 32768 /* Test expansion block size */
1448074ba9b2SJens Wiklander #define CompactTries 10 /* Maximum tries at compacting */
1449074ba9b2SJens Wiklander
1450074ba9b2SJens Wiklander #define dumpAlloc 0 /* Dump allocated buffers ? */
1451074ba9b2SJens Wiklander #define dumpFree 0 /* Dump free buffers ? */
1452074ba9b2SJens Wiklander
1453074ba9b2SJens Wiklander static char *bchain = NULL; /* Our private buffer chain */
1454074ba9b2SJens Wiklander static char *bp = NULL; /* Our initial buffer pool */
1455074ba9b2SJens Wiklander
145627e8d08dSJens Wiklander #ifdef UsingFloat
1457074ba9b2SJens Wiklander #include <math.h>
145827e8d08dSJens Wiklander #endif
1459074ba9b2SJens Wiklander
1460074ba9b2SJens Wiklander static unsigned long int next = 1;
1461074ba9b2SJens Wiklander
146227e8d08dSJens Wiklander static void *(*mymalloc)(size_t size);
146327e8d08dSJens Wiklander static void (*myfree)(void *ptr);
146427e8d08dSJens Wiklander
146527e8d08dSJens Wiklander static struct bpoolset mypoolset = {
146627e8d08dSJens Wiklander .freelist = {
146727e8d08dSJens Wiklander .bh = { 0, 0},
146827e8d08dSJens Wiklander .ql = { &mypoolset.freelist, &mypoolset.freelist},
146927e8d08dSJens Wiklander }
147027e8d08dSJens Wiklander };
147127e8d08dSJens Wiklander
1472074ba9b2SJens Wiklander /* Return next random integer */
1473074ba9b2SJens Wiklander
myrand(void)147427e8d08dSJens Wiklander static int myrand(void)
1475074ba9b2SJens Wiklander {
1476074ba9b2SJens Wiklander next = next * 1103515245L + 12345;
1477074ba9b2SJens Wiklander return (unsigned int) (next / 65536L) % 32768L;
1478074ba9b2SJens Wiklander }
1479074ba9b2SJens Wiklander
1480074ba9b2SJens Wiklander /* Set seed for random generator */
1481074ba9b2SJens Wiklander
mysrand(unsigned int seed)148227e8d08dSJens Wiklander static void mysrand(unsigned int seed)
1483074ba9b2SJens Wiklander {
1484074ba9b2SJens Wiklander next = seed;
1485074ba9b2SJens Wiklander }
1486074ba9b2SJens Wiklander
1487074ba9b2SJens Wiklander /* STATS -- Edit statistics returned by bstats() or bstatse(). */
1488074ba9b2SJens Wiklander
stats(const char * when __maybe_unused,struct bpoolset * poolset __maybe_unused)148927e8d08dSJens Wiklander static void stats(const char *when __maybe_unused,
149027e8d08dSJens Wiklander struct bpoolset *poolset __maybe_unused)
1491074ba9b2SJens Wiklander {
149227e8d08dSJens Wiklander #ifdef BufStats
1493074ba9b2SJens Wiklander bufsize cural, totfree, maxfree;
1494074ba9b2SJens Wiklander long nget, nfree;
149527e8d08dSJens Wiklander #endif
1496074ba9b2SJens Wiklander #ifdef BECtl
1497074ba9b2SJens Wiklander bufsize pincr;
1498074ba9b2SJens Wiklander long totblocks, npget, nprel, ndget, ndrel;
1499074ba9b2SJens Wiklander #endif
1500074ba9b2SJens Wiklander
150127e8d08dSJens Wiklander #ifdef BufStats
150227e8d08dSJens Wiklander bstats(&cural, &totfree, &maxfree, &nget, &nfree, poolset);
1503074ba9b2SJens Wiklander V printf(
1504074ba9b2SJens Wiklander "%s: %ld gets, %ld releases. %ld in use, %ld free, largest = %ld\n",
1505074ba9b2SJens Wiklander when, nget, nfree, (long) cural, (long) totfree, (long) maxfree);
150627e8d08dSJens Wiklander #endif
1507074ba9b2SJens Wiklander #ifdef BECtl
150827e8d08dSJens Wiklander bstatse(&pincr, &totblocks, &npget, &nprel, &ndget, &ndrel, poolset);
1509074ba9b2SJens Wiklander V printf(
1510074ba9b2SJens Wiklander " Blocks: size = %ld, %ld (%ld bytes) in use, %ld gets, %ld frees\n",
1511074ba9b2SJens Wiklander (long)pincr, totblocks, pincr * totblocks, npget, nprel);
1512074ba9b2SJens Wiklander V printf(" %ld direct gets, %ld direct frees\n", ndget, ndrel);
1513074ba9b2SJens Wiklander #endif /* BECtl */
1514074ba9b2SJens Wiklander }
1515074ba9b2SJens Wiklander
1516074ba9b2SJens Wiklander #ifdef BECtl
1517074ba9b2SJens Wiklander static int protect = 0; /* Disable compaction during bgetr() */
1518074ba9b2SJens Wiklander
1519074ba9b2SJens Wiklander /* BCOMPACT -- Compaction call-back function. */
1520074ba9b2SJens Wiklander
bcompact(bsize,seq)1521074ba9b2SJens Wiklander static int bcompact(bsize, seq)
1522074ba9b2SJens Wiklander bufsize bsize;
1523074ba9b2SJens Wiklander int seq;
1524074ba9b2SJens Wiklander {
1525074ba9b2SJens Wiklander #ifdef CompactTries
1526074ba9b2SJens Wiklander char *bc = bchain;
1527cc5981b2SJens Wiklander int i = myrand() & 0x3;
1528074ba9b2SJens Wiklander
1529074ba9b2SJens Wiklander #ifdef COMPACTRACE
1530074ba9b2SJens Wiklander V printf("Compaction requested. %ld bytes needed, sequence %d.\n",
1531074ba9b2SJens Wiklander (long) bsize, seq);
1532074ba9b2SJens Wiklander #endif
1533074ba9b2SJens Wiklander
1534074ba9b2SJens Wiklander if (protect || (seq > CompactTries)) {
1535074ba9b2SJens Wiklander #ifdef COMPACTRACE
1536074ba9b2SJens Wiklander V printf("Compaction gave up.\n");
1537074ba9b2SJens Wiklander #endif
1538074ba9b2SJens Wiklander return 0;
1539074ba9b2SJens Wiklander }
1540074ba9b2SJens Wiklander
1541074ba9b2SJens Wiklander /* Based on a random cast, release a random buffer in the list
1542074ba9b2SJens Wiklander of allocated buffers. */
1543074ba9b2SJens Wiklander
1544074ba9b2SJens Wiklander while (i > 0 && bc != NULL) {
1545074ba9b2SJens Wiklander bc = *((char **) bc);
1546074ba9b2SJens Wiklander i--;
1547074ba9b2SJens Wiklander }
1548074ba9b2SJens Wiklander if (bc != NULL) {
1549074ba9b2SJens Wiklander char *fb;
1550074ba9b2SJens Wiklander
1551074ba9b2SJens Wiklander fb = *((char **) bc);
1552074ba9b2SJens Wiklander if (fb != NULL) {
1553074ba9b2SJens Wiklander *((char **) bc) = *((char **) fb);
1554074ba9b2SJens Wiklander brel((void *) fb);
1555074ba9b2SJens Wiklander return 1;
1556074ba9b2SJens Wiklander }
1557074ba9b2SJens Wiklander }
1558074ba9b2SJens Wiklander
1559074ba9b2SJens Wiklander #ifdef COMPACTRACE
1560074ba9b2SJens Wiklander V printf("Compaction bailed out.\n");
1561074ba9b2SJens Wiklander #endif
1562074ba9b2SJens Wiklander #endif /* CompactTries */
1563074ba9b2SJens Wiklander return 0;
1564074ba9b2SJens Wiklander }
1565074ba9b2SJens Wiklander
1566074ba9b2SJens Wiklander /* BEXPAND -- Expand pool call-back function. */
1567074ba9b2SJens Wiklander
bexpand(size)1568074ba9b2SJens Wiklander static void *bexpand(size)
1569074ba9b2SJens Wiklander bufsize size;
1570074ba9b2SJens Wiklander {
1571074ba9b2SJens Wiklander void *np = NULL;
1572074ba9b2SJens Wiklander bufsize cural, totfree, maxfree;
1573074ba9b2SJens Wiklander long nget, nfree;
1574074ba9b2SJens Wiklander
1575074ba9b2SJens Wiklander /* Don't expand beyond the total allocated size given by PoolSize. */
1576074ba9b2SJens Wiklander
1577074ba9b2SJens Wiklander bstats(&cural, &totfree, &maxfree, &nget, &nfree);
1578074ba9b2SJens Wiklander
1579074ba9b2SJens Wiklander if (cural < PoolSize) {
158027e8d08dSJens Wiklander np = (void *) mymalloc((unsigned) size);
1581074ba9b2SJens Wiklander }
1582074ba9b2SJens Wiklander #ifdef EXPTRACE
1583074ba9b2SJens Wiklander V printf("Expand pool by %ld -- %s.\n", (long) size,
1584074ba9b2SJens Wiklander np == NULL ? "failed" : "succeeded");
1585074ba9b2SJens Wiklander #endif
1586074ba9b2SJens Wiklander return np;
1587074ba9b2SJens Wiklander }
1588074ba9b2SJens Wiklander
1589074ba9b2SJens Wiklander /* BSHRINK -- Shrink buffer pool call-back function. */
1590074ba9b2SJens Wiklander
bshrink(buf)1591074ba9b2SJens Wiklander static void bshrink(buf)
1592074ba9b2SJens Wiklander void *buf;
1593074ba9b2SJens Wiklander {
1594074ba9b2SJens Wiklander if (((char *) buf) == bp) {
1595074ba9b2SJens Wiklander #ifdef EXPTRACE
1596074ba9b2SJens Wiklander V printf("Initial pool released.\n");
1597074ba9b2SJens Wiklander #endif
1598074ba9b2SJens Wiklander bp = NULL;
1599074ba9b2SJens Wiklander }
1600074ba9b2SJens Wiklander #ifdef EXPTRACE
1601074ba9b2SJens Wiklander V printf("Shrink pool.\n");
1602074ba9b2SJens Wiklander #endif
160327e8d08dSJens Wiklander myfree((char *) buf);
1604074ba9b2SJens Wiklander }
1605074ba9b2SJens Wiklander
1606074ba9b2SJens Wiklander #endif /* BECtl */
1607074ba9b2SJens Wiklander
1608074ba9b2SJens Wiklander /* Restrict buffer requests to those large enough to contain our pointer and
1609074ba9b2SJens Wiklander small enough for the CPU architecture. */
1610074ba9b2SJens Wiklander
blimit(bufsize bs)161127e8d08dSJens Wiklander static bufsize blimit(bufsize bs)
1612074ba9b2SJens Wiklander {
1613074ba9b2SJens Wiklander if (bs < sizeof(char *)) {
1614074ba9b2SJens Wiklander bs = sizeof(char *);
1615074ba9b2SJens Wiklander }
1616074ba9b2SJens Wiklander
1617074ba9b2SJens Wiklander /* This is written out in this ugly fashion because the
1618074ba9b2SJens Wiklander cool expression in sizeof(int) that auto-configured
1619074ba9b2SJens Wiklander to any length int befuddled some compilers. */
1620074ba9b2SJens Wiklander
1621074ba9b2SJens Wiklander if (sizeof(int) == 2) {
1622074ba9b2SJens Wiklander if (bs > 32767) {
1623074ba9b2SJens Wiklander bs = 32767;
1624074ba9b2SJens Wiklander }
1625074ba9b2SJens Wiklander } else {
1626074ba9b2SJens Wiklander if (bs > 200000) {
1627074ba9b2SJens Wiklander bs = 200000;
1628074ba9b2SJens Wiklander }
1629074ba9b2SJens Wiklander }
1630074ba9b2SJens Wiklander return bs;
1631074ba9b2SJens Wiklander }
1632074ba9b2SJens Wiklander
bget_main_test(void * (* malloc_func)(size_t),void (* free_func)(void *))163327e8d08dSJens Wiklander int bget_main_test(void *(*malloc_func)(size_t), void (*free_func)(void *))
1634074ba9b2SJens Wiklander {
1635074ba9b2SJens Wiklander int i;
163627e8d08dSJens Wiklander #ifdef UsingFloat
1637074ba9b2SJens Wiklander double x;
163827e8d08dSJens Wiklander #endif
163927e8d08dSJens Wiklander
164027e8d08dSJens Wiklander mymalloc = malloc_func;
164127e8d08dSJens Wiklander myfree = free_func;
1642074ba9b2SJens Wiklander
1643074ba9b2SJens Wiklander /* Seed the random number generator. If Repeatable is defined, we
1644074ba9b2SJens Wiklander always use the same seed. Otherwise, we seed from the clock to
1645074ba9b2SJens Wiklander shake things up from run to run. */
1646074ba9b2SJens Wiklander
164727e8d08dSJens Wiklander mysrand(1234);
1648074ba9b2SJens Wiklander
1649074ba9b2SJens Wiklander /* Compute x such that pow(x, p) ranges between 1 and 4*ExpIncr as
1650074ba9b2SJens Wiklander p ranges from 0 to ExpIncr-1, with a concentration in the lower
1651074ba9b2SJens Wiklander numbers. */
1652074ba9b2SJens Wiklander
165327e8d08dSJens Wiklander #ifdef UsingFloat
1654074ba9b2SJens Wiklander x = 4.0 * ExpIncr;
1655074ba9b2SJens Wiklander x = log(x);
1656074ba9b2SJens Wiklander x = exp(log(4.0 * ExpIncr) / (ExpIncr - 1.0));
165727e8d08dSJens Wiklander #endif
1658074ba9b2SJens Wiklander
1659074ba9b2SJens Wiklander #ifdef BECtl
166027e8d08dSJens Wiklander bectl(bcompact, bexpand, bshrink, (bufsize) ExpIncr, &mypoolset);
166127e8d08dSJens Wiklander bp = mymalloc(ExpIncr);
1662074ba9b2SJens Wiklander assert(bp != NULL);
1663074ba9b2SJens Wiklander bpool((void *) bp, (bufsize) ExpIncr);
1664074ba9b2SJens Wiklander #else
166527e8d08dSJens Wiklander bp = mymalloc(PoolSize);
1666074ba9b2SJens Wiklander assert(bp != NULL);
166727e8d08dSJens Wiklander bpool((void *) bp, (bufsize) PoolSize, &mypoolset);
1668074ba9b2SJens Wiklander #endif
1669074ba9b2SJens Wiklander
167027e8d08dSJens Wiklander stats("Create pool", &mypoolset);
167127e8d08dSJens Wiklander #ifdef BufValid
1672074ba9b2SJens Wiklander V bpoolv((void *) bp);
167327e8d08dSJens Wiklander #endif
167427e8d08dSJens Wiklander #ifdef BufDump
1675074ba9b2SJens Wiklander bpoold((void *) bp, dumpAlloc, dumpFree);
167627e8d08dSJens Wiklander #endif
1677074ba9b2SJens Wiklander
1678074ba9b2SJens Wiklander for (i = 0; i < TestProg; i++) {
1679074ba9b2SJens Wiklander char *cb;
168027e8d08dSJens Wiklander #ifdef UsingFloat
168127e8d08dSJens Wiklander bufsize bs = pow(x, (double) (myrand() & (ExpIncr - 1)));
168227e8d08dSJens Wiklander #else
1683cc5981b2SJens Wiklander bufsize bs = (myrand() & (ExpIncr * 4 - 1)) / (1 << (myrand() & 0x7));
168427e8d08dSJens Wiklander #endif
1685cc5981b2SJens Wiklander bufsize align = 0;
168617967299SJens Wiklander bufsize hdr_size = 0;
1687cc5981b2SJens Wiklander
1688cc5981b2SJens Wiklander switch (rand() & 0x3) {
1689cc5981b2SJens Wiklander case 1:
1690cc5981b2SJens Wiklander align = 32;
1691cc5981b2SJens Wiklander break;
1692cc5981b2SJens Wiklander case 2:
1693cc5981b2SJens Wiklander align = 64;
1694cc5981b2SJens Wiklander break;
1695cc5981b2SJens Wiklander case 3:
1696cc5981b2SJens Wiklander align = 128;
1697cc5981b2SJens Wiklander break;
1698cc5981b2SJens Wiklander default:
1699cc5981b2SJens Wiklander break;
1700cc5981b2SJens Wiklander }
1701074ba9b2SJens Wiklander
170217967299SJens Wiklander hdr_size = (rand() & 0x3) * BGET_HDR_QUANTUM;
170317967299SJens Wiklander
1704074ba9b2SJens Wiklander assert(bs <= (((bufsize) 4) * ExpIncr));
1705074ba9b2SJens Wiklander bs = blimit(bs);
170627e8d08dSJens Wiklander if (myrand() & 0x400) {
170717967299SJens Wiklander cb = (char *) bgetz(align, hdr_size, bs, &mypoolset);
1708074ba9b2SJens Wiklander } else {
170917967299SJens Wiklander cb = (char *) bget(align, hdr_size, bs, &mypoolset);
1710074ba9b2SJens Wiklander }
1711074ba9b2SJens Wiklander if (cb == NULL) {
1712074ba9b2SJens Wiklander #ifdef EasyOut
1713074ba9b2SJens Wiklander break;
1714074ba9b2SJens Wiklander #else
1715074ba9b2SJens Wiklander char *bc = bchain;
1716074ba9b2SJens Wiklander
1717074ba9b2SJens Wiklander if (bc != NULL) {
1718074ba9b2SJens Wiklander char *fb;
1719074ba9b2SJens Wiklander
1720074ba9b2SJens Wiklander fb = *((char **) bc);
1721074ba9b2SJens Wiklander if (fb != NULL) {
1722074ba9b2SJens Wiklander *((char **) bc) = *((char **) fb);
172327e8d08dSJens Wiklander brel((void *) fb, &mypoolset, true/*wipe*/);
1724074ba9b2SJens Wiklander }
1725074ba9b2SJens Wiklander }
1726cc5981b2SJens Wiklander continue;
1727074ba9b2SJens Wiklander #endif
1728074ba9b2SJens Wiklander }
172917967299SJens Wiklander assert(!align || !(((unsigned long)cb + hdr_size) & (align - 1)));
1730074ba9b2SJens Wiklander *((char **) cb) = (char *) bchain;
1731074ba9b2SJens Wiklander bchain = cb;
1732074ba9b2SJens Wiklander
1733074ba9b2SJens Wiklander /* Based on a random cast, release a random buffer in the list
1734074ba9b2SJens Wiklander of allocated buffers. */
1735074ba9b2SJens Wiklander
173627e8d08dSJens Wiklander if ((myrand() & 0x10) == 0) {
1737074ba9b2SJens Wiklander char *bc = bchain;
173827e8d08dSJens Wiklander int j = myrand() & 0x3;
1739074ba9b2SJens Wiklander
174027e8d08dSJens Wiklander while (j > 0 && bc != NULL) {
1741074ba9b2SJens Wiklander bc = *((char **) bc);
174227e8d08dSJens Wiklander j--;
1743074ba9b2SJens Wiklander }
1744074ba9b2SJens Wiklander if (bc != NULL) {
1745074ba9b2SJens Wiklander char *fb;
1746074ba9b2SJens Wiklander
1747074ba9b2SJens Wiklander fb = *((char **) bc);
1748074ba9b2SJens Wiklander if (fb != NULL) {
1749074ba9b2SJens Wiklander *((char **) bc) = *((char **) fb);
175027e8d08dSJens Wiklander brel((void *) fb, &mypoolset, true/*wipe*/);
1751074ba9b2SJens Wiklander }
1752074ba9b2SJens Wiklander }
1753074ba9b2SJens Wiklander }
1754074ba9b2SJens Wiklander
1755074ba9b2SJens Wiklander /* Based on a random cast, reallocate a random buffer in the list
1756074ba9b2SJens Wiklander to a random size */
1757074ba9b2SJens Wiklander
175827e8d08dSJens Wiklander if ((myrand() & 0x20) == 0) {
1759074ba9b2SJens Wiklander char *bc = bchain;
176027e8d08dSJens Wiklander int j = myrand() & 0x3;
1761074ba9b2SJens Wiklander
176227e8d08dSJens Wiklander while (j > 0 && bc != NULL) {
1763074ba9b2SJens Wiklander bc = *((char **) bc);
176427e8d08dSJens Wiklander j--;
1765074ba9b2SJens Wiklander }
1766074ba9b2SJens Wiklander if (bc != NULL) {
1767074ba9b2SJens Wiklander char *fb;
1768074ba9b2SJens Wiklander
1769074ba9b2SJens Wiklander fb = *((char **) bc);
1770074ba9b2SJens Wiklander if (fb != NULL) {
1771074ba9b2SJens Wiklander char *newb;
1772074ba9b2SJens Wiklander
177327e8d08dSJens Wiklander #ifdef UsingFloat
177427e8d08dSJens Wiklander bs = pow(x, (double) (myrand() & (ExpIncr - 1)));
177527e8d08dSJens Wiklander #else
177627e8d08dSJens Wiklander bs = (rand() & (ExpIncr * 4 - 1)) / (1 << (rand() & 0x7));
177727e8d08dSJens Wiklander #endif
1778074ba9b2SJens Wiklander bs = blimit(bs);
1779074ba9b2SJens Wiklander #ifdef BECtl
1780074ba9b2SJens Wiklander protect = 1; /* Protect against compaction */
1781074ba9b2SJens Wiklander #endif
178217967299SJens Wiklander newb = (char *) bgetr((void *) fb, align, hdr_size, bs, &mypoolset);
1783074ba9b2SJens Wiklander #ifdef BECtl
1784074ba9b2SJens Wiklander protect = 0;
1785074ba9b2SJens Wiklander #endif
1786074ba9b2SJens Wiklander if (newb != NULL) {
178717967299SJens Wiklander assert(!align || !(((unsigned long)newb + hdr_size) &
178817967299SJens Wiklander (align - 1)));
1789074ba9b2SJens Wiklander *((char **) bc) = newb;
1790074ba9b2SJens Wiklander }
1791074ba9b2SJens Wiklander }
1792074ba9b2SJens Wiklander }
1793074ba9b2SJens Wiklander }
1794074ba9b2SJens Wiklander }
179527e8d08dSJens Wiklander stats("\nAfter allocation", &mypoolset);
1796074ba9b2SJens Wiklander if (bp != NULL) {
179727e8d08dSJens Wiklander #ifdef BufValid
1798074ba9b2SJens Wiklander V bpoolv((void *) bp);
179927e8d08dSJens Wiklander #endif
180027e8d08dSJens Wiklander #ifdef BufDump
1801074ba9b2SJens Wiklander bpoold((void *) bp, dumpAlloc, dumpFree);
180227e8d08dSJens Wiklander #endif
1803074ba9b2SJens Wiklander }
1804074ba9b2SJens Wiklander
1805074ba9b2SJens Wiklander while (bchain != NULL) {
1806074ba9b2SJens Wiklander char *buf = bchain;
1807074ba9b2SJens Wiklander
1808074ba9b2SJens Wiklander bchain = *((char **) buf);
180927e8d08dSJens Wiklander brel((void *) buf, &mypoolset, true/*wipe*/);
1810074ba9b2SJens Wiklander }
181127e8d08dSJens Wiklander stats("\nAfter release", &mypoolset);
1812074ba9b2SJens Wiklander #ifndef BECtl
1813074ba9b2SJens Wiklander if (bp != NULL) {
181427e8d08dSJens Wiklander #ifdef BufValid
1815074ba9b2SJens Wiklander V bpoolv((void *) bp);
181627e8d08dSJens Wiklander #endif
181727e8d08dSJens Wiklander #ifdef BufDump
1818074ba9b2SJens Wiklander bpoold((void *) bp, dumpAlloc, dumpFree);
181927e8d08dSJens Wiklander #endif
1820074ba9b2SJens Wiklander }
1821074ba9b2SJens Wiklander #endif
1822074ba9b2SJens Wiklander
1823074ba9b2SJens Wiklander return 0;
1824074ba9b2SJens Wiklander }
1825074ba9b2SJens Wiklander #endif
1826