bool await(const process::Future<T>& future, const Duration& duration) { if (!process::Clock::paused()) { return future.await(duration); } // If the clock is paused, no new timers will expire. // Future::await(duration) may hang forever because it depends on // a timer to expire after 'duration'. We instead ensure all // expired timers are flushed and check if the future is satisfied. Stopwatch stopwatch; stopwatch.start(); // Settle to make sure all expired timers are executed (not // necessarily finished, see below). process::Clock::settle(); while (future.isPending() && stopwatch.elapsed() < duration) { // Synchronous operations and asynchronous process::Process // operations should finish when the above 'settle()' returns. // Other types of async operations such as io::write() may not. // Therefore we wait the specified duration for it to complete. // Note that nothing prevents the operations to schedule more // timeouts for some time in the future. These timeouts will // never be executed due to the paused process::Clock. In this // case we return after the stopwatch (system clock) runs out. os::sleep(Milliseconds(10)); } return !future.isPending(); }
Option<Error> _check_failed(const process::Future<T>& f) { if (f.isPending()) { return Some("is PENDING"); } else if (f.isReady()) { return Some("is READY"); } else if (f.isDiscarded()) { return Some("is DISCARDED"); } else { CHECK(f.isFailed()); return None(); } }
Option<Error> _check_discarded(const process::Future<T>& f) { if (f.isPending()) { return Error("is PENDING"); } else if (f.isReady()) { return Error("is READY"); } else if (f.isFailed()) { return Error("is FAILED: " + f.failure()); } else { CHECK(f.isDiscarded()); return None(); } }