| Index: mojo/public/rust/src/bindings/run_loop.rs
|
| diff --git a/mojo/public/rust/src/bindings/run_loop.rs b/mojo/public/rust/src/bindings/run_loop.rs
|
| deleted file mode 100644
|
| index 754694ed3d2d4d94def3b4a39c1bc255375ef53e..0000000000000000000000000000000000000000
|
| --- a/mojo/public/rust/src/bindings/run_loop.rs
|
| +++ /dev/null
|
| @@ -1,672 +0,0 @@
|
| -// Copyright 2016 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -//! This module contains a thread-local run-loop.
|
| -//!
|
| -//! The run-loop may have handles and handlers pre-registers
|
| -//! (and in fact, must) in order to keep running. The run-loop
|
| -//! executes until it has no more handles or handlers on itself,
|
| -//! or until it is told to quit via stop().
|
| -//!
|
| -//! The run-loop waits until some signals on some handle is satisfied,
|
| -//! at which point it wakes up and executes the appropriate handler
|
| -//! method. This handler method may then be used to further populate
|
| -//! or de-populate the run-loop.
|
| -//!
|
| -//! As of yet, the run-loop is NOT thread-safe. Although it is useful
|
| -//! to be able to register tasks or handles from one thread onto
|
| -//! another thread's run-loop, this is as-of-yet unsupported, and
|
| -//! Rust should complain loudly when you try to do any threading here.
|
| -
|
| -use std::cell::RefCell;
|
| -use std::cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
|
| -use std::collections::BinaryHeap;
|
| -use std::collections::HashMap;
|
| -use std::i64;
|
| -use std::u32;
|
| -use std::vec::Vec;
|
| -
|
| -use system;
|
| -use system::{Handle, MOJO_INDEFINITE, MojoResult};
|
| -use system::core;
|
| -use system::wait_set;
|
| -
|
| -/// Define the equivalent of MOJO_INDEFINITE for absolute deadlines
|
| -const MOJO_INDEFINITE_ABSOLUTE: system::MojoTimeTicks = 0;
|
| -
|
| -// TODO(mknyszek): The numbers below are arbitrary and come from the C++ bindings,
|
| -// and should probably be changed at some point
|
| -
|
| -/// Initial size of the result buffer.
|
| -const INITIAL_WAIT_SET_NUM_RESULTS: usize = 16;
|
| -
|
| -/// Maximum size of the result buffer.
|
| -const MAXIMUM_WAIT_SET_NUM_RESULTS: usize = 256;
|
| -
|
| -/// Thread-local data structure for keeping track of handles to wait on.
|
| -thread_local!(static TL_RUN_LOOP: RefCell<RunLoop<'static, 'static>> = RefCell::new(RunLoop::new()));
|
| -
|
| -/// Token representing handle/callback to wait on for this thread only. This
|
| -/// token only has meaning on the thread in which the handle was registered.
|
| -#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
| -pub struct Token(u64);
|
| -
|
| -impl Token {
|
| - /// Get the wait token's "cookie" form, suitable for use in a wait set.
|
| - fn as_cookie(&self) -> u64 {
|
| - self.0
|
| - }
|
| -}
|
| -
|
| -/// Represents the possible error cases that may occur when waiting
|
| -/// on a handle in a RunLoop.
|
| -#[derive(Clone, Debug, PartialEq, Eq)]
|
| -pub enum WaitError {
|
| - /// The handle has been closed or is otherwise no longer valid.
|
| - HandleClosed,
|
| -
|
| - /// The handle is currently busy in some transaction.
|
| - HandleBusy,
|
| -
|
| - /// It has been determined that the signals provided will never
|
| - /// be satisfied for this handle.
|
| - Unsatisfiable,
|
| -}
|
| -
|
| -/// A trait which defines an interface to be a handler usable by
|
| -/// a RunLoop.
|
| -pub trait Handler {
|
| - /// Called after a successful wait.
|
| - fn on_ready(&mut self, runloop: &mut RunLoop, token: Token);
|
| -
|
| - /// Called after the given deadline expires.
|
| - fn on_timeout(&mut self, runloop: &mut RunLoop, token: Token);
|
| -
|
| - /// Called when an unexpected error occurs.
|
| - fn on_error(&mut self, runloop: &mut RunLoop, token: Token, error: WaitError);
|
| -}
|
| -
|
| -/// A wrapper struct for carrying the handler as well as various information
|
| -/// about it.
|
| -struct HandlerInfo<'h> {
|
| - /// The handle for which we are waiting.
|
| - ///
|
| - /// We keep this handle around so that we may easily re-register.
|
| - handle: system::MojoHandle,
|
| -
|
| - /// The handler, boxed up.
|
| - ///
|
| - /// The handler is in an Option type because if it is currently being
|
| - /// used in a callback, we must take ownership to avoid mutability
|
| - /// cycles. The easiest way to do this is to take() from the Option then
|
| - /// put it back.
|
| - handler: Option<Box<Handler + 'h>>,
|
| -
|
| - /// An absolute deadline in terms of time ticks.
|
| - ///
|
| - /// This is the most recently updated deadline that
|
| - /// we should be watching out for. All others for this
|
| - /// token may be considered "stale".
|
| - deadline: system::MojoTimeTicks,
|
| -}
|
| -
|
| -impl<'h> HandlerInfo<'h> {
|
| - /// Take the handler out of its Option type.
|
| - pub fn take(&mut self) -> Option<Box<Handler + 'h>> {
|
| - self.handler.take()
|
| - }
|
| -
|
| - /// Put a new handler into the Option type.
|
| - pub fn give(&mut self, handler: Box<Handler + 'h>) {
|
| - self.handler = Some(handler);
|
| - }
|
| -
|
| - /// Getter for the system::MojoHandle held inside.
|
| - pub fn handle(&self) -> system::MojoHandle {
|
| - self.handle
|
| - }
|
| -
|
| - /// Getter for the current absolute deadline held inside.
|
| - pub fn deadline(&self) -> system::MojoTimeTicks {
|
| - self.deadline
|
| - }
|
| -
|
| - /// Setter to update the current absolute deadline.
|
| - pub fn set_deadline(&mut self, deadline: system::MojoTimeTicks) {
|
| - self.deadline = deadline
|
| - }
|
| -}
|
| -
|
| -/// A wrapper struct for carrying the task as well as some information about
|
| -/// it.
|
| -struct TaskInfo<'t> {
|
| - /// The task, boxed up.
|
| - closure: Box<FnMut(&mut RunLoop) + 't>,
|
| -
|
| - /// An absolute deadline in terms of time ticks.
|
| - ///
|
| - /// This is the most recently updated deadline that
|
| - /// we should be watching out for. All others for this
|
| - /// token may be considered "stale".
|
| - deadline: system::MojoTimeTicks,
|
| -}
|
| -
|
| -impl<'t> TaskInfo<'t> {
|
| - /// Executes the task within the info object, consuming it
|
| - /// in the process.
|
| - pub fn execute_task(mut self, run_loop: &mut RunLoop) {
|
| - (*self.closure)(run_loop);
|
| - }
|
| -
|
| - /// Getter for the current absolute deadline held inside.
|
| - pub fn deadline(&self) -> system::MojoTimeTicks {
|
| - self.deadline
|
| - }
|
| -}
|
| -
|
| -impl<'t> PartialEq for TaskInfo<'t> {
|
| - /// Equality for TaskInfo in terms of its deadline
|
| - fn eq(&self, other: &TaskInfo) -> bool {
|
| - self.deadline == other.deadline
|
| - }
|
| -}
|
| -
|
| -impl<'t> Eq for TaskInfo<'t> {}
|
| -
|
| -impl<'t> PartialOrd for TaskInfo<'t> {
|
| - /// Partial comparison for TaskInfo in terms of its deadline
|
| - ///
|
| - /// Reverses the comparison because the Rust std library only
|
| - /// offers a max-heap, and we need a min-heap.
|
| - fn partial_cmp(&self, other: &TaskInfo) -> Option<Ordering> {
|
| - other.deadline.partial_cmp(&self.deadline)
|
| - }
|
| -}
|
| -
|
| -impl<'t> Ord for TaskInfo<'t> {
|
| - /// Implement comparisons for Task Info.
|
| - ///
|
| - /// Reverses the comparison because the Rust std library only
|
| - /// offers a max-heap, and we need a min-heap.
|
| - fn cmp(&self, other: &Self) -> Ordering {
|
| - other.deadline.cmp(&self.deadline)
|
| - }
|
| -}
|
| -
|
| -/// Wrapper struct intended to be used in a priority queue
|
| -/// for efficiently retrieving the next closest deadline.
|
| -#[derive(Clone)]
|
| -struct DeadlineInfo {
|
| - /// The ID of the associated Handler struct in the RunLoop's
|
| - /// hash map.
|
| - token: Token,
|
| -
|
| - /// An absolute deadline in terms of time ticks.
|
| - deadline: system::MojoTimeTicks,
|
| -}
|
| -
|
| -impl DeadlineInfo {
|
| - /// Getter for an immutable borrow for the token inside.
|
| - pub fn token(&self) -> &Token {
|
| - &self.token
|
| - }
|
| -
|
| - /// Getter for the absolute deadline inside.
|
| - pub fn deadline(&self) -> system::MojoTimeTicks {
|
| - self.deadline
|
| - }
|
| -}
|
| -
|
| -impl PartialEq for DeadlineInfo {
|
| - /// Equality for DeadlineInfo in terms of its deadline
|
| - fn eq(&self, other: &DeadlineInfo) -> bool {
|
| - self.deadline == other.deadline
|
| - }
|
| -}
|
| -
|
| -impl Eq for DeadlineInfo {}
|
| -
|
| -impl PartialOrd for DeadlineInfo {
|
| - /// Partial comparison for DeadlineInfo in terms of its deadline
|
| - ///
|
| - /// Reverses the comparison because the Rust std library only
|
| - /// offers a max-heap, and we need a min-heap.
|
| - fn partial_cmp(&self, other: &DeadlineInfo) -> Option<Ordering> {
|
| - other.deadline.partial_cmp(&self.deadline)
|
| - }
|
| -}
|
| -
|
| -impl Ord for DeadlineInfo {
|
| - /// Implement comparisons for Deadline Info.
|
| - ///
|
| - /// Reverses the comparison because the Rust std library only
|
| - /// offers a max-heap, and we need a min-heap.
|
| - fn cmp(&self, other: &Self) -> Ordering {
|
| - other.deadline.cmp(&self.deadline)
|
| - }
|
| -}
|
| -
|
| -/// Convert a mojo deadline (which is a relative deadline to "now") to
|
| -/// an absolute deadline based on time ticks.
|
| -fn absolute_deadline(deadline: system::MojoDeadline) -> system::MojoTimeTicks {
|
| - if deadline == MOJO_INDEFINITE {
|
| - return MOJO_INDEFINITE_ABSOLUTE;
|
| - }
|
| - let mut converted = MOJO_INDEFINITE_ABSOLUTE;
|
| - let max_time_ticks = i64::MAX as system::MojoDeadline;
|
| - if deadline <= max_time_ticks {
|
| - let now = core::get_time_ticks_now();
|
| - if deadline <= (max_time_ticks - (now as u64)) {
|
| - converted = (deadline as system::MojoTimeTicks) + now
|
| - }
|
| - }
|
| - converted
|
| -}
|
| -
|
| -/// Convert an absolute deadline to a mojo deadline which is relative to some
|
| -/// notion of "now".
|
| -///
|
| -/// If the deadline is earlier than "now", this routine rounds up to "now".
|
| -fn relative_deadline(deadline: system::MojoTimeTicks,
|
| - now: system::MojoTimeTicks)
|
| - -> system::MojoDeadline {
|
| - if deadline == MOJO_INDEFINITE_ABSOLUTE {
|
| - MOJO_INDEFINITE
|
| - } else if now >= deadline {
|
| - 0
|
| - } else {
|
| - (deadline - now) as system::MojoDeadline
|
| - }
|
| -}
|
| -
|
| -/// This structure contains all information necessary to wait on handles
|
| -/// asynchronously.
|
| -///
|
| -/// Ultimately, it should only be a singleton living in
|
| -/// thread-local storage.
|
| -pub struct RunLoop<'h, 't> {
|
| - /// Running count of the next available token slot.
|
| - token_count: u64,
|
| -
|
| - /// A map of handlers.
|
| - ///
|
| - /// TODO(mknyszek): Try out a Slab allocator instead of a hashmap.
|
| - handlers: HashMap<Token, HandlerInfo<'h>>,
|
| -
|
| - /// A min-heap of delayed tasks in order to pull the soonest task to
|
| - /// execute efficiently.
|
| - tasks: BinaryHeap<TaskInfo<'t>>,
|
| -
|
| - /// A min-heap containing deadlines in order to pull out the soonest
|
| - /// deadline efficiently.
|
| - ///
|
| - /// Warning: may contain "stale" deadlines which are not kept in the
|
| - /// map!
|
| - deadlines: BinaryHeap<DeadlineInfo>,
|
| -
|
| - /// The Mojo structure keeping track of handles and signals.
|
| - ///
|
| - /// This structure must be kept in sync with handlers.
|
| - handle_set: wait_set::WaitSet,
|
| -
|
| - /// A flag that tells the RunLoop whether it should quit.
|
| - should_quit: bool,
|
| -
|
| - /// A flag that indicates whether the RunLoop is running or now
|
| - running: bool,
|
| -}
|
| -
|
| -impl<'h, 't> RunLoop<'h, 't> {
|
| - /// Create a new RunLoop.
|
| - pub fn new() -> RunLoop<'h, 't> {
|
| - RunLoop {
|
| - token_count: 0,
|
| - handlers: HashMap::new(),
|
| - tasks: BinaryHeap::new(),
|
| - deadlines: BinaryHeap::new(),
|
| - handle_set: wait_set::WaitSet::new(wsflags!(Create::None)).unwrap(),
|
| - should_quit: false,
|
| - running: false,
|
| - }
|
| - }
|
| -
|
| - /// Generate a new Token for this RunLoop
|
| - fn generate_token(&mut self) -> Token {
|
| - self.token_count = self.token_count.wrapping_add(1);
|
| - Token(self.token_count)
|
| - }
|
| -
|
| - /// Adds a new entry to the runloop queue.
|
| - pub fn register<H>(&mut self,
|
| - handle: &Handle,
|
| - signals: system::HandleSignals,
|
| - deadline: system::MojoDeadline,
|
| - handler: H)
|
| - -> Token
|
| - where H: Handler + 'h
|
| - {
|
| -
|
| - let token = self.generate_token();
|
| - let abs_deadline = absolute_deadline(deadline);
|
| - self.handle_set.add(handle, signals, token.as_cookie(), wsflags!(Add::None));
|
| - self.deadlines.push(DeadlineInfo {
|
| - token: token.clone(),
|
| - deadline: abs_deadline,
|
| - });
|
| - debug_assert!(!self.handlers.contains_key(&token));
|
| - self.handlers.insert(token.clone(),
|
| - HandlerInfo {
|
| - handle: handle.get_native_handle(),
|
| - handler: Some(Box::new(handler)),
|
| - deadline: abs_deadline,
|
| - });
|
| - token
|
| - }
|
| -
|
| - /// Updates the signals and deadline of an existing handler in the
|
| - /// runloop via token. The token remains unchanged and valid.
|
| - ///
|
| - /// Returns true on a successful update and false if the token was not
|
| - /// found.
|
| - pub fn reregister(&mut self,
|
| - token: &Token,
|
| - signals: system::HandleSignals,
|
| - deadline: system::MojoDeadline)
|
| - -> bool {
|
| -
|
| - match self.handlers.get_mut(&token) {
|
| - Some(info) => {
|
| - let _result = self.handle_set.remove(token.as_cookie());
|
| - debug_assert_eq!(_result, MojoResult::Okay);
|
| - let abs_deadline = absolute_deadline(deadline);
|
| - // Update what deadline we should be looking for, rendering
|
| - // all previously set deadlines "stale".
|
| - info.set_deadline(abs_deadline);
|
| - // Add a new deadline
|
| - self.deadlines.push(DeadlineInfo {
|
| - token: token.clone(),
|
| - deadline: abs_deadline,
|
| - });
|
| - // Acquire the raw handle held by the HandlerInfo in order to
|
| - // call the wait_set's add method. Invalidate it immediately after
|
| - // in order to prevent the handle from being closed.
|
| - //
|
| - // It's perfectly okay for the handle to be invalid, so although this
|
| - // is all unsafe, the whole system should just call the handler with an
|
| - // error.
|
| - let mut dummy = unsafe { system::acquire(info.handle()) };
|
| - self.handle_set.add(&dummy, signals, token.as_cookie(), wsflags!(Add::None));
|
| - unsafe {
|
| - dummy.invalidate();
|
| - }
|
| - true
|
| - }
|
| - None => false,
|
| - }
|
| - }
|
| -
|
| - /// Removes an entry from the runloop.
|
| - ///
|
| - /// Since we cannot remove from the deadlines heap, we just leave the deadline
|
| - /// in there as "stale", and we handle those when trying to find the next closest
|
| - /// deadline.
|
| - pub fn deregister(&mut self, token: Token) -> bool {
|
| - match self.handlers.remove(&token) {
|
| - Some(_) => {
|
| - let _result = self.handle_set.remove(token.as_cookie());
|
| - debug_assert_eq!(_result, MojoResult::Okay);
|
| - true
|
| - }
|
| - None => false,
|
| - }
|
| - }
|
| -
|
| - /// Adds a task to be run by the runloop after some delay.
|
| - ///
|
| - /// Returns a token if the delay is valid, otherwise returns None.
|
| - pub fn post_task<F>(&mut self, task: F, delay: system::MojoTimeTicks) -> Result<(), ()>
|
| - where F: FnMut(&mut RunLoop) + 't
|
| - {
|
| - let now = core::get_time_ticks_now();
|
| - if delay > i64::MAX - now {
|
| - return Err(());
|
| - }
|
| - let deadline = now + delay;
|
| - self.tasks.push(TaskInfo {
|
| - closure: Box::new(task),
|
| - deadline: deadline,
|
| - });
|
| - Ok(())
|
| - }
|
| -
|
| - /// Uses the binary heaps to get the next closest deadline.
|
| - ///
|
| - /// Removes stale deadline entries as they are found, but
|
| - /// does not otherwise modify the heap of deadlines.
|
| - fn get_next_deadline(&mut self) -> system::MojoTimeTicks {
|
| - debug_assert!(!self.handlers.is_empty());
|
| - let top_task_deadline = match self.tasks.peek() {
|
| - Some(info) => info.deadline(),
|
| - None => MOJO_INDEFINITE_ABSOLUTE,
|
| - };
|
| - let mut top = match self.deadlines.peek() {
|
| - Some(info) => info.clone(),
|
| - None => return MOJO_INDEFINITE_ABSOLUTE,
|
| - };
|
| - while !self.handlers.contains_key(top.token()) {
|
| - self.deadlines.pop();
|
| - top = match self.deadlines.peek() {
|
| - Some(info) => info.clone(),
|
| - None => return MOJO_INDEFINITE_ABSOLUTE,
|
| - }
|
| - }
|
| - if top_task_deadline != MOJO_INDEFINITE_ABSOLUTE &&
|
| - top_task_deadline < top.deadline() {
|
| - top_task_deadline
|
| - } else {
|
| - top.deadline()
|
| - }
|
| - }
|
| -
|
| - /// Gets a handler by token to be manipulated in a consistent environment.
|
| - ///
|
| - /// This method provides a method of accessing a handler in order to manipulate
|
| - /// it in a manner that avoids a borrow cycle, that is, it take()s the handler
|
| - /// out of the HashMap, and returns it when manipulation has completed.
|
| - fn get_handler_with<F>(&mut self, token: &Token, invoker: F)
|
| - where F: FnOnce(&mut Self,
|
| - &mut Box<Handler + 'h>,
|
| - Token,
|
| - system::MojoTimeTicks)
|
| - {
|
| - // Logic for pulling out the handler as well as its current deadline.
|
| - //
|
| - // Unfortunately, pulling out the handler value here and "onto the stack"
|
| - // (it probably won't actually end up on the stack thanks to optimizations)
|
| - // is necessary since otherwise the borrow checker complains that we pass
|
| - // a mutable reference to the RunLoop and the handler (as &mut self) to
|
| - // the callbacks at the same time. This is understandably unsafe since
|
| - // modifying the hashmap with register and deregister can invalidate the
|
| - // reference to self in the callback. In the C++ bindings and in other Rust
|
| - // event loops this is exactly what happens, but I avoided this. The downside
|
| - // is that we can no longer nest event loop run() calls. Once we put a handler
|
| - // onto the stack here, we can no longer call its callback in a nested manner
|
| - // from the RunLoop. I could just enable nesting with this one restriction, that
|
| - // the handler calling run() will always be ignored, but this is unintuitive.
|
| - let (mut handler, deadline) = match self.handlers.get_mut(&token) {
|
| - Some(ref_info) => {
|
| - (match ref_info.take() {
|
| - Some(handler) => handler,
|
| - None => return,
|
| - },
|
| - ref_info.deadline())
|
| - }
|
| - None => return,
|
| - };
|
| - // Call the closure that will invoke the callbacks.
|
| - invoker(self, &mut handler, token.clone(), deadline);
|
| - // Restore the handler to its location in the HashMap
|
| - if let Some(ref_info) = self.handlers.get_mut(&token) {
|
| - ref_info.give(handler);
|
| - }
|
| - }
|
| -
|
| - /// For all the results we received, we notify the respective handle
|
| - /// owners of the results by calling their given callbacks.
|
| - ///
|
| - /// We do NOT dequeue notified handles.
|
| - fn notify_of_results(&mut self, results: &Vec<system::WaitSetResult>) {
|
| - debug_assert!(!self.handlers.is_empty());
|
| - for wsr in results.iter() {
|
| - let token = Token(wsr.cookie());
|
| - self.get_handler_with(&token, move |runloop, boxed_handler, token, _dl| {
|
| - let handler = boxed_handler.as_mut();
|
| - match wsr.result() {
|
| - MojoResult::Okay => handler.on_ready(runloop, token),
|
| - MojoResult::Cancelled => {
|
| - handler.on_error(runloop, token, WaitError::HandleClosed)
|
| - }
|
| - MojoResult::Busy => handler.on_error(runloop, token, WaitError::HandleBusy),
|
| - MojoResult::FailedPrecondition => {
|
| - handler.on_error(runloop, token, WaitError::Unsatisfiable)
|
| - }
|
| - other => panic!("Unexpected result received after waiting: {}", other),
|
| - }
|
| - });
|
| - // In order to quit as soon as possible, we should check to quit after every
|
| - // potential handler call, as any of them could have signaled to quit.
|
| - if self.should_quit {
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - /// Since the deadline expired, we notify the relevant handle
|
| - /// owners of the expiration by calling their given callbacks.
|
| - ///
|
| - /// We do NOT dequeue notified handles.
|
| - fn notify_of_expired(&mut self, expired_deadline: system::MojoTimeTicks) {
|
| - debug_assert!(!self.handlers.is_empty());
|
| - let mut top = match self.deadlines.peek() {
|
| - Some(info) => info.clone(),
|
| - None => panic!("Should not be in notify_of_expired without at least one deadline!"),
|
| - };
|
| - while expired_deadline >= top.deadline() {
|
| - let next_deadline = top.deadline();
|
| - self.get_handler_with(top.token(),
|
| - move |runloop, boxed_handler, token, expected_dl| {
|
| - let handler = boxed_handler.as_mut();
|
| - if next_deadline == expected_dl {
|
| - handler.on_timeout(runloop, token);
|
| - }
|
| - });
|
| - // In order to quit as soon as possible, we should check to quit after every
|
| - // potential handler call, as any of them could have signaled to quit.
|
| - if self.should_quit {
|
| - break;
|
| - }
|
| - // Remove the deadline
|
| - self.deadlines.pop();
|
| - // Break if the next deadline has not yet expired.
|
| - top = match self.deadlines.peek() {
|
| - Some(info) => info.clone(),
|
| - None => break,
|
| - };
|
| - }
|
| - }
|
| -
|
| - /// Iterates through all tasks whose deadline has passed and executes
|
| - /// them, consuming their information object.
|
| - ///
|
| - /// These tasks all have access to the RunLoop so that they may reschedule
|
| - /// themselves or manipulate the RunLoop in some other way.
|
| - fn execute_ready_tasks(&mut self) {
|
| - let now = core::get_time_ticks_now();
|
| - let mut deadline = match self.tasks.peek() {
|
| - Some(info) => info.deadline(),
|
| - None => return,
|
| - };
|
| - while deadline < now {
|
| - let top = self.tasks.pop().expect("Sudden change to heap?");
|
| - top.execute_task(self);
|
| - if self.should_quit {
|
| - return;
|
| - }
|
| - deadline = match self.tasks.peek() {
|
| - Some(info) => info.deadline(),
|
| - None => return,
|
| - };
|
| - }
|
| - }
|
| -
|
| - /// Blocks on handle_set.wait_on_set using the information contained
|
| - /// within itself.
|
| - ///
|
| - /// This method blocks for only as long as the shortest deadline among all
|
| - /// handles this thread has registered. This method returns immediately as
|
| - /// soon as any one handle has its signals satisfied, fails to ever have its
|
| - /// signals satisfied, or reaches its deadline.
|
| - fn wait(&mut self, results_buffer: &mut Vec<system::WaitSetResult>) {
|
| - debug_assert!(!self.handlers.is_empty());
|
| - self.execute_ready_tasks();
|
| - // If after executing a task we quit or there are no handles,
|
| - // we have no reason to continue.
|
| - if self.handlers.is_empty() || self.should_quit {
|
| - return;
|
| - }
|
| - let deadline = self.get_next_deadline();
|
| - let until_deadline = relative_deadline(deadline, core::get_time_ticks_now());
|
| - // Perform the wait
|
| - match self.handle_set.wait_on_set(until_deadline, results_buffer) {
|
| - Ok(max_results) => {
|
| - self.notify_of_results(results_buffer);
|
| - // Clear the buffer since we don't need the results anymore.
|
| - // Helps prevent a copy if we resize the buffer.
|
| - results_buffer.clear();
|
| - // Increase the size of the buffer if there are more results
|
| - // we could be holding.
|
| - let capacity = results_buffer.capacity();
|
| - if capacity < MAXIMUM_WAIT_SET_NUM_RESULTS && capacity < (max_results) as usize {
|
| - results_buffer.reserve(capacity);
|
| - }
|
| - }
|
| - Err(result) => {
|
| - assert_eq!(result, MojoResult::DeadlineExceeded);
|
| - self.notify_of_expired(deadline);
|
| - }
|
| - }
|
| - }
|
| -
|
| - /// Loop forever until a callback tells us to quit.
|
| - pub fn run(&mut self) {
|
| - // It's an error it already be running...
|
| - if self.running {
|
| - panic!("RunLoop is already running!");
|
| - }
|
| - self.running = true;
|
| - self.should_quit = false;
|
| - let mut buffer: Vec<system::WaitSetResult> =
|
| - Vec::with_capacity(INITIAL_WAIT_SET_NUM_RESULTS);
|
| - // Loop while we haven't been signaled to quit, and there's something to wait on.
|
| - while !self.should_quit && !self.handlers.is_empty() {
|
| - self.wait(&mut buffer)
|
| - }
|
| - self.running = false;
|
| - }
|
| -
|
| - /// Set a flag to quit at the next available moment.
|
| - pub fn quit(&mut self) {
|
| - self.should_quit = true;
|
| - }
|
| -}
|
| -
|
| -/// Provides a scope to modify the current thread's runloop.
|
| -pub fn with_current<F>(modifier: F)
|
| - where F: FnOnce(&mut RunLoop)
|
| -{
|
| - TL_RUN_LOOP.with(|ref_runloop| {
|
| - let mut runloop = ref_runloop.borrow_mut();
|
| - modifier(&mut *runloop);
|
| - });
|
| -}
|
|
|