1f857971dSopenharmony_ci/*
2f857971dSopenharmony_ci * Copyright (C) 2023 Huawei Device Co., Ltd.
3f857971dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4f857971dSopenharmony_ci * you may not use this file except in compliance with the License.
5f857971dSopenharmony_ci * You may obtain a copy of the License at
6f857971dSopenharmony_ci *
7f857971dSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8f857971dSopenharmony_ci *
9f857971dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10f857971dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11f857971dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f857971dSopenharmony_ci * See the License for the specific language governing permissions and
13f857971dSopenharmony_ci * limitations under the License.
14f857971dSopenharmony_ci */
15f857971dSopenharmony_ci
16f857971dSopenharmony_ci//! Providing asynchronous task scheduling and epoll handling mechanism.
17f857971dSopenharmony_ci//!
18f857971dSopenharmony_ci//! Current implementation of task scheduler allow posted tasks to run concurrently,
19f857971dSopenharmony_ci//! so synchronization are necessary if they share some data.
20f857971dSopenharmony_ci//!
21f857971dSopenharmony_ci//! On creation of scheduler, an epoll instance is also created and event loop is
22f857971dSopenharmony_ci//! started. We see a (fd, events processing logic) pair as an event handler. When
23f857971dSopenharmony_ci//! an epoll handler is added, its fd is added to the interest list of the epoll
24f857971dSopenharmony_ci//! and is waited on for events. When events occured on its fd, scheduler will
25f857971dSopenharmony_ci//! dispatch events to it.
26f857971dSopenharmony_ci
27f857971dSopenharmony_ci#![allow(dead_code)]
28f857971dSopenharmony_ci#![allow(unused_variables)]
29f857971dSopenharmony_ci
30f857971dSopenharmony_ci/// Module declarations.
31f857971dSopenharmony_cimod scheduler;
32f857971dSopenharmony_cimod task;
33f857971dSopenharmony_ci
34f857971dSopenharmony_ci/// Public exports.
35f857971dSopenharmony_cipub use scheduler::IEpollHandler;
36f857971dSopenharmony_cipub use scheduler::{
37f857971dSopenharmony_ci    LIBC_EPOLLIN,
38f857971dSopenharmony_ci    LIBC_EPOLLERR,
39f857971dSopenharmony_ci    LIBC_EPOLLHUP,
40f857971dSopenharmony_ci};
41f857971dSopenharmony_cipub use task::TaskHandle;
42f857971dSopenharmony_ci
43f857971dSopenharmony_ciuse std::ffi::{ c_char, CString };
44f857971dSopenharmony_ciuse std::sync::Arc;
45f857971dSopenharmony_ciuse std::sync::atomic::{ AtomicUsize, Ordering };
46f857971dSopenharmony_ciuse std::time::Duration;
47f857971dSopenharmony_ciuse fusion_utils_rust::{call_debug_enter, FusionResult };
48f857971dSopenharmony_ciuse hilog_rust::{ hilog, HiLogLabel, LogType };
49f857971dSopenharmony_ciuse scheduler::Scheduler;
50f857971dSopenharmony_ci
51f857971dSopenharmony_ciconst LOG_LABEL: HiLogLabel = HiLogLabel {
52f857971dSopenharmony_ci    log_type: LogType::LogCore,
53f857971dSopenharmony_ci    domain: 0xD002220,
54f857971dSopenharmony_ci    tag: "Handler",
55f857971dSopenharmony_ci};
56f857971dSopenharmony_ci
57f857971dSopenharmony_ci/// Front-end of scheduler, providing interface for posting asynchronous task
58f857971dSopenharmony_ci/// and epoll handling.
59f857971dSopenharmony_cipub struct Handler {
60f857971dSopenharmony_ci    id: usize,
61f857971dSopenharmony_ci    scheduler: Arc<Scheduler>,
62f857971dSopenharmony_ci}
63f857971dSopenharmony_ci
64f857971dSopenharmony_ciimpl Handler {
65f857971dSopenharmony_ci    /// Construct a new instance of `Handler`.
66f857971dSopenharmony_ci    pub fn new() -> Self
67f857971dSopenharmony_ci    {
68f857971dSopenharmony_ci        static ID_RADIX: AtomicUsize = AtomicUsize::new(1);
69f857971dSopenharmony_ci        let scheduler = Arc::new(Scheduler::new());
70f857971dSopenharmony_ci
71f857971dSopenharmony_ci        Self {
72f857971dSopenharmony_ci            id: ID_RADIX.fetch_add(1, Ordering::Relaxed),
73f857971dSopenharmony_ci            scheduler,
74f857971dSopenharmony_ci        }
75f857971dSopenharmony_ci    }
76f857971dSopenharmony_ci
77f857971dSopenharmony_ci    /// Return the unique identifier of this `Handler`.
78f857971dSopenharmony_ci    pub fn id(&self) -> usize
79f857971dSopenharmony_ci    {
80f857971dSopenharmony_ci        self.id
81f857971dSopenharmony_ci    }
82f857971dSopenharmony_ci
83f857971dSopenharmony_ci    /// Schedudle a `synchronous` executing task, and return the result.
84f857971dSopenharmony_ci    pub fn post_sync_task<F, R>(&self, task: F) -> R
85f857971dSopenharmony_ci    where
86f857971dSopenharmony_ci        F: Fn() -> R + Send + 'static,
87f857971dSopenharmony_ci        R: Send + 'static,
88f857971dSopenharmony_ci    {
89f857971dSopenharmony_ci        call_debug_enter!("Handler::post_sync_task");
90f857971dSopenharmony_ci        ylong_runtime::block_on(async move {
91f857971dSopenharmony_ci            task()
92f857971dSopenharmony_ci        })
93f857971dSopenharmony_ci    }
94f857971dSopenharmony_ci
95f857971dSopenharmony_ci    /// Scheduling an asynchronous task.
96f857971dSopenharmony_ci    ///
97f857971dSopenharmony_ci    /// Calling `TaskHandle::result` to get the result of the task. Calling
98f857971dSopenharmony_ci    /// `TaskHandle::result` will block current thread until the task finish.
99f857971dSopenharmony_ci    ///
100f857971dSopenharmony_ci    /// Calling `TaskHandle::cancel` to cancel the posted task before it finish.
101f857971dSopenharmony_ci    ///
102f857971dSopenharmony_ci    /// # Examples
103f857971dSopenharmony_ci    ///
104f857971dSopenharmony_ci    /// ```
105f857971dSopenharmony_ci    /// let handler = Handler::new();
106f857971dSopenharmony_ci    /// let param: usize = 0xAB1807;
107f857971dSopenharmony_ci    ///
108f857971dSopenharmony_ci    /// let mut task_handle = handler.post_async_task(move || {
109f857971dSopenharmony_ci    ///     hash(param)
110f857971dSopenharmony_ci    /// }
111f857971dSopenharmony_ci    /// let ret = task_handle.result().unwrap();
112f857971dSopenharmony_ci    /// let expected = hash(param);
113f857971dSopenharmony_ci    /// assert_eq!(ret, expected);
114f857971dSopenharmony_ci    /// ```
115f857971dSopenharmony_ci    ///
116f857971dSopenharmony_ci    pub fn post_async_task<F, R>(&self, task: F) -> TaskHandle<R>
117f857971dSopenharmony_ci    where
118f857971dSopenharmony_ci        F: Fn() -> R + Send + 'static,
119f857971dSopenharmony_ci        R: Send + 'static,
120f857971dSopenharmony_ci    {
121f857971dSopenharmony_ci        call_debug_enter!("Handler::post_async_task");
122f857971dSopenharmony_ci        let handle = ylong_runtime::spawn(async move {
123f857971dSopenharmony_ci            task()
124f857971dSopenharmony_ci        });
125f857971dSopenharmony_ci        TaskHandle::from(handle)
126f857971dSopenharmony_ci    }
127f857971dSopenharmony_ci
128f857971dSopenharmony_ci    /// Schedule an asynchronous task that will run after a period of `delay`.
129f857971dSopenharmony_ci    ///
130f857971dSopenharmony_ci    /// Calling `TaskHandle::cancel` to cancel the posted task before it finish.
131f857971dSopenharmony_ci    ///
132f857971dSopenharmony_ci    pub fn post_delayed_task<F, R>(&self, task: F, delay: Duration) -> TaskHandle<R>
133f857971dSopenharmony_ci    where
134f857971dSopenharmony_ci        F: Fn() -> R + Send + 'static,
135f857971dSopenharmony_ci        R: Send + 'static,
136f857971dSopenharmony_ci    {
137f857971dSopenharmony_ci        call_debug_enter!("Handler::post_delayed_task");
138f857971dSopenharmony_ci        let handle = ylong_runtime::spawn(async move {
139f857971dSopenharmony_ci            ylong_runtime::time::sleep(delay).await;
140f857971dSopenharmony_ci            task()
141f857971dSopenharmony_ci        });
142f857971dSopenharmony_ci        TaskHandle::from(handle)
143f857971dSopenharmony_ci    }
144f857971dSopenharmony_ci
145f857971dSopenharmony_ci    /// Schedule an asynchronous task that will run repeatedly with set interval
146f857971dSopenharmony_ci    /// after a period of time.
147f857971dSopenharmony_ci    ///
148f857971dSopenharmony_ci    /// The posted task will start to run after a period of `delay` if `delay` is not None.
149f857971dSopenharmony_ci    /// It will repeat for `repeat` times with `interval` between each running. If `repeat`
150f857971dSopenharmony_ci    /// is None, the posted task will repeat forever.
151f857971dSopenharmony_ci    ///
152f857971dSopenharmony_ci    /// Calling `TaskHandle::cancel` to cancel the posted task before it finish.
153f857971dSopenharmony_ci    ///
154f857971dSopenharmony_ci    pub fn post_perioric_task<F>(&self, task: F, delay: Option<Duration>, interval: Duration,
155f857971dSopenharmony_ci                                 repeat: Option<usize>) -> TaskHandle<()>
156f857971dSopenharmony_ci    where
157f857971dSopenharmony_ci        F: Fn() + Send + 'static
158f857971dSopenharmony_ci    {
159f857971dSopenharmony_ci        call_debug_enter!("Handler::post_perioric_task");
160f857971dSopenharmony_ci        let handle = ylong_runtime::spawn(async move {
161f857971dSopenharmony_ci            if let Some(d) = delay {
162f857971dSopenharmony_ci                ylong_runtime::time::sleep(d).await;
163f857971dSopenharmony_ci            }
164f857971dSopenharmony_ci            ylong_runtime::time::periodic_schedule(task, repeat, interval).await;
165f857971dSopenharmony_ci        });
166f857971dSopenharmony_ci        TaskHandle::from(handle)
167f857971dSopenharmony_ci    }
168f857971dSopenharmony_ci
169f857971dSopenharmony_ci    /// Schedule an asynchronous task that may block. That is, it may take a huge time to
170f857971dSopenharmony_ci    /// finish, or may block for resources.
171f857971dSopenharmony_ci    ///
172f857971dSopenharmony_ci    /// Calling `TaskHandle::cancel` to cancel the posted task before it finish.
173f857971dSopenharmony_ci    ///
174f857971dSopenharmony_ci    pub fn post_blocking_task<F, R>(&self, task: F) -> TaskHandle<R>
175f857971dSopenharmony_ci    where
176f857971dSopenharmony_ci        F: Fn() -> R + Send + 'static,
177f857971dSopenharmony_ci        R: Send + 'static,
178f857971dSopenharmony_ci    {
179f857971dSopenharmony_ci        call_debug_enter!("Handler::post_delayed_task");
180f857971dSopenharmony_ci        let handle = ylong_runtime::spawn_blocking(task);
181f857971dSopenharmony_ci        TaskHandle::from(handle)
182f857971dSopenharmony_ci    }
183f857971dSopenharmony_ci
184f857971dSopenharmony_ci    /// Add an epoll handler to epoll event loop.
185f857971dSopenharmony_ci    ///
186f857971dSopenharmony_ci    /// Note that we call a (fd, events processing logic) pair an event handler.
187f857971dSopenharmony_ci    ///
188f857971dSopenharmony_ci    /// # Examples
189f857971dSopenharmony_ci    ///
190f857971dSopenharmony_ci    /// ```
191f857971dSopenharmony_ci    /// struct EpollHandler {
192f857971dSopenharmony_ci    /// //  data members.
193f857971dSopenharmony_ci    /// }
194f857971dSopenharmony_ci    ///
195f857971dSopenharmony_ci    /// impl IEpollHandler for EpollHandler {
196f857971dSopenharmony_ci    ///     fn fd(&self) -> RawFd {
197f857971dSopenharmony_ci    ///         // Return fd of this epoll handler.
198f857971dSopenharmony_ci    ///     }
199f857971dSopenharmony_ci    ///
200f857971dSopenharmony_ci    ///     fn dispatch(&self, events: u32) {
201f857971dSopenharmony_ci    ///         // Process events.
202f857971dSopenharmony_ci    ///     }
203f857971dSopenharmony_ci    /// }
204f857971dSopenharmony_ci    ///
205f857971dSopenharmony_ci    /// let handler: Arc<Handler> = Arc::default();
206f857971dSopenharmony_ci    /// let epoll_handler = Arc::new(EpollHandler::new());
207f857971dSopenharmony_ci    /// handler.add_epoll_handler(epoll_handler)
208f857971dSopenharmony_ci    /// ```
209f857971dSopenharmony_ci    pub fn add_epoll_handler(&self, handler: Arc<dyn IEpollHandler>)
210f857971dSopenharmony_ci        -> FusionResult<Arc<dyn IEpollHandler>>
211f857971dSopenharmony_ci    {
212f857971dSopenharmony_ci        call_debug_enter!("Handler::add_epoll_handler");
213f857971dSopenharmony_ci        self.scheduler.add_epoll_handler(handler)
214f857971dSopenharmony_ci    }
215f857971dSopenharmony_ci
216f857971dSopenharmony_ci    /// Remove an epoll handler from epoll event loop.
217f857971dSopenharmony_ci    pub fn remove_epoll_handler(&self, handler: Arc<dyn IEpollHandler>)
218f857971dSopenharmony_ci        -> FusionResult<Arc<dyn IEpollHandler>>
219f857971dSopenharmony_ci    {
220f857971dSopenharmony_ci        call_debug_enter!("Handler::remove_epoll_handler");
221f857971dSopenharmony_ci        self.scheduler.remove_epoll_handler(handler)
222f857971dSopenharmony_ci    }
223f857971dSopenharmony_ci}
224f857971dSopenharmony_ci
225f857971dSopenharmony_ciimpl Default for Handler {
226f857971dSopenharmony_ci    fn default() -> Self
227f857971dSopenharmony_ci    {
228f857971dSopenharmony_ci        Self::new()
229f857971dSopenharmony_ci    }
230f857971dSopenharmony_ci}
231