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 struct AxlArena AxlArena
typedef uint32_t AxlTaskId
typedef void (*AxlTaskProc)(void *arg, AxlArena *arena)

AxlTaskProc:

Task procedure &#8212; runs on an AP. Must be AP-safe: no Boot Services, no protocol calls, no axl_print. Use the arena for memory.

typedef void (*AxlTaskComplete)(void *arg, AxlArena *arena)

AxlTaskComplete:

Completion callback &#8212; runs on BSP during axl_task_pool_poll.

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.