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