pico_async_context

An async_context provides a logically single-threaded context for performing work, and responding to asynchronous events. Thus an async_context instance is suitable for servicing third-party libraries that are not re-entrant. More...

Modules

 async_context_freertos
 
 async_context_poll
 
 async_context_threadsafe_background
 

Data Structures

struct  async_work_on_timeout
 A "timeout" instance used by an async_context. More...
 
struct  async_when_pending_worker
 A "worker" instance used by an async_context. More...
 
struct  async_context_type
 Implementation of an async_context type, providing methods common to that type. More...
 
struct  async_context
 Base structure type of all async_contexts. For details about its use, see pico_async_context. More...
 

Typedefs

typedef struct async_work_on_timeout async_at_time_worker_t
 A "timeout" instance used by an async_context. More...
 
typedef struct async_when_pending_worker async_when_pending_worker_t
 A "worker" instance used by an async_context. More...
 
typedef struct async_context_type async_context_type_t
 Implementation of an async_context type, providing methods common to that type.
 

Functions

static void async_context_acquire_lock_blocking (async_context_t *context)
 Acquire the async_context lock. More...
 
static void async_context_release_lock (async_context_t *context)
 Release the async_context lock. More...
 
static void async_context_lock_check (async_context_t *context)
 Assert if the caller does not own the lock for the async_context. More...
 
static uint32_t async_context_execute_sync (async_context_t *context, uint32_t(*func)(void *param), void *param)
 Execute work synchronously on the core the async_context belongs to. More...
 
static bool async_context_add_at_time_worker (async_context_t *context, async_at_time_worker_t *worker)
 Add an "at time" worker to a context. More...
 
static bool async_context_add_at_time_worker_at (async_context_t *context, async_at_time_worker_t *worker, absolute_time_t at)
 Add an "at time" worker to a context. More...
 
static bool async_context_add_at_time_worker_in_ms (async_context_t *context, async_at_time_worker_t *worker, uint32_t ms)
 Add an "at time" worker to a context. More...
 
static bool async_context_remove_at_time_worker (async_context_t *context, async_at_time_worker_t *worker)
 Remove an "at time" worker from a context. More...
 
static bool async_context_add_when_pending_worker (async_context_t *context, async_when_pending_worker_t *worker)
 Add a "when pending" worker to a context. More...
 
static bool async_context_remove_when_pending_worker (async_context_t *context, async_when_pending_worker_t *worker)
 Remove a "when pending" worker from a context. More...
 
static void async_context_set_work_pending (async_context_t *context, async_when_pending_worker_t *worker)
 Mark a "when pending" worker as having work pending. More...
 
static void async_context_poll (async_context_t *context)
 Perform any pending work for polling style async_context. More...
 
static void async_context_wait_until (async_context_t *context, absolute_time_t until)
 sleep until the specified time in an async_context callback safe way More...
 
static void async_context_wait_for_work_until (async_context_t *context, absolute_time_t until)
 Block until work needs to be done or the specified time has been reached. More...
 
static void async_context_wait_for_work_ms (async_context_t *context, uint32_t ms)
 Block until work needs to be done or the specified number of milliseconds have passed. More...
 
static uint async_context_core_num (const async_context_t *context)
 Return the processor core this async_context belongs to. More...
 
static void async_context_deinit (async_context_t *context)
 End async_context processing, and free any resources. More...
 

Detailed Description

An async_context provides a logically single-threaded context for performing work, and responding to asynchronous events. Thus an async_context instance is suitable for servicing third-party libraries that are not re-entrant.

The "context" in async_context refers to the fact that when calling workers or timeouts within the async_context various pre-conditions hold:

  1. That there is a single logical thread of execution; i.e. that the context does not call any worker functions concurrently.
  2. That the context always calls workers from the same processor core, as most uses of async_context rely on interaction with IRQs which are themselves core-specific.

THe async_context provides two mechanisms for asynchronous work:

Note: "when pending" workers with work pending are executed before "at time" workers.

The async_context provides locking mechanisms, see async_context_acquire_lock_blocking, async_context_release_lock and async_context_check_lock which can be used by external code to ensure execution of external code does not happen concurrently with worker code. Locked code runs on the calling core, however async_context_execute_sync is provided to synchronously run a function from the core of the async_context.

The SDK ships with the following default async_contexts:

async_context_poll - this context is not thread-safe, and the user is responsible for calling async_context_poll() periodically, and can use async_context_wait_for_work_until() to sleep between calls until work is needed if the user has nothing else to do.

