1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 use std::cell::UnsafeCell;
15 use std::future::Future;
16 use std::mem;
17 use std::pin::Pin;
18 use std::ptr::NonNull;
19 use std::sync::Weak;
20 use std::task::{Context, Poll, Waker};
21
22 use crate::executor::Schedule;
23 use crate::task::state::TaskState;
24 use crate::task::task_handle::TaskHandle;
25 use crate::task::{TaskBuilder, VirtualTableType};
26 use crate::ScheduleError;
27
28 cfg_ffrt! {
29 use crate::ffrt::ffrt_task::FfrtTaskCtx;
30 }
31
32 pub(crate) struct TaskVirtualTable {
33 /// Task running method
34 pub(crate) run: unsafe fn(NonNull<Header>) -> bool,
35 /// Task scheduling method
36 pub(crate) schedule: unsafe fn(NonNull<Header>, bool),
37 /// Task result-getting method
38 pub(crate) get_result: unsafe fn(NonNull<Header>, *mut ()),
39 /// JoinHandle drop method
40 pub(crate) drop_join_handle: unsafe fn(NonNull<Header>),
41 /// Task reference drop method
42 pub(crate) drop_ref: unsafe fn(NonNull<Header>),
43 /// Task waker setting method
44 pub(crate) set_waker: unsafe fn(NonNull<Header>, cur_state: usize, waker: *const ()) -> bool,
45 /// Task release method
46 #[cfg(not(feature = "ffrt"))]
47 pub(crate) release: unsafe fn(NonNull<Header>),
48 /// Task cancel method
49 pub(crate) cancel: unsafe fn(NonNull<Header>),
50 }
51
52 #[repr(C)]
53 pub(crate) struct Header {
54 pub(crate) state: TaskState,
55 pub(crate) vtable: &'static TaskVirtualTable,
56 }
57
58 #[derive(PartialEq, Eq, Hash)]
59 pub(crate) struct RawTask {
60 pub(crate) ptr: NonNull<Header>,
61 }
62
63 impl RawTask {
form_raw(ptr: NonNull<Header>) -> RawTask64 pub(crate) fn form_raw(ptr: NonNull<Header>) -> RawTask {
65 RawTask { ptr }
66 }
67
header(&self) -> &Header68 pub(crate) fn header(&self) -> &Header {
69 unsafe { self.ptr.as_ref() }
70 }
71
run(self) -> bool72 pub(crate) fn run(self) -> bool {
73 let vir_table = self.header().vtable;
74 unsafe { (vir_table.run)(self.ptr) }
75 }
76
get_result(self, res: *mut ())77 pub(crate) unsafe fn get_result(self, res: *mut ()) {
78 let vir_table = self.header().vtable;
79 (vir_table.get_result)(self.ptr, res);
80 }
81
cancel(self)82 pub(crate) unsafe fn cancel(self) {
83 let vir_table = self.header().vtable;
84 (vir_table.cancel)(self.ptr)
85 }
86
set_waker(self, cur_state: usize, waker: *const ()) -> bool87 pub(crate) unsafe fn set_waker(self, cur_state: usize, waker: *const ()) -> bool {
88 let vir_table = self.header().vtable;
89 (vir_table.set_waker)(self.ptr, cur_state, waker)
90 }
91
drop_ref(self)92 pub(crate) fn drop_ref(self) {
93 let vir_table = self.header().vtable;
94 unsafe {
95 (vir_table.drop_ref)(self.ptr);
96 }
97 }
98
drop_join_handle(self)99 pub(crate) fn drop_join_handle(self) {
100 let vir_table = self.header().vtable;
101 unsafe {
102 (vir_table.drop_join_handle)(self.ptr);
103 }
104 }
105 }
106
107 #[cfg(not(feature = "ffrt"))]
108 impl RawTask {
shutdown(self)109 pub(super) fn shutdown(self) {
110 let vir_table = self.header().vtable;
111 unsafe {
112 (vir_table.release)(self.ptr);
113 }
114 }
115 }
116
117 impl Copy for RawTask {}
118
119 impl Clone for RawTask {
clone(&self) -> Self120 fn clone(&self) -> Self {
121 RawTask { ptr: self.ptr }
122 }
123 }
124
125 pub(crate) enum Stage<T: Future> {
126 Executing(T),
127 Executed,
128 StoreData(Result<T::Output, ScheduleError>),
129 UsedData,
130 }
131
132 #[repr(C)]
133 pub(crate) struct Inner<T: Future, S: Schedule> {
134 /// The execution stage of the future
135 pub(crate) stage: UnsafeCell<Stage<T>>,
136 /// The scheduler of the task queue
137 pub(crate) scheduler: Weak<S>,
138 /// Waker of the task waiting on this task
139 pub(crate) waker: UnsafeCell<Option<Waker>>,
140 /// Task in adaptive runtime
141 #[cfg(feature = "ffrt")]
142 pub(crate) task: UnsafeCell<Option<FfrtTaskCtx>>,
143 }
144
145 impl<T, S> Inner<T, S>
146 where
147 T: Future,
148 S: Schedule,
149 {
new(task: T, scheduler: Weak<S>) -> Self150 fn new(task: T, scheduler: Weak<S>) -> Self {
151 Inner {
152 stage: UnsafeCell::new(Stage::Executing(task)),
153 scheduler,
154 waker: UnsafeCell::new(None),
155 #[cfg(feature = "ffrt")]
156 task: UnsafeCell::new(None),
157 }
158 }
159
160 #[cfg(feature = "ffrt")]
get_task_ctx(&self)161 pub(crate) fn get_task_ctx(&self) {
162 unsafe {
163 if (*self.task.get()).is_none() {
164 (*self.task.get()).replace(FfrtTaskCtx::get_current());
165 }
166 }
167 }
168
turning_to_executed(&self)169 fn turning_to_executed(&self) {
170 let stage = self.stage.get();
171 unsafe {
172 *stage = Stage::Executed;
173 }
174 }
175
turning_to_used_data(&self)176 pub(crate) fn turning_to_used_data(&self) {
177 let stage = self.stage.get();
178 unsafe {
179 *stage = Stage::UsedData;
180 }
181 }
182
turning_to_store_data(&self, output: std::result::Result<T::Output, ScheduleError>)183 fn turning_to_store_data(&self, output: std::result::Result<T::Output, ScheduleError>) {
184 let stage = self.stage.get();
185 unsafe {
186 *stage = Stage::StoreData(output);
187 }
188 }
189
turning_to_get_data(&self) -> Result<T::Output, ScheduleError>190 pub(crate) fn turning_to_get_data(&self) -> Result<T::Output, ScheduleError> {
191 let stage = self.stage.get();
192 let data = mem::replace(unsafe { &mut *stage }, Stage::UsedData);
193 match data {
194 Stage::StoreData(output) => output,
195 _ => panic!("invalid task stage: the output is not stored inside the task"),
196 }
197 }
198
poll(&self, context: &mut Context) -> Poll<T::Output>199 pub(crate) fn poll(&self, context: &mut Context) -> Poll<T::Output> {
200 let stage = self.stage.get();
201 let future = match unsafe { &mut *stage } {
202 Stage::Executing(future) => future,
203 _ => panic!("invalid task stage: task polled while not being executed"),
204 };
205
206 let future = unsafe { Pin::new_unchecked(future) };
207 let res = future.poll(context);
208
209 // if result is received, turn the task to finished
210 if res.is_ready() {
211 self.turning_to_executed();
212 }
213 res
214 }
215
send_result(&self, output: Result<T::Output, ScheduleError>)216 pub(crate) fn send_result(&self, output: Result<T::Output, ScheduleError>) {
217 self.turning_to_store_data(output);
218 }
219
wake_join(&self)220 pub(crate) fn wake_join(&self) {
221 let waker = self.waker.get();
222 match unsafe { &*waker } {
223 Some(waker) => {
224 waker.wake_by_ref();
225 }
226 None => panic!("task waker has not been set"),
227 }
228 }
229 }
230
231 /// Manages task infos.
232 /// `repr(C)` is necessary because we cast a pointer of [`TaskMngInfo`] into a
233 /// pointer of [`Header`].
234 #[repr(C)]
235 pub(crate) struct TaskMngInfo<T: Future, S: Schedule> {
236 /// a pointer to the heap-allocated task
237 header: Header,
238 inner: Inner<T, S>,
239 }
240
run<T, S>(ptr: NonNull<Header>) -> bool where T: Future, S: Schedule,241 unsafe fn run<T, S>(ptr: NonNull<Header>) -> bool
242 where
243 T: Future,
244 S: Schedule,
245 {
246 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
247 task_handle.run();
248 true
249 }
250
schedule<T, S>(ptr: NonNull<Header>, flag: bool) where T: Future, S: Schedule,251 unsafe fn schedule<T, S>(ptr: NonNull<Header>, flag: bool)
252 where
253 T: Future,
254 S: Schedule,
255 {
256 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
257 if flag {
258 task_handle.wake();
259 } else {
260 task_handle.wake_by_ref();
261 }
262 }
263
get_result<T, S>(ptr: NonNull<Header>, res: *mut ()) where T: Future, S: Schedule,264 unsafe fn get_result<T, S>(ptr: NonNull<Header>, res: *mut ())
265 where
266 T: Future,
267 S: Schedule,
268 {
269 let out = &mut *(res as *mut Poll<Result<T::Output, ScheduleError>>);
270 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
271 task_handle.get_result(out);
272 }
273
drop_ref<T, S>(ptr: NonNull<Header>) where T: Future, S: Schedule,274 unsafe fn drop_ref<T, S>(ptr: NonNull<Header>)
275 where
276 T: Future,
277 S: Schedule,
278 {
279 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
280 task_handle.drop_ref();
281 }
282
set_waker<T, S>(ptr: NonNull<Header>, cur_state: usize, waker: *const ()) -> bool where T: Future, S: Schedule,283 unsafe fn set_waker<T, S>(ptr: NonNull<Header>, cur_state: usize, waker: *const ()) -> bool
284 where
285 T: Future,
286 S: Schedule,
287 {
288 let waker = &*(waker as *const Waker);
289 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
290 task_handle.set_waker(cur_state, waker)
291 }
292
drop_join_handle<T, S>(ptr: NonNull<Header>) where T: Future, S: Schedule,293 unsafe fn drop_join_handle<T, S>(ptr: NonNull<Header>)
294 where
295 T: Future,
296 S: Schedule,
297 {
298 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
299 task_handle.drop_join_handle();
300 }
301
302 #[cfg(not(feature = "ffrt"))]
release<T, S>(ptr: NonNull<Header>) where T: Future, S: Schedule,303 unsafe fn release<T, S>(ptr: NonNull<Header>)
304 where
305 T: Future,
306 S: Schedule,
307 {
308 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
309 task_handle.shutdown();
310 }
311
cancel<T, S>(ptr: NonNull<Header>) where T: Future, S: Schedule,312 unsafe fn cancel<T, S>(ptr: NonNull<Header>)
313 where
314 T: Future,
315 S: Schedule,
316 {
317 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
318 task_handle.set_canceled();
319 }
320
create_vtable<T, S>() -> &'static TaskVirtualTable where T: Future, S: Schedule,321 fn create_vtable<T, S>() -> &'static TaskVirtualTable
322 where
323 T: Future,
324 S: Schedule,
325 {
326 &TaskVirtualTable {
327 run: run::<T, S>,
328 schedule: schedule::<T, S>,
329 get_result: get_result::<T, S>,
330 drop_join_handle: drop_join_handle::<T, S>,
331 drop_ref: drop_ref::<T, S>,
332 set_waker: set_waker::<T, S>,
333 #[cfg(not(feature = "ffrt"))]
334 release: release::<T, S>,
335 cancel: cancel::<T, S>,
336 }
337 }
338
339 cfg_ffrt! {
340 unsafe fn ffrt_run<T, S>(ptr: NonNull<Header>) -> bool
341 where
342 T: Future,
343 S: Schedule,
344 {
345 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
346 task_handle.ffrt_run()
347 }
348
349 unsafe fn ffrt_schedule<T, S>(ptr: NonNull<Header>, flag: bool)
350 where
351 T: Future,
352 S: Schedule,
353 {
354 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
355 if flag {
356 task_handle.ffrt_wake();
357 } else {
358 task_handle.ffrt_wake_by_ref();
359 }
360 }
361
362 unsafe fn ffrt_cancel<T, S>(ptr: NonNull<Header>)
363 where
364 T: Future,
365 S: Schedule,
366 {
367 let task_handle = TaskHandle::<T, S>::from_raw(ptr);
368 task_handle.ffrt_set_canceled();
369 }
370
371 fn create_ffrt_vtable<T, S>() -> &'static TaskVirtualTable
372 where
373 T: Future,
374 S: Schedule,
375 {
376 &TaskVirtualTable {
377 run: ffrt_run::<T, S>,
378 schedule: ffrt_schedule::<T, S>,
379 get_result: get_result::<T, S>,
380 drop_join_handle: drop_join_handle::<T, S>,
381 drop_ref: drop_ref::<T, S>,
382 set_waker: set_waker::<T, S>,
383 cancel: ffrt_cancel::<T, S>,
384 }
385 }
386 }
387
388 impl<T, S> TaskMngInfo<T, S>
389 where
390 T: Future,
391 S: Schedule,
392 {
393 /// Creates non-stackful task info.
394 // TODO: builder information currently is not used yet. Might use in the future
395 // (e.g. qos), so keep it now.
new( _builder: &TaskBuilder, scheduler: Weak<S>, task: T, virtual_table_type: VirtualTableType, ) -> Box<Self>396 pub(crate) fn new(
397 _builder: &TaskBuilder,
398 scheduler: Weak<S>,
399 task: T,
400 virtual_table_type: VirtualTableType,
401 ) -> Box<Self> {
402 let vtable = match virtual_table_type {
403 VirtualTableType::Ylong => create_vtable::<T, S>(),
404 #[cfg(feature = "ffrt")]
405 VirtualTableType::Ffrt => create_ffrt_vtable::<T, S>(),
406 };
407 // Create the common header
408 let header = Header {
409 state: TaskState::new(),
410 vtable,
411 };
412 // Create task private info
413 let inner = Inner::<T, S>::new(task, scheduler);
414 // Allocate it onto the heap
415 Box::new(TaskMngInfo { header, inner })
416 }
417
header(&self) -> &Header418 pub(crate) fn header(&self) -> &Header {
419 &self.header
420 }
421
inner(&self) -> &Inner<T, S>422 pub(crate) fn inner(&self) -> &Inner<T, S> {
423 &self.inner
424 }
425 }
426