Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aligned memory allocation #4277

Merged
merged 7 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 86 additions & 5 deletions pjlib/include/pj/pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@ struct pj_pool_t
/** The callback to be called when the pool is unable to allocate memory. */
pj_pool_callback *callback;

/** The default alignment of memory block allocated from this pool
* (must be power of 2). */
pj_size_t alignment;

};


Expand All @@ -347,8 +351,9 @@ struct pj_pool_t
#endif

/**
* Create a new pool from the pool factory. This wrapper will call create_pool
* member of the pool factory.
* Create a new pool from the pool factory. This wrapper will call
* pj_pool_aligned_create() with alignment parameter set to 0
* which means use the default alignment (PJ_POOL_ALIGNMENT).
*
* @param factory The pool factory.
* @param name The name to be assigned to the pool. The name should
Expand Down Expand Up @@ -379,6 +384,47 @@ PJ_IDECL(pj_pool_t*) pj_pool_create(pj_pool_factory *factory,
pj_size_t increment_size,
pj_pool_callback *callback);


/**
* Create a new pool from the pool factory. This wrapper will call create_pool
* member of the pool factory.
*
* @param factory The pool factory.
* @param name The name to be assigned to the pool. The name should
* not be longer than PJ_MAX_OBJ_NAME (32 chars), or
* otherwise it will be truncated.
* @param initial_size The size of initial memory blocks taken by the pool.
* Note that the pool will take 68+20 bytes for
* administrative area from this block.
* @param increment_size the size of each additional blocks to be allocated
* when the pool is running out of memory. If user
* requests memory which is larger than this size, then
* an error occurs.
* Note that each time a pool allocates additional block,
* it needs PJ_POOL_SIZE more to store some
* administrative info.
* @param alignment the default alignment of memory block allocated
* from this pool (must be power of 2).
* The actual allocation alignment will be at least equal
* to the alignment argument of the function,
* but not less than PJ_POOL_ALIGNMENT.
* Value of 0 means use PJ_POOL_ALIGNMENT.
* @param callback Callback to be called when error occurs in the pool.
* If this value is NULL, then the callback from pool
* factory policy will be used.
* Note that when an error occurs during pool creation,
* the callback itself is not called. Instead, NULL
* will be returned.
*
* @return The memory pool, or NULL.
*/
PJ_IDECL(pj_pool_t*) pj_pool_aligned_create(pj_pool_factory *factory,
const char *name,
pj_size_t initial_size,
pj_size_t increment_size,
pj_size_t alignment,
pj_pool_callback *callback);

/**
* Release the pool back to pool factory.
*
Expand Down Expand Up @@ -448,8 +494,10 @@ PJ_IDECL(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool );

/**
* Allocate storage with the specified size from the pool.
* The allocation will be aligned to the default alignment of the pool.
* If there's no storage available in the pool, then the pool can allocate more
* blocks if the increment size is larger than the requested size.
* This function will call pj_pool_aligned_alloc() with alignment set to 0.
*
* @param pool the pool.
* @param size the requested size.
Expand All @@ -460,6 +508,28 @@ PJ_IDECL(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool );
*/
PJ_IDECL(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size);


/**
* Allocate storage with the specified size and alignment from the pool.
* If there's no storage available in the pool, then the pool can allocate more
* blocks if the increment size is larger than the requested size.
*
* @param pool the pool.
* @param alignment the requested alignment of the allocation.
* The actual alignment of the allocation will be at least
* equal to the alignment argument of the function,
* but not less than the default pool alignment specified
* when the pool was created.
* Value of 0 means use the default alignment of this pool.
* @param size the requested size.
*
* @return pointer to the allocated memory.
*
* @see PJ_POOL_ALLOC_T
*/
PJ_IDECL(void *) pj_pool_aligned_alloc(pj_pool_t *pool, pj_size_t alignment,
pj_size_t size);

/**
* Allocate storage from the pool, and initialize it to zero.
* This function behaves like pj_pool_alloc(), except that the storage will
Expand Down Expand Up @@ -523,9 +593,11 @@ PJ_INLINE(void*) pj_pool_zalloc(pj_pool_t *pool, pj_size_t size)
* Internal functions
*/
/** Internal function */
PJ_IDECL(void*) pj_pool_alloc_from_block(pj_pool_block *block, pj_size_t size);
PJ_IDECL(void*) pj_pool_alloc_from_block(pj_pool_block *block, pj_size_t alignment,
pj_size_t size);
/** Internal function */
PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, pj_size_t size);
PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, pj_size_t alignment,
pj_size_t size);



