laminar_connectors/connector/
task_tracking.rs1use std::sync::atomic::{AtomicUsize, Ordering};
4use std::sync::{Arc, Weak};
5
6use tokio::sync::Notify;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
15#[serde(rename_all = "snake_case")]
16pub enum ConnectorCancellationPolicy {
17 CancelSafe,
19 RetireConnector,
22}
23
24const CONNECTOR_TASK_OWNER_DROPPED: usize = 1usize << (usize::BITS - 1);
25
26pub(super) struct ConnectorTaskState {
27 state: AtomicUsize,
28 terminated: Notify,
29}
30
31pub struct ConnectorTaskOwner {
36 inner: Arc<ConnectorTaskState>,
37}
38
39#[derive(Clone)]
45pub struct ConnectorTaskAdmission {
46 pub(super) inner: Weak<ConnectorTaskState>,
47}
48
49#[derive(Clone)]
51pub struct ConnectorTaskTracker {
52 inner: Arc<ConnectorTaskState>,
53}
54
55#[must_use = "dropping the guard marks its connector task complete"]
60pub struct ConnectorTaskGuard {
61 inner: Arc<ConnectorTaskState>,
62}
63
64impl ConnectorTaskOwner {
65 #[must_use]
67 pub fn new() -> (Self, ConnectorTaskTracker) {
68 let inner = Arc::new(ConnectorTaskState {
69 state: AtomicUsize::new(0),
70 terminated: Notify::new(),
71 });
72 (
73 Self {
74 inner: Arc::clone(&inner),
75 },
76 ConnectorTaskTracker { inner },
77 )
78 }
79
80 #[must_use]
86 pub fn admission(&self) -> ConnectorTaskAdmission {
87 ConnectorTaskAdmission {
88 inner: Arc::downgrade(&self.inner),
89 }
90 }
91
92 #[must_use]
97 pub fn track(&self) -> Option<ConnectorTaskGuard> {
98 track_connector_task(&self.inner)
99 }
100}
101
102impl ConnectorTaskAdmission {
103 #[must_use]
108 pub fn track(&self) -> Option<ConnectorTaskGuard> {
109 let inner = self.inner.upgrade()?;
110 track_connector_task(&inner)
111 }
112}
113
114fn track_connector_task(inner: &Arc<ConnectorTaskState>) -> Option<ConnectorTaskGuard> {
115 let mut observed = inner.state.load(Ordering::Acquire);
116 loop {
117 if observed & CONNECTOR_TASK_OWNER_DROPPED != 0 {
118 return None;
119 }
120 let next = observed.checked_add(1)?;
121 if next & CONNECTOR_TASK_OWNER_DROPPED != 0 {
122 return None;
123 }
124 match inner
125 .state
126 .compare_exchange_weak(observed, next, Ordering::AcqRel, Ordering::Acquire)
127 {
128 Ok(_) => {
129 return Some(ConnectorTaskGuard {
130 inner: Arc::clone(inner),
131 });
132 }
133 Err(actual) => observed = actual,
134 }
135 }
136}
137
138impl Drop for ConnectorTaskOwner {
139 fn drop(&mut self) {
140 let previous = self
141 .inner
142 .state
143 .fetch_or(CONNECTOR_TASK_OWNER_DROPPED, Ordering::AcqRel);
144 debug_assert_eq!(previous & CONNECTOR_TASK_OWNER_DROPPED, 0);
145 if previous == 0 {
146 self.inner.terminated.notify_waiters();
147 }
148 }
149}
150
151impl ConnectorTaskTracker {
152 #[must_use]
154 pub fn is_terminated(&self) -> bool {
155 self.inner.state.load(Ordering::Acquire) == CONNECTOR_TASK_OWNER_DROPPED
156 }
157
158 pub async fn wait_terminated(&self) {
160 loop {
161 let notified = self.inner.terminated.notified();
162 tokio::pin!(notified);
163 notified.as_mut().enable();
164 if self.is_terminated() {
165 return;
166 }
167 notified.await;
168 }
169 }
170}
171
172impl Drop for ConnectorTaskGuard {
173 fn drop(&mut self) {
174 let previous = self.inner.state.fetch_sub(1, Ordering::AcqRel);
175 debug_assert_ne!(previous & !CONNECTOR_TASK_OWNER_DROPPED, 0);
176 if previous == CONNECTOR_TASK_OWNER_DROPPED | 1 {
177 self.inner.terminated.notify_waiters();
178 }
179 }
180}