async_context_threadsafe_background - in order to work in the background, a low priority IRQ is used to handle callbacks. Code is usually invoked from this IRQ context, but may be invoked after any other code that uses the async context in another (non-IRQ) context on the same core. Calling async_context_poll() is not required, and is a no-op. This context implements async_context locking and is thus safe to call from either core, according to the specific notes on each API.

async_context_freertos - Work is performed from a separate "async_context" task, however once again, code may also be invoked after a direct use of the async_context on the same core that the async_context belongs to. Calling async_context_poll() is not required, and is a no-op. This context implements async_context locking and is thus safe to call from any task, and from either core, according to the specific notes on each API.

Each async_context provides bespoke methods of instantiation which are provided in the corresponding headers (e.g. async_context_poll.h, async_context_threadsafe_background.h, asycn_context_freertos.h). async_contexts are de-initialized by the common async_context_deint() method.

Multiple async_context instances can be used by a single application, and they will operate independently.

Typedef Documentation

◆ async_at_time_worker_t

A "timeout" instance used by an async_context.

A "timeout" represents some future action that must be taken at a specific time. It's methods are called from the async_context under lock at the given time

See also
async_context_add_worker_at
async_context_add_worker_in_ms

◆ async_when_pending_worker_t

A "worker" instance used by an async_context.

A "worker" represents some external entity that must do work in response to some external stimulus (usually an IRQ). It's methods are called from the async_context under lock at the given time

See also
async_context_add_worker_at
async_context_add_worker_in_ms

Function Documentation

◆ async_context_acquire_lock_blocking()

static void async_context_acquire_lock_blocking ( async_context_t context)
inlinestatic

Acquire the async_context lock.

The owner of the async_context lock is the logic owner of the async_context and other work related to this async_context will not happen concurrently.

This method may be called in a nested fashion by the the lock owner.

Note
the async_context lock is nestable by the same caller, so an internal count is maintained
for async_contexts that provide locking (not async_context_poll), this method is threadsafe. and may be called from within any worker method called by the async_context or from any other non-IRQ context.
Parameters
contextthe async_context
See also
async_context_release_lock

◆ async_context_add_at_time_worker()

static bool async_context_add_at_time_worker ( async_context_t context,
async_at_time_worker_t worker 
)
inlinestatic

Add an "at time" worker to a context.

An "at time" worker will run at or after a specific point in time, and is automatically when (just before) it runs.

The time to fire is specified in the next_time field of the worker.

Note
for async_contexts that provide locking (not async_context_poll), this method is threadsafe. and may be called from within any worker method called by the async_context or from any other non-IRQ context.
Parameters
contextthe async_context
workerthe "at time" worker to add
Returns
true if the worker was added, false if the worker was already present.

◆ async_context_add_at_time_worker_at()

static bool async_context_add_at_time_worker_at ( async_context_t context,
async_at_time_worker_t worker,
absolute_time_t  at 
)
inlinestatic

Add an "at time" worker to a context.

An "at time" worker will run at or after a specific point in time, and is automatically when (just before) it runs.

The time to fire is specified by the at parameter.

Note
for async_contexts that provide locking (not async_context_poll), this method is threadsafe. and may be called from within any worker method called by the async_context or from any other non-IRQ context.
Parameters
contextthe async_context
workerthe "at time" worker to add
atthe time to fire at
Returns
true if the worker was added, false if the worker was already present.

◆ async_context_add_at_time_worker_in_ms()

static bool async_context_add_at_time_worker_in_ms ( async_context_t context,
async_at_time_worker_t worker,
uint32_t  ms 
)
inlinestatic

Add an "at time" worker to a context.

An "at time" worker will run at or after a specific point in time, and is automatically when (just before) it runs.

The time to fire is specified by a delay via the ms parameter

Note
for async_contexts that provide locking (not async_context_poll), this method is threadsafe. and may be called from within any worker method called by the async_context or from any other non-IRQ context.
Parameters
contextthe async_context
workerthe "at time" worker to add
msthe number of milliseconds from now to fire after
Returns
true if the worker was added, false if the worker was already present.

◆ async_context_add_when_pending_worker()

static bool async_context_add_when_pending_worker ( async_context_t context,
async_when_pending_worker_t worker 
)
inlinestatic

Add a "when pending" worker to a context.

An "when pending" worker will run when it is pending (can be set via async_context_set_work_pending), and is NOT automatically removed when it runs.

The time to fire is specified by a delay via the ms parameter

Note
for async_contexts that provide locking (not async_context_poll), this method is threadsafe. and may be called from within any worker method called by the async_context or from any other non-IRQ context.
Parameters
contextthe async_context
workerthe "when pending" worker to add
Returns
true if the worker was added, false if the worker was already present.

