• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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