AxlTask – Task Pool and Arena
AP worker pool, region-based arena allocator, preallocated buffer pool, and async work helpers.
Headers:
<axl/axl-task.h>– Arena allocator and AP task pool<axl/axl-buf-pool.h>– Preallocated buffer pool (LIFO free-stack)<axl/axl-async.h>– AP-offloaded async work
Overview
UEFI systems have multiple CPU cores, but only one – the Bootstrap Processor (BSP) – can call Boot Services (I/O, networking, protocol calls). The other cores are Application Processors (APs) that can run compute-heavy tasks in parallel.
BSP (main core) APs (worker cores)
├─ Boot Services (gBS) ├─ CRC/checksum
├─ Protocol calls ├─ Decompression
├─ Network I/O ├─ Hash computation
├─ File I/O ├─ Data parsing
├─ axl_printf └─ Memory-only work
└─ Event loop (no Boot Services!)
AP constraints: APs cannot call Boot Services, axl_printf,
axl_fopen, or any UEFI protocol function. They can only access
memory (including the arena allocator, which uses lock-free CAS).
Arena Allocator
Lock-free bump allocator for AP-safe memory. Pre-allocates a contiguous block; allocations are O(1) pointer bumps with CAS (no locks needed for concurrent AP access).
AXL_AUTOPTR(AxlArena) arena = axl_arena_new(4096);
// AP-safe: can be called from any core
void *buf = axl_arena_alloc(arena, 256);
// BSP-only: reset frees all allocations at once
axl_arena_reset(arena);
Task Pool
Submit work to an AP and get a callback on the BSP when it completes:
// Initialize (discovers available APs)
axl_task_pool_init();
// AP work function (runs on a worker core)
void compute(void *arg, AxlArena *arena) {
Result *r = axl_arena_alloc(arena, sizeof(Result));
r->crc = calculate_crc(arg);
}
// BSP completion callback (runs on main core)
void on_done(void *arg, AxlArena *arena) {
axl_printf("CRC computed on AP\n");
}
AxlArena *arena = axl_arena_new(1024);
axl_task_pool_submit(compute, data, arena, on_done);
// Poll for completions (call from event loop or main loop)
axl_task_pool_poll();
// Single-core fallback: if no APs available, submit runs
// the work synchronously on the BSP.
AxlBufPool
Preallocated fixed-size buffer pool with LIFO free-stack. Zero-copy:
get returns a buffer pointer, put returns it to the pool.
No allocation or freeing in the hot path.
AXL_AUTOPTR(AxlBufPool) pool = axl_buf_pool_new(4, 64 * 1024);
// ^ ^
// 4 buffers, 64KB each
void *buf = axl_buf_pool_get(pool); // grab a buffer (NULL if exhausted)
// ... use buf ...
axl_buf_pool_put(pool, buf); // return to pool
AxlAsync
Convenience wrapper: submit AP work and get a BSP callback via the event loop (combines AxlTask + AxlLoop idle source).
axl_async_init(4); // max 4 pending jobs
axl_async_submit(loop, work_fn, data, arena, done_fn);
// work_fn runs on AP, done_fn fires on BSP via loop idle
axl_async_shutdown();
API Reference
AxlTask
Defines
-
AXL_TASK_ID_INVALID
Typedefs
-
typedef uint32_t AxlTaskId
Functions
-
AxlArena *axl_arena_new(size_t capacity)
Create a new arena with fixed capacity. BSP-only.
All memory is zeroed.
- Parameters:
capacity – total bytes available
- Returns:
arena handle, or NULL on failure.
-
void axl_arena_free(AxlArena *arena)
Free backing memory. BSP-only.
- Parameters:
arena – arena to free (NULL-safe)
-
void *axl_arena_alloc(AxlArena *arena, size_t size)
Allocate from arena. AP-safe (lock-free CAS).
Returns zeroed, 8-byte-aligned memory. Returns NULL on exhaustion.
- Parameters:
arena – arena
size – bytes to allocate
-
void axl_arena_reset(AxlArena *arena)
Reset arena, freeing all allocations.
Backing memory retained and zeroed. BSP-only.
- Parameters:
arena – arena to reset
-
size_t axl_arena_remaining(AxlArena *arena)
Get bytes remaining in the arena.
- Parameters:
arena – arena to query
- Returns:
bytes remaining.
-
size_t axl_arena_capacity(AxlArena *arena)
Get total capacity of the arena.
- Parameters:
arena – arena to query
- Returns:
total capacity in bytes.
-
int axl_task_pool_init(void)
Initialize the task pool.
Locates MP Services and dispatches APs.
- Returns:
0 on success, 1 on single-core (fallback active), -1 on error.
-
void axl_task_pool_shutdown(void)
Shut down the task pool. Signals all workers to exit.
-
AxlTaskId axl_task_pool_submit(AxlTaskProc proc, void *arg, AxlArena *arena, AxlTaskComplete on_complete)
Submit a task. Non-blocking.
On single-core, runs synchronously.
- Parameters:
proc – task procedure (AP-safe)
arg – argument passed to proc and on_complete
arena – arena for task allocations (NULL = no arena)
on_complete – BSP callback when done (NULL = fire-and-forget)
- Returns:
task ID, or AXL_TASK_ID_INVALID if all workers busy.
-
size_t axl_task_pool_poll(void)
Poll for completed tasks. Call once per event loop iteration.
- Returns:
number of tasks completed this poll cycle.
-
bool axl_task_pool_done(AxlTaskId id)
Check if a task is done.
- Parameters:
id – task ID
- Returns:
true if task is done (or ID is invalid).
-
size_t axl_task_pool_available(void)
Get idle worker count.
- Returns:
number of idle workers.
-
size_t axl_task_pool_worker_count(void)
Get total worker count.
- Returns:
total worker count (0 on single-core).
AxlBufPool
Typedefs
-
typedef struct AxlBufPool AxlBufPool
Functions
-
AxlBufPool *axl_buf_pool_new(size_t count, size_t buf_size)
Create a new buffer pool.
Allocates count buffers of buf_size bytes each in a single contiguous block. All buffers are initially available.
- Parameters:
count – number of buffers
buf_size – size of each buffer in bytes
- Returns:
pool handle, or NULL on failure.
-
void *axl_buf_pool_get(AxlBufPool *pool)
Get a buffer from the pool.
- Parameters:
pool – buffer pool
- Returns:
pointer to a buffer, or NULL if the pool is exhausted.
-
void axl_buf_pool_put(AxlBufPool *pool, void *buf)
Return a buffer to the pool.
The buffer must have been obtained from this pool via axl_buf_pool_get. NULL-safe (no-op if pool or buf is NULL).
- Parameters:
pool – buffer pool
buf – buffer to return
-
size_t axl_buf_pool_available(AxlBufPool *pool)
Get the number of available (free) buffers.
- Parameters:
pool – buffer pool (NULL returns 0)
- Returns:
number of buffers available for axl_buf_pool_get.
-
size_t axl_buf_pool_buf_size(AxlBufPool *pool)
Get the size of each buffer in the pool.
- Parameters:
pool – buffer pool
- Returns:
buffer size in bytes (0 if pool is NULL).
-
void axl_buf_pool_free(AxlBufPool *pool)
Free the pool and all backing memory. NULL-safe.
- Parameters:
pool – buffer pool to free
AxlAsync
Defines
-
AXL_ASYNC_INVALID
Typedefs
-
typedef size_t AxlAsyncHandle
Functions
-
int axl_async_init(size_t max_pending)
Initialize the async subsystem.
Allocates internal slot array and initializes the task pool.
- Parameters:
max_pending – maximum concurrent async jobs
- Returns:
0 on success, -1 on failure.
-
void axl_async_shutdown(void)
Shut down the async subsystem. Drains pending work.
-
AxlAsyncHandle axl_async_submit(AxlLoop *loop, AxlTaskProc work_fn, void *data, AxlArena *arena, AxlTaskComplete done_cb)
Submit work to an AP core.
On multi-core, dispatches work_fn to an AP and returns immediately. On single-core, runs work_fn and done_cb synchronously before returning.
- Parameters:
loop – event loop (idle source installed here)
work_fn – AP work function (same as AxlTaskProc)
data – argument passed to work_fn and done_cb
arena – arena for AP allocations (NULL OK)
done_cb – BSP callback when done (NULL = fire-and-forget)
- Returns:
handle for axl_async_cancel, or AXL_ASYNC_INVALID on failure.
-
bool axl_async_cancel(AxlAsyncHandle handle)
Cancel pending async work (best-effort).
AP work continues to completion, but done_cb is suppressed.
- Parameters:
handle – handle from axl_async_submit
- Returns:
true if cancelled, false if handle invalid or already completed.
-
size_t axl_async_pending(void)
Get the number of pending (in-flight) async jobs.
- Returns:
number of jobs submitted but not yet completed.