Simple pool allocators allow an application to specify a location identifier when allocating memory. More sophisticated pool allocators also support pool-level operations such as freeing or printing an entire pool with one function call.
If you are using a simple pool allocator, you can defeat the pool allocator when the program is Purify'd in the same manner described for fixed-size allocators.
If you are using a sophisticated pool allocator, you can take advantage of Purify's pool support to implement the pool-level operations such as freeing a pool. Purify can handle each allocation request by calling malloc, and also labeling the returned block with the correct pool-id. Pool-level operations can then be performed later by mapping a function over all blocks with a given pool-id.
As with fixed-size allocators, you can use a run-time flag instead of a compile-time flag.
Purify's pool interface functions assume that pool-id is a 32-bit sized datum. For a complete list of functions for pool allocation, click
PoolId AllocatePool() {
if (purify_is_running()) {
static PoolId pool_counter
= 0;
/* return unique id, but
allocate no mem */
return pool_counter++;
} else {
... original code for AllocatePool()
...
}
}
char* AllocateFromPool(PoolId id, int size) {
if (purify_is_running()) {
char* ret = malloc(size);
purify_set_pool_id(ret,
id);
return ret;
} else {
... original code for AllocateFromPool
...
}
}
void FreeToPool(char* mem) {
if (purify_is_running()) {
free(mem); /* this clears
the pool id */
} else {
... original code for FreeToPool ...
}
}
void FreeEntirePool(PoolId id) {
if (purify_is_running()) {
/* call 'free' on each
block in this pool */
purify_map_pool(id, free);
} else {
... original code for FreeEntirePool
...
}
}
void PrintPool(PoolId id) {
if (purify_is_running()) {
/* PrintBlock operates
on a single block */
/* call PrintBlock on every
block in this pool */
purify_map_pool(id, PrintBlock);
} else {
... original code for PrintPool
...
}
}