Skip to main content

task/manager/
lifecycle.rs

1// Lifecycle module - handles task spawning, execution, and lifecycle management
2
3use super::*;
4use alloc::boxed::Box;
5use core::{
6    future::{Future, poll_fn},
7    ptr::NonNull,
8    task::Poll,
9    time::Duration,
10};
11use embassy_executor::raw::{TaskPool, task_from_waker};
12use embassy_time::Timer;
13
14impl Manager {
15    // Static function to create and execute tasks
16    // This function is outside the closure that captures SpawnToken,
17    // so it can be called safely from nested tasks
18    async fn create_and_run_task<R: 'static, FunctionType, FutureType>(
19        manager: &'static Manager,
20        parent_task_identifier: TaskIdentifier,
21        name: &str,
22        function: FunctionType,
23        spawner: Option<usize>,
24    ) -> Result<(JoinHandle<R>, TaskIdentifier)>
25    where
26        FunctionType: FnOnce(TaskIdentifier) -> FutureType + 'static,
27        FutureType: Future<Output = R> + 'static,
28    {
29        let identifier = manager
30            .register(parent_task_identifier, name)
31            .await
32            .expect("Failed to get new task identifier");
33
34        let pool = Box::new(TaskPool::<_, 1>::new());
35        let pool = Box::leak(pool);
36
37        let (join_handle_parent, join_handle_child) = JoinHandle::new();
38
39        let task = async move || {
40            let manager = manager;
41            let internal_identifier = Manager::get_current_internal_identifier().await;
42
43            manager
44                .set_internal_identifier(identifier, internal_identifier)
45                .await
46                .expect("Failed to register task");
47
48            let result = function(identifier).await;
49
50            join_handle_child.signal(result);
51
52            manager
53                .unregister(identifier)
54                .await
55                .expect("Failed to unregister task");
56        };
57
58        let mut inner = manager.0.write().await;
59
60        // Select the best spawner for the new task
61        let spawner = if let Some(spawner) = spawner {
62            if !inner.spawners.contains_key(&spawner) {
63                return Err(Error::InvalidSpawnerIdentifier);
64            }
65            spawner
66        } else {
67            Manager::select_best_spawner(&inner)?
68        };
69
70        inner
71            .tasks
72            .get_mut(&identifier)
73            .expect("Failed to get task metadata")
74            .spawner_identifier = spawner;
75
76        let token = pool.spawn(task).expect("Failed to spawn task");
77
78        inner
79            .spawners
80            .get(&spawner)
81            .expect("Failed to get spawner")
82            .spawn(token);
83
84        Ok((join_handle_parent, identifier))
85    }
86
87    /// Spawn task
88    pub async fn spawn<FunctionType, FutureType, ReturnType>(
89        &'static self,
90        parent_task: TaskIdentifier,
91        name: &str,
92        spawner: Option<usize>,
93        function: FunctionType,
94    ) -> Result<(JoinHandle<ReturnType>, TaskIdentifier)>
95    where
96        FunctionType: FnOnce(TaskIdentifier) -> FutureType + 'static,
97        FutureType: Future<Output = ReturnType> + 'static,
98        ReturnType: 'static,
99    {
100        // Call the helper function with all our parameters
101        Self::create_and_run_task(self, parent_task, name, function, spawner).await
102    }
103
104    /// Set the internal identifier of a task.
105    ///
106    /// This function check if the task identifier is not already used,
107    /// however it doesn't check if the parent task exists.
108    async fn set_internal_identifier(
109        &self,
110        identifier: TaskIdentifier,
111        internal_identifier: usize,
112    ) -> Result<()> {
113        let mut inner = self.0.write().await;
114
115        let metadata = Self::get_task_mutable(&mut inner, identifier)?;
116
117        metadata.internal_identifier = internal_identifier;
118
119        // Register the internal identifier of the task
120        if let Some(old_identifier) = inner.identifiers.insert(internal_identifier, identifier) {
121            // Rollback the task registration if internal identifier registration fails
122            inner.identifiers.remove(&internal_identifier);
123            inner
124                .identifiers
125                .insert(internal_identifier, old_identifier);
126            return Err(Error::InvalidTaskIdentifier);
127        }
128
129        Ok(())
130    }
131
132    /// Sleep the current thread for a given duration.
133    pub async fn sleep(duration: Duration) {
134        let nano_seconds = duration.as_nanos();
135
136        Timer::after(embassy_time::Duration::from_nanos(nano_seconds as u64)).await
137    }
138
139    pub async fn get_current_internal_identifier() -> usize {
140        poll_fn(|context| {
141            let task_reference = task_from_waker(context.waker());
142
143            let inner: NonNull<u8> = unsafe { core::mem::transmute(task_reference) };
144
145            let identifier = inner.as_ptr() as usize;
146
147            Poll::Ready(identifier)
148        })
149        .await
150    }
151
152    pub async fn get_current_task_identifier(&self) -> TaskIdentifier {
153        let internal_identifier = Self::get_current_internal_identifier().await;
154
155        {
156            let inner = self.0.read().await;
157            if let Some(identifier) = inner.identifiers.get(&internal_identifier) {
158                return *identifier;
159            }
160        }
161
162        // Every independently constructed task manager registers the executor's
163        // current task as its own root task on first access.
164        let mut inner = self.0.write().await;
165        if let Some(identifier) = inner.identifiers.get(&internal_identifier) {
166            return *identifier;
167        }
168        let root = Manager::ROOT_TASK_IDENTIFIER;
169        inner.tasks.insert(
170            root,
171            Metadata {
172                internal_identifier,
173                name: "Root".into(),
174                parent: root,
175                user: users::UserIdentifier::ROOT,
176                group: users::GroupIdentifier::ROOT,
177                environment_variables: alloc::vec::Vec::new(),
178                signals: crate::signal::SignalAccumulator::new(),
179                spawner_identifier: 0,
180            },
181        );
182        inner.identifiers.insert(internal_identifier, root);
183
184        root
185    }
186}