|
PebbleOS v4.45.0-223-gf3212a729
|
Run functions on a kernel thread, deferred from interrupts or other threads. More...
Data Structures | |
| struct | pbl_work |
| Work item. More... | |
| struct | pbl_delayed_work |
| Work item submitted after a delay. More... | |
| struct | pbl_wallclock_work |
| Work item submitted at wall clock boundaries. More... | |
| struct | pbl_workq_ops |
| Optional hooks run on a queue's thread. More... | |
| struct | pbl_workq |
| Work queue. More... | |
| struct | pbl_work_pool |
| Slots for pbl_work_call(). More... | |
Macros | |
| #define | PBL_WORK_INITIALIZER(_fn) {.fn = (_fn)} |
| Static initializer for a work item. | |
| #define | PBL_WORK_DEFINE(name, fn) struct pbl_work name = PBL_WORK_INITIALIZER(fn) |
| Define a work item, usable without pbl_work_init(). | |
| #define | PBL_DELAYED_WORK_INITIALIZER(_fn) |
| Static initializer for a delayed work item. | |
| #define | PBL_DELAYED_WORK_DEFINE(name, fn) struct pbl_delayed_work name = PBL_DELAYED_WORK_INITIALIZER(fn) |
| Define a delayed work item, usable without pbl_delayed_work_init(). | |
| #define | PBL_WORKQ_INITIALIZER {.wake = PBL_SEM_INITIALIZER(0, 1)} |
| Static initializer for a work queue. | |
| #define | PBL_WORKQ_DEFINE(name) struct pbl_workq name = PBL_WORKQ_INITIALIZER |
| Define a work queue, usable without pbl_workq_init(). | |
| #define | PBL_WORK_POOL_DEFINE(name, n) |
| Define a pool for pbl_work_call(), usable without pbl_work_pool_init(). | |
Typedefs | |
| typedef void(* | pbl_work_fn_t) (struct pbl_work *work) |
| Work function, run on the queue's thread. | |
| typedef void(* | pbl_work_call_fn_t) (void *data) |
| Function run by pbl_work_call(). | |
Functions | |
| void | pbl_workq_init (struct pbl_workq *q) |
| Initialize a work queue in dynamically allocated memory. | |
| void | pbl_workq_set_ops (struct pbl_workq *q, const struct pbl_workq_ops *ops) |
| Set the hooks of a queue, which take effect once it is next idle. | |
| void | pbl_workq_thread (void *arg) |
| Thread entry serving a queue, with the queue as its argument. | |
| void | pbl_workq_flush (struct pbl_workq *q) |
| Wait until everything submitted so far has run. | |
| struct pbl_thread * | pbl_workq_get_thread (const struct pbl_workq *q) |
| Get the thread serving a queue. | |
| bool | pbl_workq_is_current (const struct pbl_workq *q) |
| Check whether the caller runs on a queue's thread. | |
| void * | pbl_workq_current_fn (const struct pbl_workq *q) |
| Get the function being run, for debugging. | |
| void | pbl_work_init (struct pbl_work *work, pbl_work_fn_t fn) |
| Initialize a work item. | |
| bool | pbl_work_submit (struct pbl_workq *q, struct pbl_work *work) |
| Queue a work item. | |
| void | pbl_workq_set_boost_prio (struct pbl_workq *q, pbl_prio_t prio) |
| Set the priority a queue's thread runs at while it has boosted work. | |
| bool | pbl_work_submit_boosted (struct pbl_workq *q, struct pbl_work *work) |
| Queue a work item that raises its queue's priority until it has run. | |
| bool | pbl_work_cancel (struct pbl_work *work) |
| Remove a work item from its queue, without waiting for it if it is running. | |
| bool | pbl_work_cancel_sync (struct pbl_work *work) |
| Remove a work item from its queue and wait for it to finish running. | |
| bool | pbl_work_flush (struct pbl_work *work) |
| Wait for a work item to finish its last submission. | |
| bool | pbl_work_is_pending (const struct pbl_work *work) |
| Check whether a work item is queued. | |
| bool | pbl_work_is_running (const struct pbl_work *work) |
| Check whether a work item's function is running. | |
| void | pbl_delayed_work_init (struct pbl_delayed_work *dwork, pbl_work_fn_t fn) |
| Initialize a delayed work item. | |
| bool | pbl_delayed_work_schedule (struct pbl_workq *q, struct pbl_delayed_work *dwork, pbl_timeout_t delay) |
| Queue a delayed work item after a delay, unless it is already pending. | |
| bool | pbl_delayed_work_reschedule (struct pbl_workq *q, struct pbl_delayed_work *dwork, pbl_timeout_t delay) |
| Queue a delayed work item after a delay, replacing any pending delay. | |
| void | pbl_delayed_work_schedule_next (struct pbl_delayed_work *dwork, pbl_tick_t period) |
| Queue a delayed work item one period after its last expiry, so it does not drift. | |
| bool | pbl_delayed_work_cancel (struct pbl_delayed_work *dwork) |
| Stop a delayed work item, without waiting for it if it is running. | |
| bool | pbl_delayed_work_cancel_sync (struct pbl_delayed_work *dwork) |
| Stop a delayed work item and wait for it to finish running. | |
| bool | pbl_delayed_work_is_pending (const struct pbl_delayed_work *dwork) |
| Check whether a delayed work item is pending. | |
| pbl_tick_t | pbl_delayed_work_remaining (const struct pbl_delayed_work *dwork) |
| Get the time left on a delayed work item. | |
| void | pbl_work_pool_init (struct pbl_work_pool *pool, struct pbl_work_call *slots, size_t num_slots) |
| Initialize a pool in dynamically allocated memory. | |
| size_t | pbl_work_pool_num_free (const struct pbl_work_pool *pool) |
| Get the free slots of a pool. | |
| int | pbl_work_call (struct pbl_workq *q, struct pbl_work_pool *pool, pbl_work_call_fn_t fn, void *data, pbl_timeout_t timeout) |
| Run a function with a payload on a queue. | |
| void | pbl_wallclock_work_init (struct pbl_wallclock_work *w, pbl_work_fn_t fn) |
| Initialize a wall clock work item. | |
| void | pbl_wallclock_work_start (struct pbl_workq *q, struct pbl_wallclock_work *w, uint32_t unit_s, uint32_t every) |
Queue a work item at every every -th boundary of the wall clock's unit_s seconds. | |
| bool | pbl_wallclock_work_stop (struct pbl_wallclock_work *w) |
| Stop a wall clock work item, and remove it from its queue if it is pending. | |
| bool | pbl_wallclock_work_is_running (const struct pbl_wallclock_work *w) |
| Check whether a wall clock work item is started. | |
| bool | pbl_sys_work_call (pbl_work_call_fn_t fn, void *data) |
| Run a function with a payload on pbl_sys_workq. | |
| bool | pbl_sys_work_call_from_isr (pbl_work_call_fn_t fn, void *data) |
| Like pbl_sys_work_call(), from an ISR: stops the system at once if no slot is free. | |
| bool | pbl_sys_work_try_call (pbl_work_call_fn_t fn, void *data) |
| Like pbl_sys_work_call(), but never waits nor stops the system. | |
| bool | pbl_sys_work_call_high (pbl_work_call_fn_t fn, void *data) |
| Run a short, time sensitive function with a payload on pbl_sys_workq_high. | |
| void | pbl_sys_work_call_high_from_isr (pbl_work_call_fn_t fn, void *data) |
| Like pbl_sys_work_call_high(), from an ISR: the call is dropped if no slot is free. | |
| void | pbl_sys_work_block (bool block) |
| Refuse new calls to pbl_sys_workq, e.g. | |
| size_t | pbl_sys_work_num_free (void) |
| Get how many calls the caller can make to pbl_sys_workq without waiting. | |
| void * | pbl_sys_work_current_fn (void) |
| Get the function running on pbl_sys_workq, for debugging. | |
Variables | |
| struct pbl_workq | pbl_sys_workq |
| Queue for background work, which may block and take a while. | |
| struct pbl_workq | pbl_sys_workq_high |
| Queue for short, time sensitive work, at the highest thread priority. | |
Run functions on a kernel thread, deferred from interrupts or other threads.
A work item is a caller-owned struct, usually embedded in the object it acts on. Submitting allocates nothing and cannot fail: an item is queued at most once, so submitting a pending item does nothing, and its function runs once for any number of submits. Items run one at a time in submission order. An item may be resubmitted or freed by its own function.
Delayed work adds a timer in front of the queue. Payloads that cannot share one item go through pbl_work_call(), which takes its slots from a bounded pool.
The kernel provides pbl_sys_workq for background work and pbl_sys_workq_high for short, time sensitive work.
Everything may be called from an ISR except where noted.
| struct pbl_work |
Work item.
| Data Fields | ||
|---|---|---|
| pbl_work_fn_t | fn | Function. |
| struct pbl_delayed_work |
Work item submitted after a delay.
| Data Fields | ||
|---|---|---|
| struct pbl_work | work | Work item, passed to the function. |
| struct pbl_wallclock_work |
Work item submitted at wall clock boundaries.
| Data Fields | ||
|---|---|---|
| struct pbl_work | work | Work item, passed to the function. |
| struct pbl_workq |
Work queue.
| struct pbl_work_pool |
Slots for pbl_work_call().
| #define PBL_DELAYED_WORK_DEFINE | ( | name, | |
| fn | |||
| ) | struct pbl_delayed_work name = PBL_DELAYED_WORK_INITIALIZER(fn) |
Define a delayed work item, usable without pbl_delayed_work_init().
| name | Name of the variable. |
| fn | Function. |
| #define PBL_DELAYED_WORK_INITIALIZER | ( | _fn | ) |
Static initializer for a delayed work item.
| _fn | Function. |
| #define PBL_WORK_DEFINE | ( | name, | |
| fn | |||
| ) | struct pbl_work name = PBL_WORK_INITIALIZER(fn) |
Define a work item, usable without pbl_work_init().
| name | Name of the variable. |
| fn | Function. |
| #define PBL_WORK_INITIALIZER | ( | _fn | ) | {.fn = (_fn)} |
Static initializer for a work item.
| _fn | Function. |
| #define PBL_WORK_POOL_DEFINE | ( | name, | |
| n | |||
| ) |
Define a pool for pbl_work_call(), usable without pbl_work_pool_init().
| name | Name of the variable. |
| n | Number of calls that can be pending at once. |
| #define PBL_WORKQ_DEFINE | ( | name | ) | struct pbl_workq name = PBL_WORKQ_INITIALIZER |
Define a work queue, usable without pbl_workq_init().
| name | Name of the variable. |
| #define PBL_WORKQ_INITIALIZER {.wake = PBL_SEM_INITIALIZER(0, 1)} |
Static initializer for a work queue.
| typedef void(* pbl_work_call_fn_t) (void *data) |
Function run by pbl_work_call().
| typedef void(* pbl_work_fn_t) (struct pbl_work *work) |
Work function, run on the queue's thread.
| bool pbl_delayed_work_cancel | ( | struct pbl_delayed_work * | dwork | ) |
Stop a delayed work item, without waiting for it if it is running.
| dwork | Delayed work item. |
| bool pbl_delayed_work_cancel_sync | ( | struct pbl_delayed_work * | dwork | ) |
Stop a delayed work item and wait for it to finish running.
Thread context only.
Holds against an item that schedules itself again from its function.
| dwork | Delayed work item. |
| void pbl_delayed_work_init | ( | struct pbl_delayed_work * | dwork, |
| pbl_work_fn_t | fn | ||
| ) |
Initialize a delayed work item.
| [out] | dwork | Delayed work item. |
| fn | Function. |
| bool pbl_delayed_work_is_pending | ( | const struct pbl_delayed_work * | dwork | ) |
Check whether a delayed work item is pending.
| dwork | Delayed work item. |
| pbl_tick_t pbl_delayed_work_remaining | ( | const struct pbl_delayed_work * | dwork | ) |
Get the time left on a delayed work item.
| dwork | Delayed work item. |
| bool pbl_delayed_work_reschedule | ( | struct pbl_workq * | q, |
| struct pbl_delayed_work * | dwork, | ||
| pbl_timeout_t | delay | ||
| ) |
Queue a delayed work item after a delay, replacing any pending delay.
| q | Queue. |
| dwork | Delayed work item. |
| delay | Delay, PBL_NO_WAIT to queue now; must not be PBL_FOREVER. |
| bool pbl_delayed_work_schedule | ( | struct pbl_workq * | q, |
| struct pbl_delayed_work * | dwork, | ||
| pbl_timeout_t | delay | ||
| ) |
Queue a delayed work item after a delay, unless it is already pending.
| q | Queue. |
| dwork | Delayed work item. |
| delay | Delay, PBL_NO_WAIT to queue now; must not be PBL_FOREVER. |
| void pbl_delayed_work_schedule_next | ( | struct pbl_delayed_work * | dwork, |
| pbl_tick_t | period | ||
| ) |
Queue a delayed work item one period after its last expiry, so it does not drift.
For a periodic item, from its own function. When that time has passed, the item is queued on the next tick and later periods count from there, so missed periods do not pile up.
| dwork | Delayed work item, which must have been scheduled before. |
| period | Ticks since its last expiry. |
| void pbl_sys_work_block | ( | bool | block | ) |
Refuse new calls to pbl_sys_workq, e.g.
while the system shuts down.
| block | true to refuse them, false to accept them again. |
| bool pbl_sys_work_call | ( | pbl_work_call_fn_t | fn, |
| void * | data | ||
| ) |
Run a function with a payload on pbl_sys_workq.
For work that cannot embed a work item. Thread context only. A thread with its own slots, see pbl_thread_attr, waits for one; the queue's own thread puts what does not fit on the heap; any other thread waits a while, then stops the system, as a queue that stays full is stuck.
| fn | Function. |
| data | Argument of fn. |
| bool pbl_sys_work_call_from_isr | ( | pbl_work_call_fn_t | fn, |
| void * | data | ||
| ) |
Like pbl_sys_work_call(), from an ISR: stops the system at once if no slot is free.
| fn | Function. |
| data | Argument of fn. |
| bool pbl_sys_work_call_high | ( | pbl_work_call_fn_t | fn, |
| void * | data | ||
| ) |
Run a short, time sensitive function with a payload on pbl_sys_workq_high.
Thread context only; waits a little for a free slot.
| fn | Function. |
| data | Argument of fn. |
| void pbl_sys_work_call_high_from_isr | ( | pbl_work_call_fn_t | fn, |
| void * | data | ||
| ) |
Like pbl_sys_work_call_high(), from an ISR: the call is dropped if no slot is free.
| fn | Function. |
| data | Argument of fn. |
| void * pbl_sys_work_current_fn | ( | void | ) |
Get the function running on pbl_sys_workq, for debugging.
| size_t pbl_sys_work_num_free | ( | void | ) |
Get how many calls the caller can make to pbl_sys_workq without waiting.
| bool pbl_sys_work_try_call | ( | pbl_work_call_fn_t | fn, |
| void * | data | ||
| ) |
Like pbl_sys_work_call(), but never waits nor stops the system.
Callable from an ISR.
| fn | Function. |
| data | Argument of fn. |
| void pbl_wallclock_work_init | ( | struct pbl_wallclock_work * | w, |
| pbl_work_fn_t | fn | ||
| ) |
Initialize a wall clock work item.
| [out] | w | Wall clock work item. |
| fn | Function, whose argument is &w->work. |
| bool pbl_wallclock_work_is_running | ( | const struct pbl_wallclock_work * | w | ) |
Check whether a wall clock work item is started.
| w | Wall clock work item. |
| void pbl_wallclock_work_start | ( | struct pbl_workq * | q, |
| struct pbl_wallclock_work * | w, | ||
| uint32_t | unit_s, | ||
| uint32_t | every | ||
| ) |
Queue a work item at every every -th boundary of the wall clock's unit_s seconds.
E.g. every minute, as the wall clock's minute changes, or every 5 seconds, as its second does. The first is every boundaries from now. Items due at the same boundary expire together, so they wake the system once.
Setting the clock moves the boundaries with it. A change that lands in another unit counts as one boundary, so a minute item runs at once when the clock moves to another minute. Starting a running item restarts it.
| q | Queue. |
| w | Wall clock work item. |
| unit_s | Unit in seconds, e.g. 1 or 60. |
| every | Number of boundaries between runs. |
| bool pbl_wallclock_work_stop | ( | struct pbl_wallclock_work * | w | ) |
Stop a wall clock work item, and remove it from its queue if it is pending.
Does not wait for a function that is running.
| w | Wall clock work item. |
| int pbl_work_call | ( | struct pbl_workq * | q, |
| struct pbl_work_pool * | pool, | ||
| pbl_work_call_fn_t | fn, | ||
| void * | data, | ||
| pbl_timeout_t | timeout | ||
| ) |
Run a function with a payload on a queue.
For work that cannot share a work item because several payloads may be pending at once; prefer a work item otherwise. The slot is released before fn runs, so fn may queue another call.
The queue's own thread never waits, as only it can release the slots of its queue's calls.
| q | Queue. |
| pool | Pool to take the slot from. |
| fn | Function. |
| data | Argument of fn. |
| timeout | How long to wait for a free slot; must be PBL_NO_WAIT in an ISR. |
| bool pbl_work_cancel | ( | struct pbl_work * | work | ) |
Remove a work item from its queue, without waiting for it if it is running.
| work | Work item. |
| bool pbl_work_cancel_sync | ( | struct pbl_work * | work | ) |
Remove a work item from its queue and wait for it to finish running.
Thread context only.
On return the function is not running, unless called by the item itself, and will not run unless submitted again.
| work | Work item. |
| bool pbl_work_flush | ( | struct pbl_work * | work | ) |
Wait for a work item to finish its last submission.
Thread context only.
Must not be called from the thread of the item's queue.
| work | Work item. |
| void pbl_work_init | ( | struct pbl_work * | work, |
| pbl_work_fn_t | fn | ||
| ) |
Initialize a work item.
| [out] | work | Work item. |
| fn | Function. |
| bool pbl_work_is_pending | ( | const struct pbl_work * | work | ) |
Check whether a work item is queued.
| work | Work item. |
| bool pbl_work_is_running | ( | const struct pbl_work * | work | ) |
Check whether a work item's function is running.
| work | Work item. |
| void pbl_work_pool_init | ( | struct pbl_work_pool * | pool, |
| struct pbl_work_call * | slots, | ||
| size_t | num_slots | ||
| ) |
Initialize a pool in dynamically allocated memory.
| [out] | pool | Pool. |
| slots | Storage for the slots, which must outlive the pool. | |
| num_slots | Number of calls that can be pending at once. |
| size_t pbl_work_pool_num_free | ( | const struct pbl_work_pool * | pool | ) |
Get the free slots of a pool.
| pool | Pool. |
Queue a work item.
| q | Queue. |
| work | Work item. |
Queue a work item that raises its queue's priority until it has run.
For latency sensitive work on a low priority queue, such as reading a device after its interrupt. The queue's thread runs at the priority set with pbl_workq_set_boost_prio() from now until the function returns or the item is canceled, together with any other boosted item. Submitting an item that is already pending boosts it.
| q | Queue. |
| work | Work item. |
| void * pbl_workq_current_fn | ( | const struct pbl_workq * | q | ) |
Get the function being run, for debugging.
| q | Queue. |
| void pbl_workq_flush | ( | struct pbl_workq * | q | ) |
Wait until everything submitted so far has run.
Thread context only.
Must not be called from the queue's own thread.
| q | Queue. |
| struct pbl_thread * pbl_workq_get_thread | ( | const struct pbl_workq * | q | ) |
Get the thread serving a queue.
| q | Queue. |
| void pbl_workq_init | ( | struct pbl_workq * | q | ) |
Initialize a work queue in dynamically allocated memory.
| [out] | q | Queue. |
| bool pbl_workq_is_current | ( | const struct pbl_workq * | q | ) |
Check whether the caller runs on a queue's thread.
| q | Queue. |
| void pbl_workq_set_boost_prio | ( | struct pbl_workq * | q, |
| pbl_prio_t | prio | ||
| ) |
Set the priority a queue's thread runs at while it has boosted work.
| q | Queue. |
| prio | Priority, above the thread's own for the boost to have an effect. |
| void pbl_workq_set_ops | ( | struct pbl_workq * | q, |
| const struct pbl_workq_ops * | ops | ||
| ) |
Set the hooks of a queue, which take effect once it is next idle.
| q | Queue. |
| ops | Hooks, which must outlive the queue. |
| void pbl_workq_thread | ( | void * | arg | ) |
Thread entry serving a queue, with the queue as its argument.
For queues other than the system ones, which the kernel starts at boot. The caller creates the thread, which picks the queue's priority and stack. Work may be submitted before it starts.
| arg | Queue. |
|
extern |
Queue for background work, which may block and take a while.
|
extern |
Queue for short, time sensitive work, at the highest thread priority.