v2.0.0
Modules | Data Structures | Typedefs | Functions
pico_async_context
High Level APIs

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_freertos provides an implementation of async_context that handles asynchronous work in a separate FreeRTOS task.
| async_context_poll
| async_context_poll provides an implementation of async_context that is intended for use with a simple polling loop on one core. It is not thread safe.
| async_context_threadsafe_background
| async_context_threadsafe_background provides an implementation of async_context that handles asynchronous work in a low priority IRQ, and there is no need for the user to poll for work

## 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:

- when_pending workers, which are processed whenever they have work pending. See async_context_add_when_pending_worker, async_context_remove_when_pending_worker, and async_context_set_work_pending, the latter of which can be used from an interrupt handler to signal that servicing work is required to be performed by the worker from the regular async_context.
- at_time workers, that are executed after at a specific time.

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_lock_check 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

typedef struct async_work_on_timeout 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. Its 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

typedef struct async_when_pending_worker 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). Its 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

  context | the 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

  context | the async_context
  worker | the "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

  context | the async_context
  worker | the "at time" worker to add
  at | the 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

  context | the async_context
  worker | the "at time" worker to add
  ms | the 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

  context | the async_context
  worker | the "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

  context | the 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

  context | the async_context

## ◆ 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

  context | the async_context
  func | the function to call
  param | the parameter 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

  context | the 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

  context | the 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

  context | the 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

  context | the async_context
  worker | the "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

  context | the async_context
  worker | the "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

  context | the async_context
  worker | the "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

  context | the async_context
  ms | the 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

  context | the async_context
  until | the 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

  context | the async_context
  until | the time to sleep until