Expand Down Expand Up @@ -687,7 +759,11 @@ struct pj_pool_factory
* Note that each time a pool allocates additional block,
* it needs 20 bytes (equal to sizeof(pj_pool_block)) to
* store some administrative info.
* @param callback Cllback to be called when error occurs in the pool.
* @param alignment the default alignment of memory block allocated
* from this pool (must be power of 2).
* A value of 0 should result in the pool being created
* with alignment equal to PJ_POOL_ALIGNMENT.
* @param callback Callback to be called when error occurs in the pool.
* Note that when an error occurs during pool creation,
* the callback itself is not called. Instead, NULL
* will be returned.
Expand All @@ -698,6 +774,7 @@ struct pj_pool_factory
const char *name,
pj_size_t initial_size,
pj_size_t increment_size,
pj_size_t alignment,
pj_pool_callback *callback);

/**
Expand Down Expand Up @@ -748,25 +825,29 @@ struct pj_pool_factory
* @param name Pool name.
* @param initial_size Initial size.
* @param increment_size Increment size.
* @param alignment Pool alignment.
* @param callback Callback.
* @return The pool object, or NULL.
*/
PJ_DECL(pj_pool_t*) pj_pool_create_int( pj_pool_factory *factory,
const char *name,
pj_size_t initial_size,
pj_size_t increment_size,
pj_size_t alignment,
pj_pool_callback *callback);

/**
* This function is intended to be used by pool factory implementors.
* @param pool The pool.
* @param name Pool name.
* @param increment_size Increment size.
* @param alignment Pool alignment.
* @param callback Callback function.
*/
PJ_DECL(void) pj_pool_init_int( pj_pool_t *pool,
const char *name,
pj_size_t increment_size,
pj_size_t alignment,
pj_pool_callback *callback);

/**
Expand Down
13 changes: 10 additions & 3 deletions pjlib/include/pj/pool_alt.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct pj_pool_t
char obj_name[32];
pj_size_t used_size;
pj_pool_callback *cb;
pj_size_t alignment;
};


Expand All @@ -68,7 +69,9 @@ PJ_DECL(int) pj_NO_MEMORY_EXCEPTION(void);
* function.
*/
#define pj_pool_create(fc,nm,init,inc,cb) \
pj_pool_create_imp(__FILE__, __LINE__, fc, nm, init, inc, cb)
pj_pool_create_imp(__FILE__, __LINE__, fc, nm, init, inc, 0, cb)
#define pj_pool_aligned_create(fc,nm,init,inc,alg,cb) \
pj_pool_create_imp(__FILE__, __LINE__, fc, nm, init, inc, alg, cb)

#define pj_pool_release(pool) pj_pool_release_imp(pool)
#define pj_pool_safe_release(pool) pj_pool_safe_release_imp(pool)
Expand All @@ -78,7 +81,9 @@ PJ_DECL(int) pj_NO_MEMORY_EXCEPTION(void);
#define pj_pool_get_capacity(pool) pj_pool_get_capacity_imp(pool)
#define pj_pool_get_used_size(pool) pj_pool_get_used_size_imp(pool)
#define pj_pool_alloc(pool,sz) \
pj_pool_alloc_imp(__FILE__, __LINE__, pool, sz)
pj_pool_alloc_imp(__FILE__, __LINE__, pool, 0, sz)
#define pj_pool_aligned_alloc(pool, alignment, sz) \
pj_pool_alloc_imp(__FILE__, __LINE__, pool, alignment, sz)

#define pj_pool_calloc(pool,cnt,elem) \
pj_pool_calloc_imp(__FILE__, __LINE__, pool, cnt, elem)
Expand All @@ -98,6 +103,7 @@ PJ_DECL(pj_pool_t*) pj_pool_create_imp(const char *file, int line,
const char *name,
pj_size_t initial_size,
pj_size_t increment_size,
pj_size_t alignment,
pj_pool_callback *callback);

/* Release pool */
Expand All @@ -123,7 +129,8 @@ PJ_DECL(pj_size_t) pj_pool_get_used_size_imp(pj_pool_t *pool);

