1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
use std::sync::Arc;
use mvutils::id_eq;
use mvutils::utils::next_id;
use crate::block::Signal;
/// A sync object used to add control flow to tasks. It is an internal sync object, meaning it can
/// only be read from within a task. If a task depends on another one to finish, you should use a
/// Semaphore to force the task to wait for the dependency to finish.
///
/// # Note
/// If a semaphore is bound to multiple tasks, it will signal as soon as the first task finishes.
/// Counter semaphores are planned to be added in the future.
pub struct Semaphore {
id: u64,
signaled: bool
}
impl Semaphore {
pub(crate) fn new() -> Semaphore {
Semaphore {
id: next_id("MVSync"),
signaled: false
}
}
pub(crate) fn signal(&self) {
unsafe {
(self as *const Semaphore).cast_mut().as_mut().unwrap().signaled = true;
}
}
pub(crate) fn ready(&self) -> bool {
self.signaled
}
}
/// A sync object used to wait for tasks. It is an external sync object, meaning it can
/// only be read from outside tasks. If you need to await a task whose result was passed into
/// another task, or you need to share a task "handle" without sharing the result, you should
/// use a Fence.
///
/// # Note
/// If a fence is bound to multiple tasks, it will open as soon as the first task finishes.
/// Counter fences are planned to be added in the future.
pub struct Fence {
id: u64,
signalled: Option<Arc<Signal>>
}
impl Fence {
pub(crate) fn new() -> Self {
Fence {
id: next_id("MVSync"),
signalled: None
}
}
pub(crate) fn bind(&self, signal: Arc<Signal>) {
unsafe {
(self as *const Fence).cast_mut().as_mut().unwrap().signalled.replace(signal);
}
}
/// Check if the fence is open.
///
/// If this returns `true`, the task that signalled the fence has already finished.
///
/// # Note
/// If a fence is bound to multiple tasks, it will open as soon as the first task finishes.
/// Counter fences are planned to be added in the future.
pub fn ready(&self) -> bool {
self.signalled.as_ref().expect("Checking unbound fence!").ready()
}
/// Block the current thread until the fence is signaled, indicating that the task
/// this fence is bound to has finished.
///
/// # Note
/// If a fence is bound to multiple tasks, it will open as soon as the first task finishes.
/// Counter fences are planned to be added in the future.
pub fn wait(&self) {
self.signalled.clone().expect("Checking unbound fence!").wait()
}
/// Block the current thread until the fence is signaled, indicating that the task
/// this fence is bound to has finished.
///
/// # Note
/// If a fence is bound to multiple tasks, it will open as soon as the first task finishes.
/// Counter fences are planned to be added in the future.
pub async fn wait_async(&self) {
self.signalled.clone().expect("Checking unbound fence!").wait_async().await
}
}
id_eq!(Semaphore, Fence);
pub enum SemaphoreUsage {
/// Wait for the semaphore to be signaled.
Wait,
/// Signal the semaphore upon completion.
Signal
}