|
8 | 8 | //! [`futures`]: crate::work::futures
|
9 | 9 |
|
10 | 10 | use core::ffi::CStr;
|
11 |
| -use core::task::Poll; |
| 11 | +use core::task::{Context, Poll}; |
12 | 12 | use core::{future::Future, pin::Pin};
|
13 | 13 |
|
14 |
| -use crate::time::NoWait; |
| 14 | +use crate::sys::queue::Queue; |
| 15 | +use crate::sys::sync::Semaphore; |
| 16 | +use crate::time::{NoWait, Timeout}; |
15 | 17 | use crate::work::futures::WakeInfo;
|
| 18 | +use crate::work::Signal; |
16 | 19 | use crate::work::{futures::JoinHandle, futures::WorkBuilder, WorkQueue};
|
17 | 20 |
|
18 | 21 | pub mod sync;
|
19 | 22 |
|
| 23 | +pub use crate::work::futures::sleep; |
| 24 | + |
20 | 25 | /// Run an async future on the given worker thread.
|
21 | 26 | ///
|
22 | 27 | /// Arrange to have the given future run on the given worker thread. The resulting `JoinHandle` has
|
@@ -94,3 +99,67 @@ impl Future for YieldNow {
|
94 | 99 | }
|
95 | 100 | }
|
96 | 101 | }
|
| 102 | + |
| 103 | +/// Extensions on [`Context`] to support scheduling via Zephyr's workqueue system. |
| 104 | +/// |
| 105 | +/// All of these are called from within the context of running work, and indicate what _next_ |
| 106 | +/// should cause this work to be run again. If none of these methods are called before the work |
| 107 | +/// exits, the work will be scheduled to run after `Forever`, which is not useful. There may be |
| 108 | +/// later support for having a `Waker` that can schedule work from another context. |
| 109 | +/// |
| 110 | +/// Note that the events to wait on, such as Semaphores or channels, if there are multiple threads |
| 111 | +/// that can wait for them, might cause this worker to run, but not actually be available. As such, |
| 112 | +/// to maintain the non-blocking requirements of Work, [`Semaphore::take`], and the blocking `send` |
| 113 | +/// and `recv` operations on channels should not be used, even after being woken. |
| 114 | +/// |
| 115 | +/// For the timeout [`Forever`] is useful to indicate there is no timeout. If called with |
| 116 | +/// [`NoWait`], the work will be immediately scheduled. In general, it is better to query the |
| 117 | +/// underlying object directly rather than have the overhead of being rescheduled. |
| 118 | +/// |
| 119 | +/// # Safety |
| 120 | +/// |
| 121 | +/// The lifetime bounds on the items waited for ensure that these items live at least as long as the |
| 122 | +/// work queue. Practically, this can only be satisfied by using something with 'static' lifetime, |
| 123 | +/// or embedding the value in the Future itself. |
| 124 | +/// |
| 125 | +/// With the Zephyr executor, the `Context` is embedded within a `WakeInfo` struct, which this makes |
| 126 | +/// use of. If a different executor were to be used, these calls would result in undefined |
| 127 | +/// behavior. |
| 128 | +/// |
| 129 | +/// This could be checked at runtime, but it would have runtime cost. |
| 130 | +pub trait ContextExt { |
| 131 | + /// Indicate the work should next be scheduled based on a semaphore being available for "take". |
| 132 | + /// |
| 133 | + /// The work will be scheduled either when the given semaphore becomes available to 'take', or |
| 134 | + /// after the timeout. |
| 135 | + fn add_semaphore<'a>(&'a mut self, sem: &'a Semaphore, timeout: impl Into<Timeout>); |
| 136 | + |
| 137 | + /// Indicate that the work should be scheduled after receiving the given [`Signal`], or the |
| 138 | + /// timeout occurs. |
| 139 | + fn add_signal<'a>(&'a mut self, signal: &'a Signal, timeout: impl Into<Timeout>); |
| 140 | + |
| 141 | + /// Indicate that the work should be scheduled when the given [`Queue`] has data available to |
| 142 | + /// recv, or the timeout occurs. |
| 143 | + fn add_queue<'a>(&'a mut self, queue: &'a Queue, timeout: impl Into<Timeout>); |
| 144 | +} |
| 145 | + |
| 146 | +/// Implementation of ContextExt for the Rust [`Context`] type. |
| 147 | +impl<'b> ContextExt for Context<'b> { |
| 148 | + fn add_semaphore<'a>(&'a mut self, sem: &'a Semaphore, timeout: impl Into<Timeout>) { |
| 149 | + let info = unsafe { WakeInfo::from_context(self) }; |
| 150 | + info.add_semaphore(sem); |
| 151 | + info.timeout = timeout.into(); |
| 152 | + } |
| 153 | + |
| 154 | + fn add_signal<'a>(&'a mut self, signal: &'a Signal, timeout: impl Into<Timeout>) { |
| 155 | + let info = unsafe { WakeInfo::from_context(self) }; |
| 156 | + info.add_signal(signal); |
| 157 | + info.timeout = timeout.into(); |
| 158 | + } |
| 159 | + |
| 160 | + fn add_queue<'a>(&'a mut self, queue: &'a Queue, timeout: impl Into<Timeout>) { |
| 161 | + let info = unsafe { WakeInfo::from_context(self) }; |
| 162 | + info.add_queue(queue); |
| 163 | + info.timeout = timeout.into(); |
| 164 | + } |
| 165 | +} |
0 commit comments