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