pw_work_queue: Adds a single threaded work queue
Adds a pw::work_queue::WorkQueue concept which is comprised of a
queue of pw::Functions and a singular thread which drains the
queue.
Change-Id: I67d595c097222f8c3a582c990434abeadbb8910a
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/56269
Pigweed-Auto-Submit: Ewout van Bekkum <ewout@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
Reviewed-by: Keir Mierle <keir@google.com>
diff --git a/pw_work_queue/docs.rst b/pw_work_queue/docs.rst
new file mode 100644
index 0000000..7ae6efa
--- /dev/null
+++ b/pw_work_queue/docs.rst
@@ -0,0 +1,104 @@
+.. _module-pw_work_queue:
+
+=============
+pw_work_queue
+=============
+The ``pw_work_queue`` module contains utilities for deferring work to be
+executed by another thread.
+
+.. Warning::
+ This module is still under construction, the API is not yet stable.
+
+---------
+WorkQueue
+---------
+The ``pw::work_queue::WorkQueue`` class enables threads and interrupts to
+enqueue work as a ``pw::work_queue::WorkItem`` for execution by the work queue.
+
+The entire API is thread and interrupt safe.
+
+Queue Sizing
+============
+The number of outstanding work requests is limited based on the
+``pw::work_queue::WorkQueue``'s internal queue size. This must be set
+appropriately for the application by the user.
+
+The queue size is set trough either through the size of the ``queue_storage``
+buffer passed into the constructor or by using the templated
+``pw::work_queue::WorkQueueWithBuffer`` helper.
+
+.. Note:: While the queue is full, the queue will not accept further work.
+
+Cooperative Thread Cancellation
+===============================
+The class is a ``pw::thread::ThreadCore``, meaning it should be executed as a
+single thread. In order to facilitate clean shutdown, it provides a
+``RequestStop()`` API for cooperative cancellation which should be invoked
+before joining the thread.
+
+.. Note:: Once stop has been requested the queue will no longer accept further
+ work.
+
+C++
+===
+.. cpp:class:: pw::work_queue::WorkQueue
+
+ .. cpp:function:: Status PushWork(WorkItem work_item)
+
+ Enqueues a work_item for execution by the work queue thread.
+
+ Returns:
+
+ * **Ok** - Success, entry was enqueued for execution.
+ * **FailedPrecondition** - the work queue is shutting down, entries are no
+ longer permitted.
+ * **ResourceExhausted** - internal work queue is full, entry was not
+ enqueued.
+
+ .. cpp:function:: void CheckPushWork(WorkItem work_item)
+
+ Queue work for execution. Crash if the work cannot be queued due to a
+ full queue or a stopped worker thread.
+
+ This call is recommended where possible since it saves error handling code
+ at the callsite; and in many practical cases, it is a bug if the work
+ queue is full (and so a crash is useful to detect the problem).
+
+ **Precondition:** The queue must not overflow, i.e. be full.
+
+ **Precondition:** The queue must not have been requested to stop, i.e. it
+ must not be in the process of shutting down.
+
+ .. cpp:function:: void RequestStop()
+
+ Locks the queue to prevent further work enqueing, finishes outstanding
+ work, then shuts down the worker thread.
+
+ The WorkQueue cannot be resumed after stopping as the ThreadCore thread
+ returns and may be joined. It must be reconstructed for re-use after
+ the thread has been joined.
+
+Example
+-------
+
+.. code-block:: cpp
+
+ #include "pw_thread/detached_thread.h"
+ #include "pw_work_queue/work_queue.h"
+
+ pw::work_queue::WorkQueueWithBuffer<10> work_queue;
+
+ pw::thread::Options& WorkQueueThreadOptions();
+ void SomeLongRunningProcessing();
+
+ void SomeInterruptHandler() {
+ // Instead of executing the long running processing task in the interrupt,
+ // the work_queue executes it on the interrupt's behalf.
+ work_queue.CheckPushWork(SomeLongRunningProcessing);
+ }
+
+ int main() {
+ // Start up the work_queue as a detached thread which runs forever.
+ pw::thread::DetachedThread(WorkQueueThreadOptions(), work_queue);
+ }
+