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:

// Create pool (discovers available APs)
AxlTaskPool *pool = axl_task_pool_new();

// 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(pool, compute, data, arena, on_done);

// Poll for completions (call from event loop or main loop)
axl_task_pool_poll(pool);

// Single-core fallback: if no APs available, submit runs
// the work synchronously on the BSP.

axl_task_pool_free(pool);

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).

AxlAsync *async = axl_async_new(loop, 4);  // max 4 pending jobs

axl_async_submit(async, work_fn, data, arena, done_fn);
// work_fn runs on AP, done_fn fires on BSP via loop idle

axl_async_free(async);

API Reference

AxlTask

Defines

AXL_TASK_ID_INVALID

Typedefs

typedef struct AxlArena AxlArena
typedef struct AxlTaskPool AxlTaskPool
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.

AxlTaskPool *axl_task_pool_new(void)

Create a new task pool.

Locates MP Services and dispatches APs.

Returns:

pool handle, or NULL on error.

void axl_task_pool_free(AxlTaskPool *pool)

Free the task pool. Signals all workers to exit.

Parameters:
  • pool – pool to free (NULL-safe)

AxlTaskId axl_task_pool_submit(AxlTaskPool *pool, AxlTaskProc proc, void *arg, AxlArena *arena, AxlTaskComplete on_complete)

Submit a task. Non-blocking.

On single-core, runs synchronously.

Parameters:
  • pool – task pool

  • 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(AxlTaskPool *pool)

Poll for completed tasks. Call once per event loop iteration.

Parameters:
  • pool – task pool

Returns:

number of tasks completed this poll cycle.

bool axl_task_pool_done(AxlTaskPool *pool, AxlTaskId id)

Check if a task is done.

Parameters:
  • pool – task pool

  • id – task ID

Returns:

true if task is done (or ID is invalid).

size_t axl_task_pool_available(AxlTaskPool *pool)

Get idle worker count.

Parameters:
  • pool – task pool

Returns:

number of idle workers.

size_t axl_task_pool_worker_count(AxlTaskPool *pool)

Get total worker count.

Parameters:
  • pool – task pool

Returns:

total worker count (0 on single-core).

bool axl_task_pool_is_single_core(AxlTaskPool *pool)

Check if the pool is in single-core fallback mode.

Parameters:
  • pool – task pool

Returns:

true if single-core (no APs available).

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 struct AxlLoop AxlLoop
typedef struct AxlAsync AxlAsync
typedef uint32_t AxlAsyncHandle

Functions

AxlAsync *axl_async_new(AxlLoop *loop, size_t max_pending)

Create a new async work queue.

Creates an internal task pool and slot array.

Parameters:
  • loop – event loop (idle source installed here)

  • max_pending – maximum concurrent async jobs

Returns:

async handle, or NULL on failure.

void axl_async_free(AxlAsync *async)

Free the async work queue. Drains pending work.

Parameters:
  • async – async handle (NULL-safe)

AxlAsyncHandle axl_async_submit(AxlAsync *async, 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:
  • async – async handle

  • 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(AxlAsync *async, AxlAsyncHandle handle)

Cancel pending async work (best-effort).

AP work continues to completion, but done_cb is suppressed.

Parameters:
  • async – async handle

  • handle – handle from axl_async_submit

Returns:

true if cancelled, false if handle invalid or already completed.

size_t axl_async_pending(AxlAsync *async)

Get the number of pending (in-flight) async jobs.

Parameters:
  • async – async handle

Returns:

number of jobs submitted but not yet completed.