blob: 0ec305813d66b6c01f380a72e77a83e33222171b [file]
/**
* Copyright (C) Advanced Micro Devices, Inc. All rights reserved.
*
* You may not use this software and documentation (if any) (collectively, the
* "Materials") except in compliance with the terms and conditions of the
* Software License Agreement included with the Materials or otherwise as set
* forth in writing and signed by you and an authorized signatory of AMD.
*
* If you do not have a copy of the Software License Agreement, contact your AMD
* representative for a copy. You agree that you will not reverse engineer or
* decompile the Materials, in whole or in part, except as allowed by applicable
* law.
*
* THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef DC_MEMORY_POOL_H
#define DC_MEMORY_POOL_H
#include "os_types.h"
/**
* Non-resizable lock-free memory pool with fixed capacity.
*
* Custom implementation is used over Linux llist, as llist requires external
* locking if more than one thread pops from the list.
*
* Emplace and erase operations do not use any mutexes or spinlocks, which
* guarantees forward progress even if another thread
* has been suspended in the middle of the call. High contention might result
* in multiple internal retries, but will eventually either succeed once other
* threads stop actively modifying the pool, or fail if the pool is empty.
*
* Implemented as Treiber stack using indexed free list and head with generation
* counter to solve ABA problem, as each modification of the head increments
* the generation, preventing issue of `push(A)` being indistinguishable from
* `push(A); { push(B); pop(B); }` to another thread, corrupting data structure.
*/
struct dc_memory_pool;
/**
* Create dc_memory_pool.
*
* @param size Non-zero pool block size, all acquires will be of this size.
* @param capacity Non-zero number of blocks that can be acquired from the pool.
* @return Pointer to the pool if succeeded, null if failed.
*/
__must_check struct dc_memory_pool *dc_memory_pool_create(size_t size,
size_t capacity);
/**
* Destroy given pool and free all allocated memory, invalidating any pointers.
*
* This operation is not synchronized, calling any other operation on the pool
* while it is being destroyed results in Undefined Behavior.
*
* @param pool Can be null to support common destruction patterns.
*/
void dc_memory_pool_destroy(struct dc_memory_pool *pool);
/**
* Acquire single block from pool.
*
* @param pool Cannot be null.
* @return Pointer to block if succeeded, null if empty.
*/
__must_check void *dc_memory_pool_acquire(struct dc_memory_pool *pool);
/**
* Release previously acquired block, freeing it for others to acquire.
*
* @param pool Cannot be null.
* @param memory Cannot be null, has to be owned by the pool.
*/
void dc_memory_pool_release(struct dc_memory_pool *pool, void *memory);
/**
* Check if given memory is owned by the pool to facilitate arenas.
*
* @warning if (owns(pool, p)) release(pool, p);` pattern is not safe
* if used with same `p` from multiple unsynchronized threads.
* If multiple owning threads are desired, use krefs to assure single release.
*
* @param pool Cannot be null.
* @param memory Cannot be null.
* @return True if the memory was previously acquired from the pool.
*/
__must_check bool dc_memory_pool_owns(const struct dc_memory_pool *pool,
const void *memory);
/**
* Get pool block size.
*
* @param pool Cannot be null.
* @return Pool block size as given to dc_memory_pool_create().
*/
__must_check size_t dc_memory_pool_size(const struct dc_memory_pool *pool);
/**
* Get pool block count.
*
* @param pool Cannot be null.
* @return Pool block count as given to dc_memory_pool_create().
*/
__must_check size_t dc_memory_pool_capacity(const struct dc_memory_pool *pool);
#endif // Header guard