Implement start/finish waiting for gpui2

Conrad Irwin created

I'm not sure these are strictly necessary, but it will make porting
tests easier to have them.

Change summary

crates/gpui2/src/executor.rs                 | 11 ++++++++---
crates/gpui2/src/platform/test/dispatcher.rs | 18 ++++++++++++++++++
2 files changed, 26 insertions(+), 3 deletions(-)

Detailed changes

crates/gpui2/src/executor.rs 🔗

@@ -161,7 +161,12 @@ impl Executor {
                         #[cfg(any(test, feature = "test-support"))]
                         if let Some(test) = self.dispatcher.as_test() {
                             if !test.parking_allowed() {
-                                panic!("blocked with nothing left to run")
+                                let mut backtrace_message = String::new();
+                                if let Some(backtrace) = test.waiting_backtrace() {
+                                    backtrace_message =
+                                        format!("\nbacktrace of waiting future:\n{:?}", backtrace);
+                                }
+                                panic!("parked with nothing left to run\n{:?}", backtrace_message)
                             }
                         }
                         parker.park();
@@ -220,12 +225,12 @@ impl Executor {
 
     #[cfg(any(test, feature = "test-support"))]
     pub fn start_waiting(&self) {
-        todo!("start_waiting")
+        self.dispatcher.as_test().unwrap().start_waiting();
     }
 
     #[cfg(any(test, feature = "test-support"))]
     pub fn finish_waiting(&self) {
-        todo!("finish_waiting")
+        self.dispatcher.as_test().unwrap().finish_waiting();
     }
 
     #[cfg(any(test, feature = "test-support"))]

crates/gpui2/src/platform/test/dispatcher.rs 🔗

@@ -1,5 +1,6 @@
 use crate::PlatformDispatcher;
 use async_task::Runnable;
+use backtrace::Backtrace;
 use collections::{HashMap, VecDeque};
 use parking_lot::Mutex;
 use rand::prelude::*;
@@ -29,6 +30,7 @@ struct TestDispatcherState {
     is_main_thread: bool,
     next_id: TestDispatcherId,
     allow_parking: bool,
+    waiting_backtrace: Option<Backtrace>,
 }
 
 impl TestDispatcher {
@@ -42,6 +44,7 @@ impl TestDispatcher {
             is_main_thread: true,
             next_id: TestDispatcherId(1),
             allow_parking: false,
+            waiting_backtrace: None,
         };
 
         TestDispatcher {
@@ -103,6 +106,21 @@ impl TestDispatcher {
     pub fn allow_parking(&self) {
         self.state.lock().allow_parking = true
     }
+
+    pub fn start_waiting(&self) {
+        self.state.lock().waiting_backtrace = Some(Backtrace::new_unresolved());
+    }
+
+    pub fn finish_waiting(&self) {
+        self.state.lock().waiting_backtrace.take();
+    }
+
+    pub fn waiting_backtrace(&self) -> Option<Backtrace> {
+        self.state.lock().waiting_backtrace.take().map(|mut b| {
+            b.resolve();
+            b
+        })
+    }
 }
 
 impl Clone for TestDispatcher {