Skip to content

Commit

Permalink
kernel: Introduce k_work_poll
Browse files Browse the repository at this point in the history
This commit adds new k_work_poll interface. It allows to
submit given work to a workqueue automatically when one of the
watched pollable objects changes its state.

Signed-off-by: Piotr Zięcik <piotr.ziecik@nordicsemi.no>
Signed-off-by: Peter A. Bigot <pab@pabigot.com>
  • Loading branch information
pizi-nordic authored and carlescufi committed Oct 4, 2019
1 parent 1c4177d commit 19d8349
Show file tree
Hide file tree
Showing 9 changed files with 1,042 additions and 53 deletions.
35 changes: 35 additions & 0 deletions doc/reference/kernel/threads/workqueue.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,41 @@ queue, unless the work item has already been removed and processed by the
workqueue's thread. Consequently, once a work item's timeout has expired
the work item is always processed by the workqueue and cannot be canceled.

Triggered Work
**************

The :cpp:func:`k_work_poll_submit()` interface schedules a triggered work
item in response to a **poll event** (see :ref:`polling_v2`), that will
call a user-defined function when a monitored resource becomes available
or poll signal is raised, or a timeout occurs.
In contrast to :cpp:func:`k_poll()`, the triggered work does not require
a dedicated thread waiting or actively polling for a poll event.

A triggered work item is a standard work item that has the following
added properties:

* A pointer to an array of poll events that will trigger work item
submissions to the workqueue

* A size of the array containing poll events.

A triggered work item is initialized and submitted to a workqueue in a similar
manner to a standard work item, although dedicated kernel APIs are used.
When a submit request is made, the kernel begins observing kernel objects
specified by the poll events. Once at least one of the observed kernel
object's changes state, the work item is submitted to the specified workqueue,
where it remains pending until it is processed in the standard manner.

.. important::
The triggered work item as well as the referenced array of poll events
have to be valid and cannot be modified for a complete triggered work
item lifecycle, from submission to work item execution or cancellation.

An ISR or a thread may **cancel** a triggered work item it has submitted
as long as it is still waiting for a poll event. In such case, the kernel
stops waiting for attached poll events and the specified work is not executed.
Otherwise the cancellation cannot be performed.

System Workqueue
*****************

Expand Down
123 changes: 122 additions & 1 deletion include/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -2681,8 +2681,9 @@ __syscall int k_stack_pop(struct k_stack *stack, stack_data_t *data, s32_t timeo
/** @} */

struct k_work;
struct k_work_poll;

/* private, used by k_poll */
/* private, used by k_poll and k_work_poll */
typedef int (*_poller_cb_t)(struct k_poll_event *event, u32_t state);
struct _poller {
volatile bool is_polling;
Expand Down Expand Up @@ -2734,6 +2735,16 @@ struct k_delayed_work {
struct k_work_q *work_q;
};

struct k_work_poll {
struct k_work work;
struct _poller poller;
struct k_poll_event *events;
int num_events;
k_work_handler_t real_handler;
struct _timeout timeout;
int poll_result;
};

extern struct k_work_q k_sys_work_q;

/**
Expand Down Expand Up @@ -3066,6 +3077,116 @@ static inline s32_t k_delayed_work_remaining_get(struct k_delayed_work *work)
return __ticks_to_ms(z_timeout_remaining(&work->timeout));
}

/**
* @brief Initialize a triggered work item.
*
* This routine initializes a workqueue triggered work item, prior to
* its first use.
*
* @param work Address of triggered work item.
* @param handler Function to invoke each time work item is processed.
*
* @return N/A
*/
extern void k_work_poll_init(struct k_work_poll *work,
k_work_handler_t handler);

/**
* @brief Submit a triggered work item.
*
* This routine schedules work item @a work to be processed by workqueue
* @a work_q when one of the given @a events is signaled. The routine
* initiates internal poller for the work item and then returns to the caller.
* Only when one of the watched events happen the work item is actually
* submitted to the workqueue and becomes pending.
*
* Submitting a previously submitted triggered work item that is still
* waiting for the event cancels the existing submission and reschedules it
* the using the new event list. Note that this behavior is inherently subject
* to race conditions with the pre-existig triggered work item and work queue,
* so care must be taken to synchronize such resubmissions externally.
*
* @note Can be called by ISRs.
*
* @warning
* Provided array of events as well as a triggered work item must be placed
* in persistent memory (valid until work handler execution or work
* cancellation) and cannot be modified after submission.
*
* @param work_q Address of workqueue.
* @param work Address of delayed work item.
* @param events An array of pointers to events which trigger the work.
* @param num_events The number of events in the array.
* @param timeout Timeout after which the work will be scheduled for
* execution even if not triggered.
*
*
* @retval 0 Work item started watching for events.
* @retval -EINVAL Work item is being processed or has completed its work.
* @retval -EADDRINUSE Work item is pending on a different workqueue.
*/
extern int k_work_poll_submit_to_queue(struct k_work_q *work_q,
struct k_work_poll *work,
struct k_poll_event *events,
int num_events,
s32_t timeout);

/**
* @brief Submit a triggered work item to the system workqueue.
*
* This routine schedules work item @a work to be processed by system
* workqueue when one of the given @a events is signaled. The routine
* initiates internal poller for the work item and then returns to the caller.
* Only when one of the watched events happen the work item is actually
* submitted to the workqueue and becomes pending.
*
* Submitting a previously submitted triggered work item that is still
* waiting for the event cancels the existing submission and reschedules it
* the using the new event list. Note that this behavior is inherently subject
* to race conditions with the pre-existig triggered work item and work queue,
* so care must be taken to synchronize such resubmissions externally.
*
* @note Can be called by ISRs.
*
* @warning
* Provided array of events as well as a triggered work item must not be
* modified until the item has been processed by the workqueue.
*
* @param work Address of delayed work item.
* @param events An array of pointers to events which trigger the work.
* @param num_events The number of events in the array.
* @param timeout Timeout after which the work will be scheduled for
* execution even if not triggered.
*
* @retval 0 Work item started watching for events.
* @retval -EINVAL Work item is being processed or has completed its work.
* @retval -EADDRINUSE Work item is pending on a different workqueue.
*/
static inline int k_work_poll_submit(struct k_work_poll *work,
struct k_poll_event *events,
int num_events,
s32_t timeout)
{
return k_work_poll_submit_to_queue(&k_sys_work_q, work,
events, num_events, timeout);
}

/**
* @brief Cancel a triggered work item.
*
* This routine cancels the submission of triggered work item @a work.
* A triggered work item can only be canceled if no event triggered work
* submission.
*
* @note Can be called by ISRs.
*
* @param work Address of delayed work item.
*
* @retval 0 Work tiem canceled.
* @retval -EINVAL Work item is being processed or has completed its work.
*/
extern int k_work_poll_cancel(struct k_work_poll *work);

/** @} */
/**
* @defgroup mutex_apis Mutex APIs
Expand Down
Loading

0 comments on commit 19d8349

Please sign in to comment.