.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "ici::doc::pod3::psm 3" .TH ici::doc::pod3::psm 3 "2016-07-07" "perl v5.24.1" "ICI library functions" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" psm \- Personal Space Management .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& #include "psm.h" \& \& typedef enum { Okay, Redundant, Refused } PsmMgtOutcome; \& typedef unsigned long PsmAddress; \& typedef struct psm_str \& { \& char *space; \& int freeNeeded; \& struct psm_str *trace; \& int traceArea[3]; \& } PsmView, *PsmPartition; \& \& [see description for available functions] .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\s-1PSM\s0 is a library of functions that support personal space management, that is, user management of an application-configured memory partition. \s-1PSM\s0 is designed to be faster and more efficient than malloc/free (for details, see the \s-1DETAILED DESCRIPTION\s0 below), but more importantly it provides a memory management abstraction that insulates applications from differences in the management of private versus shared memory. .PP \&\s-1PSM\s0 is often used to manage shared memory partitions. On most operating systems, separate tasks that connect to a common shared memory partition are given the same base address with which to access the partition. On some systems (such as Solaris) this is not necessarily the case; an absolute address within such a shared partition will be mapped to different pointer values in different tasks. If a pointer value is stored within shared memory and used without conversion by multiple tasks, segment violations will occur. .PP \&\s-1PSM\s0 gets around this problem by providing functions for translating between local pointer values and relative addresses within the shared memory partition. For complete portability, applications which store addresses in shared memory should store these addresses as \s-1PSM\s0 relative addresses and convert them to local pointer values before using them. The PsmAddress data type is provided for this purpose, along with the conversion functions \fIpsa()\fR and \fIpsp()\fR. .IP "int psm_manage(char *start, unsigned int length, char *name, PsmPartition *partitionPointer, PsmMgtOutcome *outcome)" 4 .IX Item "int psm_manage(char *start, unsigned int length, char *name, PsmPartition *partitionPointer, PsmMgtOutcome *outcome)" Puts the \fIlength\fR bytes of memory at \fIstart\fR under \s-1PSM\s0 management, associating this memory partition with the identifying string \fIname\fR (which is required and which can have a maximum string length of 31). \s-1PSM\s0 can manage any contiguous range of addresses to which the application has access, typically a block of heap memory returned by a malloc call. .Sp Every other \s-1PSM API\s0 function must be passed a pointer to a local \*(L"partition\*(R" state structure characterizing the PSM-managed memory to which the function is to be applied. The partition state structure itself may be pre-allocated in static or local (or shared) memory by the application, in which case a pointer to that structure must be passed to \fIpsm_manage()\fR as the value of \fI*partitionPointer\fR; if \fI*partitionPointer\fR is null, \&\fIpsm_manage()\fR will use \fImalloc()\fR to allocate this structure dynamically from local memory and will store a pointer to the structure in \&\fI*partitionPointer\fR. .Sp \&\fIpsm_manage()\fR formats the managed memory as necessary and returns \-1 on any error, 0 otherwise. The outcome to the attempt to manage memory is placed in \fIoutcome\fR. An outcome of Redundant means that the memory at \fIstart\fR is already under \s-1PSM\s0 management with the same name and size. An outcome of Refused means that \s-1PSM\s0 was unable to put the memory at \fIstart\fR under \&\s-1PSM\s0 management as directed; a diagnostic message was posted to the message pool (see discussion of \fIputErrmsg()\fR in \fIplatform\fR\|(3)). .IP "char *psm_name(PsmPartition partition)" 4 .IX Item "char *psm_name(PsmPartition partition)" Returns the name associated with the partition at the time it was put under management. .IP "char *psm_space(PsmPartition partition)" 4 .IX Item "char *psm_space(PsmPartition partition)" Returns the address of the space managed by \s-1PSM\s0 for \fIpartition\fR. This function is provided to enable the application to do an operating-system release (such as \fIfree()\fR) of this memory when the managed partition is no longer needed. \fI\s-1NOTE\s0\fR that calling \&\fIpsm_erase()\fR or \fIpsm_unmanage()\fR [or any other \s-1PSM\s0 function, for that matter] after releasing that space is virtually guaranteed to result in a segmentation fault or other seriously bad behavior. .IP "void *psp(PsmPartition partition, PsmAddress address)" 4 .IX Item "void *psp(PsmPartition partition, PsmAddress address)" \&\fIaddress\fR is an offset within the space managed for the partition. Returns the conversion of that offset into a locally usable pointer. .IP "PsmAddress psa(PsmPartition partition, void *pointer)" 4 .IX Item "PsmAddress psa(PsmPartition partition, void *pointer)" Returns the conversion of \fIpointer\fR into an offset within the space managed for the partition. .IP "PsmAddress psm_malloc(PsmPartition partition, unsigned int length)" 4 .IX Item "PsmAddress psm_malloc(PsmPartition partition, unsigned int length)" Allocates a block of memory from the \*(L"large pool\*(R" of the indicated partition. (See the \s-1DETAILED DESCRIPTION\s0 below.) \fIlength\fR is the size of the block to allocate; the maximum size is 1/2 of the total address space (i.e., 2G for a 32\-bit machine). Returns \&\s-1NULL\s0 if no free block could be found. The block returned is aligned on a doubleword boundary. .IP "void psm_panic(PsmPartition partition)" 4 .IX Item "void psm_panic(PsmPartition partition)" Forces the \*(L"large pool\*(R" memory allocation algorithm to hunt laboriously for free blocks in buckets that may not contain any. This setting remains in force for the indicated partition until a subsequent \fIpsm_relax()\fR call reverses it. .IP "void psm_relax(PsmPartition partition)" 4 .IX Item "void psm_relax(PsmPartition partition)" Reverses \fIpsm_panic()\fR. Lets the \*(L"large pool\*(R" memory allocation algorithm return \s-1NULL\s0 when no free block can be found easily. .IP "PsmAddress psm_zalloc(PsmPartition partition, unsigned int length)" 4 .IX Item "PsmAddress psm_zalloc(PsmPartition partition, unsigned int length)" Allocates a block of memory from the \*(L"small pool\*(R" of the indicated partition, if possible; if the requested block size \*(-- \fIlength\fR \*(-- is too large for small pool allocation (which is limited to 64 words, i.e., 256 bytes for a 32\-bit machine), or if no small pool space is available and the size of the small pool cannot be increased, then allocates from the large pool instead. Small pool allocation is performed by an especially speedy algorithm, and minimum space is consumed in memory management overhead for small-pool blocks. Returns \s-1NULL\s0 if no free block could be found. The block returned is aligned on a word boundary. .IP "void psm_free(PsmPartition partition, PsmAddress block)" 4 .IX Item "void psm_free(PsmPartition partition, PsmAddress block)" Frees for subsequent re-allocation the indicated block of memory from the indicated partition. \fIblock\fR may have been allocated by either \fIpsm_malloc()\fR or \fIpsm_zalloc()\fR. .IP "int psm_set_root(PsmPartition partition, PsmAddress root)" 4 .IX Item "int psm_set_root(PsmPartition partition, PsmAddress root)" Sets the \*(L"root\*(R" word of the indicated partition (a word at a fixed, private location in the \s-1PSM\s0 bookkeeping data area) to the indicated value. This function is typically useful in a shared-memory environment, such as a VxWorks address space, in which a task wants to retrieve from the indicated partition some data that was inserted into the partition by some other task; the partition root word enables multiple tasks to navigate the same data in the same \s-1PSM\s0 partition in shared memory. The argument is normally a pointer to something like a linked list of the linked lists that populate the partition; in particular, it is likely to be an object catalog (see \fIpsm_add_catlg()\fR). Returns 0 on success, \-1 on any failure (e.g., the partition already has a root object, in which case \fIpsm_erase_root()\fR must be called before \fIpsm_set_root()\fR). .IP "PsmAddress psm_get_root(PsmPartition partition)" 4 .IX Item "PsmAddress psm_get_root(PsmPartition partition)" Retrieves the current value of the root word of the indicated partition. .IP "void psm_erase_root(PsmPartition partition)" 4 .IX Item "void psm_erase_root(PsmPartition partition)" Erases the current value of the root word of the indicated partition. .IP "PsmAddress psm_add_catlg(PsmPartition partition)" 4 .IX Item "PsmAddress psm_add_catlg(PsmPartition partition)" Allocates space for an object catalog in the indicated partition and establishes the new catalog as the partition's root object. Returns 0 on success, \-1 on any error (e.g., the partition already has some other root object). .IP "int psm_catlg(PsmPartition partition, char *objName, PsmAddress objLocation)" 4 .IX Item "int psm_catlg(PsmPartition partition, char *objName, PsmAddress objLocation)" Inserts an entry for the indicated object into the catalog that is the root object for this partition. The length of \fIobjName\fR cannot exceed 32 bytes, and \fIobjName\fR must be unique in the catalog. Returns 0 on success, \-1 on any error. .IP "int psm_uncatlg(PsmPartition partition, char *objName)" 4 .IX Item "int psm_uncatlg(PsmPartition partition, char *objName)" Removes the entry for the named object from the catalog that is the root object for this partition, if that object is found in the catalog. Returns 0 on success, \-1 on any error. .IP "int psm_locate(PsmPartition partition, char *objName, PsmAddress *objLocation, PsmAddress *entryElt)" 4 .IX Item "int psm_locate(PsmPartition partition, char *objName, PsmAddress *objLocation, PsmAddress *entryElt)" Places in \fI*objLocation\fR the address associated with \fIobjName\fR in the catalog that is the root object for this partition and places in \fI*entryElt\fR the address of the list element that points to this catalog entry. If \fIname\fR is not found in catalog, set \fI*entryElt\fR to zero. Returns 0 on success, \-1 on any error. .IP "void psm_usage(PsmPartition partition, PsmUsageSummary *summary)" 4 .IX Item "void psm_usage(PsmPartition partition, PsmUsageSummary *summary)" Loads the indicated PsmUsageSummary structure with a snapshot of the indicated partition's usage status. PsmUsageSummary is defined by: .Sp .Vb 10 \& typedef struct { \& char partitionName[32]; \& unsigned int partitionSize; \& unsigned int smallPoolSize; \& unsigned int smallPoolFreeBlockCount[SMALL_SIZES]; \& unsigned int smallPoolFree; \& unsigned int smallPoolAllocated; \& unsigned int largePoolSize; \& unsigned int largePoolFreeBlockCount[LARGE_ORDERS]; \& unsigned int largePoolFree; \& unsigned int largePoolAllocated; \& unsigned int unusedSize; \& } PsmUsageSummary; .Ve .IP "void psm_report(PsmUsageSummary *summary)" 4 .IX Item "void psm_report(PsmUsageSummary *summary)" Sends to stdout the content of \fIsummary\fR, a snapshot of a partition's usage status. .IP "void psm_unmanage(PsmPartition partition)" 4 .IX Item "void psm_unmanage(PsmPartition partition)" Terminates local \s-1PSM\s0 management of the memory in \fIpartition\fR and destroys the partition state structure \fI*partition\fR, but doesn't erase anything in the managed memory; \s-1PSM\s0 management can be re-established by a subsequent call to \fIpsm_manage()\fR. .IP "void psm_erase(PsmPartition partition)" 4 .IX Item "void psm_erase(PsmPartition partition)" Unmanages the indicated partition and additionally discards all information in the managed memory, preventing re-management of the partition. .SH "MEMORY USAGE TRACING" .IX Header "MEMORY USAGE TRACING" If \s-1PSM_TRACE\s0 is defined at the time the \s-1PSM\s0 source code is compiled, the system includes built-in support for simple tracing of memory usage: memory allocations are logged, and memory deallocations are matched to logged allocations, \*(L"closing\*(R" them. This enables memory leaks and some other kinds of memory access problems to be readily investigated. .IP "int psm_start_trace(PsmPartition partition, int traceLogSize, char *traceLogAddress)" 4 .IX Item "int psm_start_trace(PsmPartition partition, int traceLogSize, char *traceLogAddress)" Begins an episode of \s-1PSM\s0 memory usage tracing. \fItraceLogSize\fR is the number of bytes of shared memory to use for trace activity logging; the frequency with which \*(L"closed\*(R" trace log events must be deleted will vary inversely with the amount of memory allocated for the trace log. \&\fItraceLogAddress\fR is normally \s-1NULL,\s0 causing the trace system to allocate \&\fItraceLogSize\fR bytes of shared memory dynamically for trace logging; if non-NULL, it must point to \fItraceLogSize\fR bytes of shared memory that have been pre-allocated by the application for this purpose. Returns 0 on success, \-1 on any failure. .IP "void psm_print_trace(PsmPartition partition, int verbose)" 4 .IX Item "void psm_print_trace(PsmPartition partition, int verbose)" Prints a cumulative trace report and current usage report for \&\fIpartition\fR. If \fIverbose\fR is zero, only exceptions (notably, trace log events that remain open \*(-- potential memory leaks) are printed; otherwise all activity in the trace log is printed. .IP "void psm_clear_trace(PsmPartition partition)" 4 .IX Item "void psm_clear_trace(PsmPartition partition)" Deletes all closed trace log events from the log, freeing up memory for additional tracing. .IP "void psm_stop_trace(PsmPartition partition)" 4 .IX Item "void psm_stop_trace(PsmPartition partition)" Ends the current episode of \s-1PSM\s0 memory usage tracing. If the shared memory used for the trace log was allocated by \fIpsm_start_trace()\fR, releases that shared memory. .SH "EXAMPLE" .IX Header "EXAMPLE" For an example of the use of psm, see the file psmshell.c in the \s-1PSM\s0 source directory. .SH "USER'S GUIDE" .IX Header "USER'S GUIDE" .IP "Compiling a \s-1PSM\s0 application" 4 .IX Item "Compiling a PSM application" Just be sure to \*(L"#include \*(R"psm.h"" at the top of each source file that includes any \s-1PSM\s0 function calls. .IP "Linking/loading a \s-1PSM\s0 application" 4 .IX Item "Linking/loading a PSM application" a. In a \s-1UNIX\s0 environment, link with libpsm.a. .Sp b. In a VxWorks environment, use .Sp .Vb 1 \& ld 1, 0, "libpsm.o" .Ve .Sp to load \s-1PSM\s0 on the target before loading any \s-1PSM\s0 applications. .IP "Typical usage:" 4 .IX Item "Typical usage:" a. Call \fIpsm_manage()\fR to initiate management of the partition. .Sp b. Call \fIpsm_malloc()\fR (and/or \fIpsm_zalloc()\fR) to allocate space in the partition; call \fIpsm_free()\fR to release space for later re-allocation. .Sp c. When \fIpsm_malloc()\fR returns \s-1NULL\s0 and you're willing to wait a while for a more exhaustive free block search, call \&\fIpsm_panic()\fR before retrying \fIpsm_malloc()\fR. When you're no longer so desperate for space, call \fIpsm_relax()\fR. .Sp d. To store a vital pointer in the single predefined location in the partition that \s-1PSM\s0 reserves for this purpose, call \&\fIpsm_set_root()\fR; to retrieve that pointer, call \fIpsm_get_root()\fR. .Sp e. To get a snapshot of the current configuration of the partition, call \fIpsm_usage()\fR. To print this snapshot to stdout, call \fIpsm_report()\fR. .Sp f. When you're done with the partition but want to leave it in its current state for future re-management (e.g., if the partition is in shared memory), call \fIpsm_unmanage()\fR. If you're done with the partition forever, call \fIpsm_erase()\fR. .SH "DETAILED DESCRIPTION" .IX Header "DETAILED DESCRIPTION" \&\s-1PSM\s0 supports user management of an application-configured memory partition. The partition is functionally divided into two pools of variable size: a \*(L"small pool\*(R" of low-overhead blocks aligned on 4\-byte boundaries that can each contain up to 256 bytes of user data, and a \*(L"large pool\*(R" of high-overhead blocks aligned on 8\-byte boundaries that can each contain up to 2GB of user data. .PP Space in the small pool is allocated in any one of 64 different block sizes; each possible block size is (4i + n) where i is a \&\*(L"block list index\*(R" from 1 through 64 and n is the length of the \&\s-1PSM\s0 overhead information per block [4 bytes on a 32\-bit machine]. Given a user request for a block of size q where q is in the range 1 through 256 inclusive, we return the first block on the j'th small-pool free list where j = (q \- 1) / 4. If there is no such block, we increase the size of the small pool [incrementing its upper limit by (4 * (j + 1)) + n], initialize the increase as a free block from list j, and return that block. No attempt is made to consolidate physically adjacent blocks when they are freed or to bisect large blocks to satisfy requests for small ones; if there is no free block of the requested size and the size of the small pool cannot be increased without encroaching on the large pool (or if the requested size exceeds 256), we attempt to allocate a large-pool block as described below. The differences between small-pool and large-pool blocks are transparent to the user, and small-pool and large-pool blocks can be freely intermixed in an application. .PP Small-pool blocks are allocated and freed very rapidly, and space overhead consumption is small, but capacity per block is limited and space assigned to small-pool blocks of a given size is never again available for any other purpose. The small pool is designed to satisfy requests for allocation of a stable overall population of small, volatile objects such as List and ListElt structures (see \fIlyst\fR\|(3)). .PP Space in the large pool is allocated from any one of 29 buckets, one for each power of 2 in the range 8 through 2G. The size of each block can be expressed as (n + 8i + m) where i is any integer in the range 1 through 256M, n is the size of the block's leading overhead area [8 bytes on a 32\-bit machine], and m is the size of the block's trailing overhead area [also 8 bytes on a 32\-bit machine]. Given a user request for a block of size q where q is in the range 1 through 2G inclusive, we first compute r as the smallest multiple of 8 that is greater than or equal to q. We then allocate the first block in bucket t such that 2 ** (t + 3) is the smallest power of 2 that is greater than r [or, if r is a power of 2, the first block in bucket t such that 2 ** (t + 3) = r]. That is, we try to allocate blocks of size 8 from bucket 0 [2**3 = 8], blocks of size 16 from bucket 1 [2**4 = 16], blocks of size 24 from bucket 2 [2**5 = 32, 32 > 24], blocks of size 32 from bucket 2 [2**5 = 32], and so on. t is the first bucket whose free blocks are \s-1ALL\s0 guaranteed to be at least as large as r; bucket t \- 1 may also contain some blocks that are as large as r (e.g., bucket 1 will contain blocks of size 24 as well as blocks of size 16), but we would have to do a possibly time consuming sequential search through the free blocks in that bucket to find a match, because free blocks within a bucket are stored in no particular order. .PP If bucket t is empty, we allocate the first block from the first non-empty bucket corresponding to a greater power of two; if all eligible bucket are empty, we increase the size of the large pool [decrementing its lower limit by (r + 16)], initialize the increase as a free block and \*(L"free\*(R" it, and try again. If the size of the large pool cannot be increased without encroaching on the small pool, then if we are desperate we search sequentially through all blocks in bucket t \- 1 (some of which may be of size r or greater) and allocate the first block that is big enough, if any. Otherwise, no block is returned. .PP Having selected a free block to allocate, we remove the allocated block from the free list, split off as a new free block all bytes in excess of (r + 16) bytes [unless that excess is too small to form a legal-size block], and return the remainder to the user. When a block is freed, it is automatically consolidated with the physically preceding block (if that block is free) and the physically subsequent block (if that block is free). .PP Large-pool blocks are allocated and freed quite rapidly; capacity is effectively unlimited; space overhead consumption is very high for extremely small objects but becomes an insignificant fraction of block size as block size increases. The large pool is designed to serve as a general-purpose heap with minimal fragmentation whose overhead is best justified when used to store relatively large, long-lived objects such as image packets. .PP The general goal of this memory allocation scheme is to satisfy memory management requests rapidly and yet minimize the chance of refusing a memory allocation request when adequate unused space exists but is inaccessible (because it is fragmentary or is buried as unused space in a block that is larger than necessary). The size of a small-pool block delivered to satisfy a request for q bytes will never exceed q + 3 (alignment), plus 4 bytes of overhead. The size of a large-pool block delivered to satisfy a request for q bytes will never exceed q + 7 (alignment) + 20 (the maximum excess that can't be split off as a separate free block), plus 16 bytes of overhead. .PP Neither the small pool nor the large pool ever decrease in size, but large-pool space previously allocated and freed is available for small-pool allocation requests if no small-pool space is available. Small-pool space previously allocated and freed cannot easily be reassigned to the large pool, though, because blocks in the large pool must be physically contiguous to support defragmentation. No such reassignment algorithm has yet been developed. .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIlyst\fR\|(3)