/* Allocate memory from the pool */
PJ_DECL(void*) pj_pool_alloc_imp(const char *file, int line,
pj_pool_t *pool, pj_size_t sz);
pj_pool_t *pool, pj_size_t alignment,
pj_size_t sz);

/* Allocate memory from the pool and zero the memory */
PJ_DECL(void*) pj_pool_calloc_imp(const char *file, int line,
Expand Down
72 changes: 58 additions & 14 deletions pjlib/include/pj/pool_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

#include <pj/string.h>

#define PJ_POOL_ALIGN_PTR(PTR,ALIGNMENT) (PTR + (-(pj_ssize_t)(PTR) & (ALIGNMENT-1)))
#define PJ_IS_POWER_OF_TWO(val) (((val)>0) && ((val) & ((val)-1))==0)
#define PJ_IS_ALIGNED(PTR, ALIGNMENT) (!((pj_ssize_t)(PTR) & ((ALIGNMENT)-1)))

PJ_IDEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )
{
Expand All @@ -37,28 +40,59 @@ PJ_IDEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )
return used_size;
}

PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_block *block, pj_size_t size )
PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_block *block, pj_size_t alignment,
pj_size_t size )
{
bennylp marked this conversation as resolved.
Show resolved Hide resolved
/* The operation below is valid for size==0.
* When size==0, the function will return the pointer to the pool
* memory address, but no memory will be allocated.
*/
if (size & (PJ_POOL_ALIGNMENT-1)) {
size = (size + PJ_POOL_ALIGNMENT) & ~(PJ_POOL_ALIGNMENT-1);
}
if ((pj_size_t)(block->end - block->cur) >= size) {
void *ptr = block->cur;
block->cur += size;
unsigned char *ptr;

pj_assert(PJ_IS_POWER_OF_TWO(alignment) && PJ_IS_ALIGNED(size, alignment));
// Size should be already aligned.
// this code was moved up to pj_pool_aligned_alloc.
///* The operation below is valid for size==0.
// * When size==0, the function will return the pointer to the pool
// * memory address, but no memory will be allocated.
// */
//if (size & (alignment -1)) {
// size = (size + alignment) & ~(alignment -1);
//}
ptr = PJ_POOL_ALIGN_PTR(block->cur, alignment);
if (ptr + size <= block->end &&
/* here we check pointer overflow */
block->cur <= ptr && ptr <= ptr + size) {
block->cur = ptr + size;
return ptr;
}
return NULL;
}

PJ_IDEF(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size)
{
void *ptr = pj_pool_alloc_from_block(pool->block_list.next, size);
return pj_pool_aligned_alloc(pool, 0, size);
}

PJ_IDECL(void *) pj_pool_aligned_alloc(pj_pool_t *pool, pj_size_t alignment,
pj_size_t size)
{
void *ptr;

PJ_ASSERT_RETURN(!alignment || PJ_IS_POWER_OF_TWO(alignment), NULL);

if (alignment < pool->alignment)
alignment = pool->alignment;

/* The operation below is valid for size==0.
* When size==0, the function will return the pointer to the pool
* memory address, but no memory will be allocated.
*/
if (size & (alignment -1)) {
size = (size + alignment) & ~(alignment -1);
}
pj_assert(PJ_IS_ALIGNED(size, alignment));

ptr = pj_pool_alloc_from_block(pool->block_list.next,
alignment, size);
if (!ptr)
ptr = pj_pool_allocate_find(pool, size);
ptr = pj_pool_allocate_find(pool, alignment, size);
return ptr;
}

Expand All @@ -82,7 +116,17 @@ PJ_IDEF(pj_pool_t*) pj_pool_create( pj_pool_factory *f,
pj_size_t increment_size,
pj_pool_callback *callback)
{
return (*f->create_pool)(f, name, initial_size, increment_size, callback);
return pj_pool_aligned_create(f, name, initial_size, increment_size, 0, callback);
}

PJ_IDECL(pj_pool_t *) pj_pool_aligned_create(pj_pool_factory *f,
const char *name,
pj_size_t initial_size,
pj_size_t increment_size,
pj_size_t alignment,
pj_pool_callback *callback)
{
return (*f->create_pool)(f, name, initial_size, increment_size, alignment, callback);
}

PJ_IDEF(void) pj_pool_release( pj_pool_t *pool )
Expand Down
Loading
Loading