◆ async_context_core_num()

static uint async_context_core_num ( const async_context_t context)
inlinestatic

Return the processor core this async_context belongs to.

Parameters
contextthe async_context
Returns
the physical core number

◆ async_context_deinit()

static void async_context_deinit ( async_context_t context)
inlinestatic

End async_context processing, and free any resources.

Note the user should clean up any resources associated with workers in the async_context themselves.

Asynchronous (non-polled) async_contexts guarantee that no callback is being called once this method returns.

Parameters
contextthe async_context
Returns
the physical core number

◆ async_context_execute_sync()

static uint32_t async_context_execute_sync ( async_context_t context,
uint32_t(*)(void *param)  func,
void *  param 
)
inlinestatic

Execute work synchronously on the core the async_context belongs to.

This method is intended for code external to the async_context (e.g. another thread/task) to execute a function with the same guarantees (single core, logical thread of execution) that async_context workers are called with.

Note
you should NOT call this method while holding the async_context's lock
Parameters
contextthe async_context
functhe function to call
parmthe paramter to pass to the function
Returns
the return value from func

◆ async_context_lock_check()

static void async_context_lock_check ( async_context_t context)
inlinestatic

Assert if the caller does not own the lock for the async_context.

Note
this method is thread-safe
Parameters
contextthe async_context

◆ async_context_poll()

static void async_context_poll ( async_context_t context)
inlinestatic

Perform any pending work for polling style async_context.

For a polled async_context (e.g. async_context_poll) the user is responsible for calling this method periodically to perform any required work.

This method may immediately perform outstanding work on other context types, but is not required to.

Parameters
contextthe async_context

◆ async_context_release_lock()

static void async_context_release_lock ( async_context_t context)
inlinestatic

Release the async_context lock.

Note
the async_context lock may be called in a nested fashion, so an internal count is maintained. On the outermost release, When the outermost lock is released, a check is made for work which might have been skipped while the lock was held, and any such work may be performed during this call IF the call is made from the same core that the async_context belongs to.
for async_contexts that provide locking (not async_context_poll), this method is threadsafe. and may be called from within any worker method called by the async_context or from any other non-IRQ context.
Parameters
contextthe async_context
See also
async_context_acquire_lock_blocking

◆ async_context_remove_at_time_worker()

static bool async_context_remove_at_time_worker ( async_context_t context,
async_at_time_worker_t worker 
)
inlinestatic

Remove an "at time" worker from a context.

Note
for async_contexts that provide locking (not async_context_poll), this method is threadsafe. and may be called from within any worker method called by the async_context or from any other non-IRQ context.
Parameters
contextthe async_context
workerthe "at time" worker to remove
Returns
true if the worker was removed, false if the instance not present.

◆ async_context_remove_when_pending_worker()

static bool async_context_remove_when_pending_worker ( async_context_t context,
async_when_pending_worker_t worker 
)
inlinestatic

Remove a "when pending" worker from a context.

Note
for async_contexts that provide locking (not async_context_poll), this method is threadsafe. and may be called from within any worker method called by the async_context or from any other non-IRQ context.
Parameters
contextthe async_context
workerthe "when pending" worker to remove
Returns
true if the worker was removed, false if the instance not present.

◆ async_context_set_work_pending()

static void async_context_set_work_pending ( async_context_t context,
async_when_pending_worker_t worker 
)
inlinestatic

Mark a "when pending" worker as having work pending.

The worker will be run from the async_context at a later time.

Note
this method may be called from any context including IRQs
Parameters
contextthe async_context
workerthe "when pending" worker to mark as pending.

◆ async_context_wait_for_work_ms()

static void async_context_wait_for_work_ms ( async_context_t context,
uint32_t  ms 
)
inlinestatic

Block until work needs to be done or the specified number of milliseconds have passed.

Note
this method should not be called from a worker callback
Parameters
contextthe async_context
msthe number of milliseconds to return after if no work is required

◆ async_context_wait_for_work_until()

static void async_context_wait_for_work_until ( async_context_t context,
absolute_time_t  until 
)
inlinestatic

Block until work needs to be done or the specified time has been reached.

Note
this method should not be called from a worker callback
Parameters
contextthe async_context
untilthe time to return at if no work is required

◆ async_context_wait_until()

static void async_context_wait_until ( async_context_t context,
absolute_time_t  until 
)
inlinestatic

sleep until the specified time in an async_context callback safe way

Note
for async_contexts that provide locking (not async_context_poll), this method is threadsafe. and may be called from within any worker method called by the async_context or from any other non-IRQ context.
Parameters
contextthe async_context
untilthe time to sleep until