1use std::future::Future;
2
3use gpui::{App, AppContext, Global, ReadGlobal, Task};
4use util::defer;
5
6pub use tokio::task::JoinError;
7
8pub fn init(cx: &mut App) {
9 cx.set_global(GlobalTokio::new());
10}
11
12struct GlobalTokio {
13 runtime: tokio::runtime::Runtime,
14}
15
16impl Global for GlobalTokio {}
17
18impl GlobalTokio {
19 fn new() -> Self {
20 let runtime = tokio::runtime::Builder::new_multi_thread()
21 // Since we now have two executors, let's try to keep our footprint small
22 .worker_threads(2)
23 .enable_all()
24 .build()
25 .expect("Failed to initialize Tokio");
26
27 Self { runtime }
28 }
29}
30
31pub struct Tokio {}
32
33impl Tokio {
34 /// Spawns the given future on Tokio's thread pool, and returns it via a GPUI task
35 /// Note that the Tokio task will be cancelled if the GPUI task is dropped
36 pub fn spawn<C, Fut, R>(cx: &C, f: Fut) -> C::Result<Task<Result<R, JoinError>>>
37 where
38 C: AppContext,
39 Fut: Future<Output = R> + Send + 'static,
40 R: Send + 'static,
41 {
42 cx.read_global(|tokio: &GlobalTokio, cx| {
43 let join_handle = tokio.runtime.spawn(f);
44 let abort_handle = join_handle.abort_handle();
45 let cancel = defer(move || {
46 abort_handle.abort();
47 });
48 cx.background_spawn(async move {
49 let result = join_handle.await;
50 drop(cancel);
51 result
52 })
53 })
54 }
55
56 /// Spawns the given future on Tokio's thread pool, and returns it via a GPUI task
57 /// Note that the Tokio task will be cancelled if the GPUI task is dropped
58 pub fn spawn_result<C, Fut, R>(cx: &C, f: Fut) -> C::Result<Task<anyhow::Result<R>>>
59 where
60 C: AppContext,
61 Fut: Future<Output = anyhow::Result<R>> + Send + 'static,
62 R: Send + 'static,
63 {
64 cx.read_global(|tokio: &GlobalTokio, cx| {
65 let join_handle = tokio.runtime.spawn(f);
66 let abort_handle = join_handle.abort_handle();
67 let cancel = defer(move || {
68 abort_handle.abort();
69 });
70 cx.background_spawn(async move {
71 let result = join_handle.await?;
72 drop(cancel);
73 result
74 })
75 })
76 }
77
78 pub fn handle(cx: &App) -> tokio::runtime::Handle {
79 GlobalTokio::global(cx).runtime.handle().clone()
80 }
81}