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