Quick Start

This guide provides small snippets on how to use poco.

The activities generally fall into the following steps.

  1. Pick and initialise a scheduler.

  2. Create tasks.

  3. Run the scheduler in the main loop.

poco can be included either as a single header or as individual components. The examples provided as part of this library showcase both styles.

Picking a Scheduler

The scheduler determines which coroutine is run at each context switch. Every coroutine is run within the context of a scheduler.

Coroutine/Task Creation

Tasks are the execution units within poco. You can group the program’s activities in the form of a coroutine and the poco scheduler will run in along side all other defined coroutines.

A sample task function.
void producer_task(void *context) {
    Queue *queue = context;
    for (int i = 0; i < 3; ++i) {
        queue_put(queue, &i, PLATFORM_TICKS_FOREVER);
        printf("Put %d\n", i);
        coro_yield_delay(1000);
    }
    int const sentinel = CONSUMER_STOP;
    queue_put(queue, &sentinel, PLATFORM_TICKS_FOREVER);
    printf("Put %d\n", sentinel);
}

Once the function has been defined, it can be attached to a coroutine via coro_create().

if (producer_handle == NULL) {
    /* Memory error */

To pause a coroutine, simply yield control back to the scheduler using the provided yield commands. As this is a coroutine library, yielding back to the scheduler is under control by the developer (with the exception of communication primitives).

Note

The frequency and duration between yields directly effects the responsiveness of the program. It is best to yield often to ensure the best responsiveness.

poco’s built-in communication primitives also perform yields, such as when putting items in a queue.

If coroutines need to be sequential, :cpp:func`coro_join` can be used to ensure a particular coroutine runs after another.

Scheduler

TODO

Running

TODO