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