1 /* 2 * Copyright (C) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 use super::*; 17 18 extern crate ylong_runtime; 19 20 use std::future::Future; 21 use crate::is_handling_transaction; 22 use crate::errors::{IpcStatusCode}; 23 24 /// Use the Ylong `spawn_blocking` pool 25 pub enum Ylong {} 26 27 impl IpcAsyncPool for Ylong { spawn<'a, F1, F2, Fut, A, B>(spawn_this: F1, after_handle: F2) -> BoxFuture<'a, IpcResult<B>> where F1: FnOnce() -> A, F2: FnOnce(A) -> Fut, Fut: Future<Output = IpcResult<B>>, F1: Send + 'static, F2: Send + 'a, Fut: Send + 'a, A: Send + 'static, B: Send + 'a,28 fn spawn<'a, F1, F2, Fut, A, B>(spawn_this: F1, after_handle: F2) -> BoxFuture<'a, IpcResult<B>> 29 where 30 F1: FnOnce() -> A, 31 F2: FnOnce(A) -> Fut, 32 Fut: Future<Output = IpcResult<B>>, 33 F1: Send + 'static, 34 F2: Send + 'a, 35 Fut: Send + 'a, 36 A: Send + 'static, 37 B: Send + 'a, 38 { 39 if is_handling_transaction() { 40 // We are currently on the thread pool for a binder server, so we should execute the 41 // transaction on the current thread so that the binder kernel driver is able to apply 42 // its deadlock prevention strategy to the sub-call. 43 // 44 // This shouldn't cause issues with blocking the thread as only one task will run in a 45 // call to `block_on`, so there aren't other tasks to block. 46 let result = spawn_this(); 47 Box::pin(after_handle(result)) 48 } else { 49 let handle = Runtime::spawn_blocking(spawn_this); 50 Box::pin(async move { 51 // The `is_panic` branch is not actually reachable in OH as we compile 52 // with `panic = abort`. 53 match handle.await { 54 Ok(res) => after_handle(res).await, 55 Err(_) => Err(IpcStatusCode::Failed), 56 } 57 }) 58 } 59 } 60 } 61 62 /// Wrapper around Ylong runtime types for providing a runtime to a binder server. 63 pub struct Runtime; 64 65 impl IpcAsyncRuntime for Runtime { spawn<T, R>(task: T) -> JoinHandle<R> where T: Future<Output = R>, T: Send + 'static, R: Send + 'static,66 fn spawn<T, R>(task: T) -> JoinHandle<R> 67 where 68 T: Future<Output = R>, 69 T: Send + 'static, 70 R: Send + 'static, 71 { 72 ylong_runtime::spawn(task) 73 } 74 spawn_blocking<T, R>(task: T) -> JoinHandle<R> where T: FnOnce() -> R, T: Send + 'static, R: Send + 'static,75 fn spawn_blocking<T, R>(task: T) -> JoinHandle<R> 76 where 77 T: FnOnce() -> R, 78 T: Send + 'static, 79 R: Send + 'static, 80 { 81 ylong_runtime::spawn_blocking(task) 82 } 83 block_on<F: Future>(future: F) -> F::Output84 fn block_on<F: Future>(future: F) -> F::Output 85 { 86 ylong_runtime::block_on(future) 87 } 88 } 89 90