doc: kernel: workqueue: correct documentation of delayed work API

The delayed work API has been changed to allow cancellation in
conditions not previously documented, but this feature can cause both
submission and cancellation to fail in the general case.  Summarize
the conditions and highlight the importance of checking result codes
for these functions.

Also explicitly note that no kernel API can reliably indicate that a
work item has been completed, and that doing so is the responsibility
of the code that provides the work handler.

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
This commit is contained in:
Peter Bigot 2020-10-02 17:22:00 -05:00 committed by Carles Cufí
commit cbff3e34d7
2 changed files with 53 additions and 24 deletions

View file

@ -87,6 +87,13 @@ the processing of other work items in the workqueue's queue.
handler function needs to perform its work must not be altered until
the handler function has finished executing.
There *is no kernel API* that can be used to determine that the handler
function has finished executing. Infrastructure that uses work items and
needs to know the work item status must manage state in the handler
function.
.. _k_delayed_work:
Delayed Work
************
@ -111,15 +118,34 @@ that is triggered after the specified delay has elapsed. Once the timeout
occurs the kernel submits the delayed work item to the specified workqueue,
where it remains pending until it is processed in the standard manner.
An ISR or a thread may **cancel** a delayed work item it has submitted,
providing the work item's timeout is still counting down. The work item's
timeout is aborted and the specified work is not performed.
An ISR or a thread may attempt to **cancel** a delayed work item. If
successful the specified work is not performed. However, attempting to cancel
a delayed work item succeeds in only two cases:
Attempting to cancel a delayed work item once its timeout has expired has
no effect on the work item; the work item remains pending in the workqueue's
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.
* its timeout has not yet expired and been processed; or
* it is still pending and the cancellation successfully removes it from the
workqueue before the workqueue's thread gets to it.
Because of the locking used to manage workqueues there are transient states
that are sometimes not observable, but if observed will cause the cancellation
will fail. In those cases the work item may or may not be invoked. The
transient states can be observed and cause failure when:
* the workqueue or application threads are preemptible;
* the API is invoked from an ISR; or
* when the code is run on a multiprocessor system.
Note that both :c:func:`k_delayed_work_submit_to_queue()` and
:c:func:`k_delayed_work_cancel()` attempt to cancel a previously submitted
item and can fail. When they fail the work handler of the previous submission
may or may not be invoked.
.. warning::
Because of these race conditions all code that invokes the delayed work API
must check return values and be prepared to react when either submission or
cancellation fails.
Triggered Work
**************
@ -259,6 +285,9 @@ calling :c:func:`k_delayed_work_submit_to_queue`. A delayed work item
that has been submitted but not yet consumed by its workqueue can be canceled
by calling :c:func:`k_delayed_work_cancel`.
.. warning::
All of these operations can fail as described in :ref:`k_delayed_work`.
Suggested Uses
**************

View file

@ -3270,9 +3270,9 @@ extern void k_delayed_work_init(struct k_delayed_work *work,
*
* @retval 0 Work item countdown started.
* @retval -EINVAL
* @li if a previously submitted work item had to be cancelled,
* and the cancellation failed; or
* @li Work item is being processed or has completed its work.
* * if a previously submitted work item had to be cancelled and the
* cancellation failed; or
* * Work item is being processed or has completed its work.
* @retval -EADDRINUSE Work item was submitted to a different workqueue.
*/
extern int k_delayed_work_submit_to_queue(struct k_work_q *work_q,
@ -3294,21 +3294,21 @@ extern int k_delayed_work_submit_to_queue(struct k_work_q *work_q,
* @param work Address of delayed work item.
*
* @retval 0
* @li Work item countdown cancelled before the item was submitted to its
* queue; or
* @li Work item was removed from its queue before it was processed.
* * Work item countdown cancelled before the item was submitted to its
* queue; or
* * Work item was removed from its queue before it was processed.
* @retval -EINVAL
* @li Work item has never been submitted; or
* @li Work item has been successfully cancelled; or
* @li Timeout handler is in the process of submitting the work item to its
* queue; or
* @li Work queue thread has removed the work item from the queue but has
* not called its handler.
* * Work item has never been submitted; or
* * Work item has been successfully cancelled; or
* * Timeout handler is in the process of submitting the work item to its
* queue; or
* * Work queue thread has removed the work item from the queue but has not
* called its handler.
* @retval -EALREADY
* @li Work queue thread has removed the work item from the queue and
* cleared its pending flag; or
* @li Work queue thread is invoking the item handler; or
* @li Work item handler has completed.
* * Work queue thread has removed the work item from the queue and cleared
* its pending flag; or
* * Work queue thread is invoking the item handler; or
* * Work item handler has completed.
*/
extern int k_delayed_work_cancel(struct k_delayed_work *work);