1use crate::future::Future;
10use crate::loom::cell::UnsafeCell;
11use crate::runtime::task::{JoinHandle, LocalNotified, Notified, Schedule, SpawnLocation, Task};
12use crate::util::linked_list::LinkedList;
13use crate::util::sharded_list::ShardedList;
14
15use crate::loom::sync::atomic::{AtomicBool, Ordering};
16use std::marker::PhantomData;
17use std::num::NonZeroU64;
18
19cfg_has_atomic_u64! {
29 use std::sync::atomic::AtomicU64;
30
31 static NEXT_OWNED_TASKS_ID: AtomicU64 = AtomicU64::new(1);
32
33 fn get_next_id() -> NonZeroU64 {
34 loop {
35 let id = NEXT_OWNED_TASKS_ID.fetch_add(1, Ordering::Relaxed);
36 if let Some(id) = NonZeroU64::new(id) {
37 return id;
38 }
39 }
40 }
41}
42
43cfg_not_has_atomic_u64! {
44 use std::sync::atomic::AtomicU32;
45
46 static NEXT_OWNED_TASKS_ID: AtomicU32 = AtomicU32::new(1);
47
48 fn get_next_id() -> NonZeroU64 {
49 loop {
50 let id = NEXT_OWNED_TASKS_ID.fetch_add(1, Ordering::Relaxed);
51 if let Some(id) = NonZeroU64::new(u64::from(id)) {
52 return id;
53 }
54 }
55 }
56}
57
58pub(crate) struct OwnedTasks<S: 'static> {
59 list: ShardedList<Task<S>>,
60 pub(crate) id: NonZeroU64,
61 closed: AtomicBool,
62}
63
64pub(crate) struct LocalOwnedTasks<S: 'static> {
65 inner: UnsafeCell<OwnedTasksInner<S>>,
66 pub(crate) id: NonZeroU64,
67 _not_send_or_sync: PhantomData<*const ()>,
68}
69
70struct OwnedTasksInner<S: 'static> {
71 list: LinkedList<Task<S>>,
72 closed: bool,
73}
74
75impl<S: 'static> OwnedTasks<S> {
76 pub(crate) fn new(num_cores: usize) -> Self {
77 let shard_size = Self::gen_shared_list_size(num_cores);
78 Self {
79 list: ShardedList::new(shard_size),
80 closed: AtomicBool::new(false),
81 id: get_next_id(),
82 }
83 }
84
85 pub(crate) fn bind<T>(
88 &self,
89 task: T,
90 scheduler: S,
91 id: super::Id,
92 spawned_at: SpawnLocation,
93 ) -> (JoinHandle<T::Output>, Option<Notified<S>>)
94 where
95 S: Schedule,
96 T: Future + Send + 'static,
97 T::Output: Send + 'static,
98 {
99 let (task, notified, join) = super::new_task(task, scheduler, id, spawned_at);
100 let notified = unsafe { self.bind_inner(task, notified) };
101 (join, notified)
102 }
103
104 pub(crate) unsafe fn bind_local<T>(
110 &self,
111 task: T,
112 scheduler: S,
113 id: super::Id,
114 spawned_at: SpawnLocation,
115 ) -> (JoinHandle<T::Output>, Option<Notified<S>>)
116 where
117 S: Schedule,
118 T: Future + 'static,
119 T::Output: 'static,
120 {
121 let (task, notified, join) = super::new_task(task, scheduler, id, spawned_at);
122 let notified = unsafe { self.bind_inner(task, notified) };
123 (join, notified)
124 }
125
126 unsafe fn bind_inner(&self, task: Task<S>, notified: Notified<S>) -> Option<Notified<S>>
128 where
129 S: Schedule,
130 {
131 unsafe {
132 task.header().set_owner_id(self.id);
135 }
136
137 let shard = self.list.lock_shard(&task);
138 if self.closed.load(Ordering::Acquire) {
141 drop(shard);
142 task.shutdown();
143 return None;
144 }
145 shard.push(task);
146 Some(notified)
147 }
148
149 #[inline]
152 pub(crate) fn assert_owner(&self, task: Notified<S>) -> LocalNotified<S> {
153 debug_assert_eq!(task.header().get_owner_id(), Some(self.id));
154 LocalNotified {
157 task: task.0,
158 _not_send: PhantomData,
159 }
160 }
161
162 pub(crate) fn close_and_shutdown_all(&self, start: usize)
168 where
169 S: Schedule,
170 {
171 self.closed.store(true, Ordering::Release);
172 for i in start..self.get_shard_size() + start {
173 loop {
174 let task = self.list.pop_back(i);
175 match task {
176 Some(task) => {
177 task.shutdown();
178 }
179 None => break,
180 }
181 }
182 }
183 }
184
185 #[inline]
186 pub(crate) fn get_shard_size(&self) -> usize {
187 self.list.shard_size()
188 }
189
190 pub(crate) fn num_alive_tasks(&self) -> usize {
191 self.list.len()
192 }
193
194 cfg_unstable_metrics! {
195 cfg_64bit_metrics! {
196 pub(crate) fn spawned_tasks_count(&self) -> u64 {
197 self.list.added()
198 }
199 }
200 }
201
202 pub(crate) fn remove(&self, task: &Task<S>) -> Option<Task<S>> {
203 let task_id = task.header().get_owner_id()?;
206
207 assert_eq!(task_id, self.id);
208
209 unsafe { self.list.remove(task.header_ptr()) }
212 }
213
214 pub(crate) fn is_empty(&self) -> bool {
215 self.list.is_empty()
216 }
217
218 fn gen_shared_list_size(num_cores: usize) -> usize {
230 const MAX_SHARED_LIST_SIZE: usize = 1 << 16;
231 usize::min(MAX_SHARED_LIST_SIZE, num_cores.next_power_of_two() * 4)
232 }
233}
234
235cfg_taskdump! {
236 impl<S: 'static> OwnedTasks<S> {
237 pub(crate) fn for_each<F>(&self, f: F)
239 where
240 F: FnMut(&Task<S>),
241 {
242 self.list.for_each(f);
243 }
244 }
245}
246
247impl<S: 'static> LocalOwnedTasks<S> {
248 pub(crate) fn new() -> Self {
249 Self {
250 inner: UnsafeCell::new(OwnedTasksInner {
251 list: LinkedList::new(),
252 closed: false,
253 }),
254 id: get_next_id(),
255 _not_send_or_sync: PhantomData,
256 }
257 }
258
259 pub(crate) fn bind<T>(
260 &self,
261 task: T,
262 scheduler: S,
263 id: super::Id,
264 spawned_at: SpawnLocation,
265 ) -> (JoinHandle<T::Output>, Option<Notified<S>>)
266 where
267 S: Schedule,
268 T: Future + 'static,
269 T::Output: 'static,
270 {
271 let (task, notified, join) = super::new_task(task, scheduler, id, spawned_at);
272
273 unsafe {
274 task.header().set_owner_id(self.id);
277 }
278
279 if self.is_closed() {
280 drop(notified);
281 task.shutdown();
282 (join, None)
283 } else {
284 self.with_inner(|inner| {
285 inner.list.push_front(task);
286 });
287 (join, Some(notified))
288 }
289 }
290
291 pub(crate) fn close_and_shutdown_all(&self)
294 where
295 S: Schedule,
296 {
297 self.with_inner(|inner| inner.closed = true);
298
299 while let Some(task) = self.with_inner(|inner| inner.list.pop_back()) {
300 task.shutdown();
301 }
302 }
303
304 pub(crate) fn remove(&self, task: &Task<S>) -> Option<Task<S>> {
305 let task_id = task.header().get_owner_id()?;
308
309 assert_eq!(task_id, self.id);
310
311 self.with_inner(|inner|
312 unsafe { inner.list.remove(task.header_ptr()) })
315 }
316
317 #[inline]
320 pub(crate) fn assert_owner(&self, task: Notified<S>) -> LocalNotified<S> {
321 assert_eq!(task.header().get_owner_id(), Some(self.id));
322
323 LocalNotified {
327 task: task.0,
328 _not_send: PhantomData,
329 }
330 }
331
332 #[inline]
333 fn with_inner<F, T>(&self, f: F) -> T
334 where
335 F: FnOnce(&mut OwnedTasksInner<S>) -> T,
336 {
337 self.inner.with_mut(|ptr| unsafe { f(&mut *ptr) })
341 }
342
343 pub(crate) fn is_closed(&self) -> bool {
344 self.with_inner(|inner| inner.closed)
345 }
346
347 pub(crate) fn is_empty(&self) -> bool {
348 self.with_inner(|inner| inner.list.is_empty())
349 }
350}
351
352#[cfg(test)]
353mod tests {
354 use super::*;
355
356 #[test]
359 fn test_id_not_broken() {
360 let mut last_id = get_next_id();
361
362 for _ in 0..1000 {
363 let next_id = get_next_id();
364 assert!(last_id < next_id);
365 last_id = next_id;
366 }
367 }
368}