| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 //! This module contains a thread-local run-loop. | |
| 6 //! | |
| 7 //! The run-loop may have handles and handlers pre-registers | |
| 8 //! (and in fact, must) in order to keep running. The run-loop | |
| 9 //! executes until it has no more handles or handlers on itself, | |
| 10 //! or until it is told to quit via stop(). | |
| 11 //! | |
| 12 //! The run-loop waits until some signals on some handle is satisfied, | |
| 13 //! at which point it wakes up and executes the appropriate handler | |
| 14 //! method. This handler method may then be used to further populate | |
| 15 //! or de-populate the run-loop. | |
| 16 //! | |
| 17 //! As of yet, the run-loop is NOT thread-safe. Although it is useful | |
| 18 //! to be able to register tasks or handles from one thread onto | |
| 19 //! another thread's run-loop, this is as-of-yet unsupported, and | |
| 20 //! Rust should complain loudly when you try to do any threading here. | |
| 21 | |
| 22 use std::cell::RefCell; | |
| 23 use std::cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; | |
| 24 use std::collections::BinaryHeap; | |
| 25 use std::collections::HashMap; | |
| 26 use std::i64; | |
| 27 use std::u32; | |
| 28 use std::vec::Vec; | |
| 29 | |
| 30 use system; | |
| 31 use system::{Handle, MOJO_INDEFINITE, MojoResult}; | |
| 32 use system::core; | |
| 33 use system::wait_set; | |
| 34 | |
| 35 /// Define the equivalent of MOJO_INDEFINITE for absolute deadlines | |
| 36 const MOJO_INDEFINITE_ABSOLUTE: system::MojoTimeTicks = 0; | |
| 37 | |
| 38 // TODO(mknyszek): The numbers below are arbitrary and come from the C++ binding
s, | |
| 39 // and should probably be changed at some point | |
| 40 | |
| 41 /// Initial size of the result buffer. | |
| 42 const INITIAL_WAIT_SET_NUM_RESULTS: usize = 16; | |
| 43 | |
| 44 /// Maximum size of the result buffer. | |
| 45 const MAXIMUM_WAIT_SET_NUM_RESULTS: usize = 256; | |
| 46 | |
| 47 /// Thread-local data structure for keeping track of handles to wait on. | |
| 48 thread_local!(static TL_RUN_LOOP: RefCell<RunLoop<'static, 'static>> = RefCell::
new(RunLoop::new())); | |
| 49 | |
| 50 /// Token representing handle/callback to wait on for this thread only. This | |
| 51 /// token only has meaning on the thread in which the handle was registered. | |
| 52 #[derive(Clone, Debug, PartialEq, Eq, Hash)] | |
| 53 pub struct Token(u64); | |
| 54 | |
| 55 impl Token { | |
| 56 /// Get the wait token's "cookie" form, suitable for use in a wait set. | |
| 57 fn as_cookie(&self) -> u64 { | |
| 58 self.0 | |
| 59 } | |
| 60 } | |
| 61 | |
| 62 /// Represents the possible error cases that may occur when waiting | |
| 63 /// on a handle in a RunLoop. | |
| 64 #[derive(Clone, Debug, PartialEq, Eq)] | |
| 65 pub enum WaitError { | |
| 66 /// The handle has been closed or is otherwise no longer valid. | |
| 67 HandleClosed, | |
| 68 | |
| 69 /// The handle is currently busy in some transaction. | |
| 70 HandleBusy, | |
| 71 | |
| 72 /// It has been determined that the signals provided will never | |
| 73 /// be satisfied for this handle. | |
| 74 Unsatisfiable, | |
| 75 } | |
| 76 | |
| 77 /// A trait which defines an interface to be a handler usable by | |
| 78 /// a RunLoop. | |
| 79 pub trait Handler { | |
| 80 /// Called after a successful wait. | |
| 81 fn on_ready(&mut self, runloop: &mut RunLoop, token: Token); | |
| 82 | |
| 83 /// Called after the given deadline expires. | |
| 84 fn on_timeout(&mut self, runloop: &mut RunLoop, token: Token); | |
| 85 | |
| 86 /// Called when an unexpected error occurs. | |
| 87 fn on_error(&mut self, runloop: &mut RunLoop, token: Token, error: WaitError
); | |
| 88 } | |
| 89 | |
| 90 /// A wrapper struct for carrying the handler as well as various information | |
| 91 /// about it. | |
| 92 struct HandlerInfo<'h> { | |
| 93 /// The handle for which we are waiting. | |
| 94 /// | |
| 95 /// We keep this handle around so that we may easily re-register. | |
| 96 handle: system::MojoHandle, | |
| 97 | |
| 98 /// The handler, boxed up. | |
| 99 /// | |
| 100 /// The handler is in an Option type because if it is currently being | |
| 101 /// used in a callback, we must take ownership to avoid mutability | |
| 102 /// cycles. The easiest way to do this is to take() from the Option then | |
| 103 /// put it back. | |
| 104 handler: Option<Box<Handler + 'h>>, | |
| 105 | |
| 106 /// An absolute deadline in terms of time ticks. | |
| 107 /// | |
| 108 /// This is the most recently updated deadline that | |
| 109 /// we should be watching out for. All others for this | |
| 110 /// token may be considered "stale". | |
| 111 deadline: system::MojoTimeTicks, | |
| 112 } | |
| 113 | |
| 114 impl<'h> HandlerInfo<'h> { | |
| 115 /// Take the handler out of its Option type. | |
| 116 pub fn take(&mut self) -> Option<Box<Handler + 'h>> { | |
| 117 self.handler.take() | |
| 118 } | |
| 119 | |
| 120 /// Put a new handler into the Option type. | |
| 121 pub fn give(&mut self, handler: Box<Handler + 'h>) { | |
| 122 self.handler = Some(handler); | |
| 123 } | |
| 124 | |
| 125 /// Getter for the system::MojoHandle held inside. | |
| 126 pub fn handle(&self) -> system::MojoHandle { | |
| 127 self.handle | |
| 128 } | |
| 129 | |
| 130 /// Getter for the current absolute deadline held inside. | |
| 131 pub fn deadline(&self) -> system::MojoTimeTicks { | |
| 132 self.deadline | |
| 133 } | |
| 134 | |
| 135 /// Setter to update the current absolute deadline. | |
| 136 pub fn set_deadline(&mut self, deadline: system::MojoTimeTicks) { | |
| 137 self.deadline = deadline | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 /// A wrapper struct for carrying the task as well as some information about | |
| 142 /// it. | |
| 143 struct TaskInfo<'t> { | |
| 144 /// The task, boxed up. | |
| 145 closure: Box<FnMut(&mut RunLoop) + 't>, | |
| 146 | |
| 147 /// An absolute deadline in terms of time ticks. | |
| 148 /// | |
| 149 /// This is the most recently updated deadline that | |
| 150 /// we should be watching out for. All others for this | |
| 151 /// token may be considered "stale". | |
| 152 deadline: system::MojoTimeTicks, | |
| 153 } | |
| 154 | |
| 155 impl<'t> TaskInfo<'t> { | |
| 156 /// Executes the task within the info object, consuming it | |
| 157 /// in the process. | |
| 158 pub fn execute_task(mut self, run_loop: &mut RunLoop) { | |
| 159 (*self.closure)(run_loop); | |
| 160 } | |
| 161 | |
| 162 /// Getter for the current absolute deadline held inside. | |
| 163 pub fn deadline(&self) -> system::MojoTimeTicks { | |
| 164 self.deadline | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 impl<'t> PartialEq for TaskInfo<'t> { | |
| 169 /// Equality for TaskInfo in terms of its deadline | |
| 170 fn eq(&self, other: &TaskInfo) -> bool { | |
| 171 self.deadline == other.deadline | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 impl<'t> Eq for TaskInfo<'t> {} | |
| 176 | |
| 177 impl<'t> PartialOrd for TaskInfo<'t> { | |
| 178 /// Partial comparison for TaskInfo in terms of its deadline | |
| 179 /// | |
| 180 /// Reverses the comparison because the Rust std library only | |
| 181 /// offers a max-heap, and we need a min-heap. | |
| 182 fn partial_cmp(&self, other: &TaskInfo) -> Option<Ordering> { | |
| 183 other.deadline.partial_cmp(&self.deadline) | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 impl<'t> Ord for TaskInfo<'t> { | |
| 188 /// Implement comparisons for Task Info. | |
| 189 /// | |
| 190 /// Reverses the comparison because the Rust std library only | |
| 191 /// offers a max-heap, and we need a min-heap. | |
| 192 fn cmp(&self, other: &Self) -> Ordering { | |
| 193 other.deadline.cmp(&self.deadline) | |
| 194 } | |
| 195 } | |
| 196 | |
| 197 /// Wrapper struct intended to be used in a priority queue | |
| 198 /// for efficiently retrieving the next closest deadline. | |
| 199 #[derive(Clone)] | |
| 200 struct DeadlineInfo { | |
| 201 /// The ID of the associated Handler struct in the RunLoop's | |
| 202 /// hash map. | |
| 203 token: Token, | |
| 204 | |
| 205 /// An absolute deadline in terms of time ticks. | |
| 206 deadline: system::MojoTimeTicks, | |
| 207 } | |
| 208 | |
| 209 impl DeadlineInfo { | |
| 210 /// Getter for an immutable borrow for the token inside. | |
| 211 pub fn token(&self) -> &Token { | |
| 212 &self.token | |
| 213 } | |
| 214 | |
| 215 /// Getter for the absolute deadline inside. | |
| 216 pub fn deadline(&self) -> system::MojoTimeTicks { | |
| 217 self.deadline | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 impl PartialEq for DeadlineInfo { | |
| 222 /// Equality for DeadlineInfo in terms of its deadline | |
| 223 fn eq(&self, other: &DeadlineInfo) -> bool { | |
| 224 self.deadline == other.deadline | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 impl Eq for DeadlineInfo {} | |
| 229 | |
| 230 impl PartialOrd for DeadlineInfo { | |
| 231 /// Partial comparison for DeadlineInfo in terms of its deadline | |
| 232 /// | |
| 233 /// Reverses the comparison because the Rust std library only | |
| 234 /// offers a max-heap, and we need a min-heap. | |
| 235 fn partial_cmp(&self, other: &DeadlineInfo) -> Option<Ordering> { | |
| 236 other.deadline.partial_cmp(&self.deadline) | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 impl Ord for DeadlineInfo { | |
| 241 /// Implement comparisons for Deadline Info. | |
| 242 /// | |
| 243 /// Reverses the comparison because the Rust std library only | |
| 244 /// offers a max-heap, and we need a min-heap. | |
| 245 fn cmp(&self, other: &Self) -> Ordering { | |
| 246 other.deadline.cmp(&self.deadline) | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 /// Convert a mojo deadline (which is a relative deadline to "now") to | |
| 251 /// an absolute deadline based on time ticks. | |
| 252 fn absolute_deadline(deadline: system::MojoDeadline) -> system::MojoTimeTicks { | |
| 253 if deadline == MOJO_INDEFINITE { | |
| 254 return MOJO_INDEFINITE_ABSOLUTE; | |
| 255 } | |
| 256 let mut converted = MOJO_INDEFINITE_ABSOLUTE; | |
| 257 let max_time_ticks = i64::MAX as system::MojoDeadline; | |
| 258 if deadline <= max_time_ticks { | |
| 259 let now = core::get_time_ticks_now(); | |
| 260 if deadline <= (max_time_ticks - (now as u64)) { | |
| 261 converted = (deadline as system::MojoTimeTicks) + now | |
| 262 } | |
| 263 } | |
| 264 converted | |
| 265 } | |
| 266 | |
| 267 /// Convert an absolute deadline to a mojo deadline which is relative to some | |
| 268 /// notion of "now". | |
| 269 /// | |
| 270 /// If the deadline is earlier than "now", this routine rounds up to "now". | |
| 271 fn relative_deadline(deadline: system::MojoTimeTicks, | |
| 272 now: system::MojoTimeTicks) | |
| 273 -> system::MojoDeadline { | |
| 274 if deadline == MOJO_INDEFINITE_ABSOLUTE { | |
| 275 MOJO_INDEFINITE | |
| 276 } else if now >= deadline { | |
| 277 0 | |
| 278 } else { | |
| 279 (deadline - now) as system::MojoDeadline | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 /// This structure contains all information necessary to wait on handles | |
| 284 /// asynchronously. | |
| 285 /// | |
| 286 /// Ultimately, it should only be a singleton living in | |
| 287 /// thread-local storage. | |
| 288 pub struct RunLoop<'h, 't> { | |
| 289 /// Running count of the next available token slot. | |
| 290 token_count: u64, | |
| 291 | |
| 292 /// A map of handlers. | |
| 293 /// | |
| 294 /// TODO(mknyszek): Try out a Slab allocator instead of a hashmap. | |
| 295 handlers: HashMap<Token, HandlerInfo<'h>>, | |
| 296 | |
| 297 /// A min-heap of delayed tasks in order to pull the soonest task to | |
| 298 /// execute efficiently. | |
| 299 tasks: BinaryHeap<TaskInfo<'t>>, | |
| 300 | |
| 301 /// A min-heap containing deadlines in order to pull out the soonest | |
| 302 /// deadline efficiently. | |
| 303 /// | |
| 304 /// Warning: may contain "stale" deadlines which are not kept in the | |
| 305 /// map! | |
| 306 deadlines: BinaryHeap<DeadlineInfo>, | |
| 307 | |
| 308 /// The Mojo structure keeping track of handles and signals. | |
| 309 /// | |
| 310 /// This structure must be kept in sync with handlers. | |
| 311 handle_set: wait_set::WaitSet, | |
| 312 | |
| 313 /// A flag that tells the RunLoop whether it should quit. | |
| 314 should_quit: bool, | |
| 315 | |
| 316 /// A flag that indicates whether the RunLoop is running or now | |
| 317 running: bool, | |
| 318 } | |
| 319 | |
| 320 impl<'h, 't> RunLoop<'h, 't> { | |
| 321 /// Create a new RunLoop. | |
| 322 pub fn new() -> RunLoop<'h, 't> { | |
| 323 RunLoop { | |
| 324 token_count: 0, | |
| 325 handlers: HashMap::new(), | |
| 326 tasks: BinaryHeap::new(), | |
| 327 deadlines: BinaryHeap::new(), | |
| 328 handle_set: wait_set::WaitSet::new(wsflags!(Create::None)).unwrap(), | |
| 329 should_quit: false, | |
| 330 running: false, | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 /// Generate a new Token for this RunLoop | |
| 335 fn generate_token(&mut self) -> Token { | |
| 336 self.token_count = self.token_count.wrapping_add(1); | |
| 337 Token(self.token_count) | |
| 338 } | |
| 339 | |
| 340 /// Adds a new entry to the runloop queue. | |
| 341 pub fn register<H>(&mut self, | |
| 342 handle: &Handle, | |
| 343 signals: system::HandleSignals, | |
| 344 deadline: system::MojoDeadline, | |
| 345 handler: H) | |
| 346 -> Token | |
| 347 where H: Handler + 'h | |
| 348 { | |
| 349 | |
| 350 let token = self.generate_token(); | |
| 351 let abs_deadline = absolute_deadline(deadline); | |
| 352 self.handle_set.add(handle, signals, token.as_cookie(), wsflags!(Add::No
ne)); | |
| 353 self.deadlines.push(DeadlineInfo { | |
| 354 token: token.clone(), | |
| 355 deadline: abs_deadline, | |
| 356 }); | |
| 357 debug_assert!(!self.handlers.contains_key(&token)); | |
| 358 self.handlers.insert(token.clone(), | |
| 359 HandlerInfo { | |
| 360 handle: handle.get_native_handle(), | |
| 361 handler: Some(Box::new(handler)), | |
| 362 deadline: abs_deadline, | |
| 363 }); | |
| 364 token | |
| 365 } | |
| 366 | |
| 367 /// Updates the signals and deadline of an existing handler in the | |
| 368 /// runloop via token. The token remains unchanged and valid. | |
| 369 /// | |
| 370 /// Returns true on a successful update and false if the token was not | |
| 371 /// found. | |
| 372 pub fn reregister(&mut self, | |
| 373 token: &Token, | |
| 374 signals: system::HandleSignals, | |
| 375 deadline: system::MojoDeadline) | |
| 376 -> bool { | |
| 377 | |
| 378 match self.handlers.get_mut(&token) { | |
| 379 Some(info) => { | |
| 380 let _result = self.handle_set.remove(token.as_cookie()); | |
| 381 debug_assert_eq!(_result, MojoResult::Okay); | |
| 382 let abs_deadline = absolute_deadline(deadline); | |
| 383 // Update what deadline we should be looking for, rendering | |
| 384 // all previously set deadlines "stale". | |
| 385 info.set_deadline(abs_deadline); | |
| 386 // Add a new deadline | |
| 387 self.deadlines.push(DeadlineInfo { | |
| 388 token: token.clone(), | |
| 389 deadline: abs_deadline, | |
| 390 }); | |
| 391 // Acquire the raw handle held by the HandlerInfo in order to | |
| 392 // call the wait_set's add method. Invalidate it immediately aft
er | |
| 393 // in order to prevent the handle from being closed. | |
| 394 // | |
| 395 // It's perfectly okay for the handle to be invalid, so although
this | |
| 396 // is all unsafe, the whole system should just call the handler
with an | |
| 397 // error. | |
| 398 let mut dummy = unsafe { system::acquire(info.handle()) }; | |
| 399 self.handle_set.add(&dummy, signals, token.as_cookie(), wsflags!
(Add::None)); | |
| 400 unsafe { | |
| 401 dummy.invalidate(); | |
| 402 } | |
| 403 true | |
| 404 } | |
| 405 None => false, | |
| 406 } | |
| 407 } | |
| 408 | |
| 409 /// Removes an entry from the runloop. | |
| 410 /// | |
| 411 /// Since we cannot remove from the deadlines heap, we just leave the deadli
ne | |
| 412 /// in there as "stale", and we handle those when trying to find the next cl
osest | |
| 413 /// deadline. | |
| 414 pub fn deregister(&mut self, token: Token) -> bool { | |
| 415 match self.handlers.remove(&token) { | |
| 416 Some(_) => { | |
| 417 let _result = self.handle_set.remove(token.as_cookie()); | |
| 418 debug_assert_eq!(_result, MojoResult::Okay); | |
| 419 true | |
| 420 } | |
| 421 None => false, | |
| 422 } | |
| 423 } | |
| 424 | |
| 425 /// Adds a task to be run by the runloop after some delay. | |
| 426 /// | |
| 427 /// Returns a token if the delay is valid, otherwise returns None. | |
| 428 pub fn post_task<F>(&mut self, task: F, delay: system::MojoTimeTicks) -> Res
ult<(), ()> | |
| 429 where F: FnMut(&mut RunLoop) + 't | |
| 430 { | |
| 431 let now = core::get_time_ticks_now(); | |
| 432 if delay > i64::MAX - now { | |
| 433 return Err(()); | |
| 434 } | |
| 435 let deadline = now + delay; | |
| 436 self.tasks.push(TaskInfo { | |
| 437 closure: Box::new(task), | |
| 438 deadline: deadline, | |
| 439 }); | |
| 440 Ok(()) | |
| 441 } | |
| 442 | |
| 443 /// Uses the binary heaps to get the next closest deadline. | |
| 444 /// | |
| 445 /// Removes stale deadline entries as they are found, but | |
| 446 /// does not otherwise modify the heap of deadlines. | |
| 447 fn get_next_deadline(&mut self) -> system::MojoTimeTicks { | |
| 448 debug_assert!(!self.handlers.is_empty()); | |
| 449 let top_task_deadline = match self.tasks.peek() { | |
| 450 Some(info) => info.deadline(), | |
| 451 None => MOJO_INDEFINITE_ABSOLUTE, | |
| 452 }; | |
| 453 let mut top = match self.deadlines.peek() { | |
| 454 Some(info) => info.clone(), | |
| 455 None => return MOJO_INDEFINITE_ABSOLUTE, | |
| 456 }; | |
| 457 while !self.handlers.contains_key(top.token()) { | |
| 458 self.deadlines.pop(); | |
| 459 top = match self.deadlines.peek() { | |
| 460 Some(info) => info.clone(), | |
| 461 None => return MOJO_INDEFINITE_ABSOLUTE, | |
| 462 } | |
| 463 } | |
| 464 if top_task_deadline != MOJO_INDEFINITE_ABSOLUTE && | |
| 465 top_task_deadline < top.deadline() { | |
| 466 top_task_deadline | |
| 467 } else { | |
| 468 top.deadline() | |
| 469 } | |
| 470 } | |
| 471 | |
| 472 /// Gets a handler by token to be manipulated in a consistent environment. | |
| 473 /// | |
| 474 /// This method provides a method of accessing a handler in order to manipul
ate | |
| 475 /// it in a manner that avoids a borrow cycle, that is, it take()s the handl
er | |
| 476 /// out of the HashMap, and returns it when manipulation has completed. | |
| 477 fn get_handler_with<F>(&mut self, token: &Token, invoker: F) | |
| 478 where F: FnOnce(&mut Self, | |
| 479 &mut Box<Handler + 'h>, | |
| 480 Token, | |
| 481 system::MojoTimeTicks) | |
| 482 { | |
| 483 // Logic for pulling out the handler as well as its current deadline. | |
| 484 // | |
| 485 // Unfortunately, pulling out the handler value here and "onto the stack
" | |
| 486 // (it probably won't actually end up on the stack thanks to optimizatio
ns) | |
| 487 // is necessary since otherwise the borrow checker complains that we pas
s | |
| 488 // a mutable reference to the RunLoop and the handler (as &mut self) to | |
| 489 // the callbacks at the same time. This is understandably unsafe since | |
| 490 // modifying the hashmap with register and deregister can invalidate the | |
| 491 // reference to self in the callback. In the C++ bindings and in other R
ust | |
| 492 // event loops this is exactly what happens, but I avoided this. The dow
nside | |
| 493 // is that we can no longer nest event loop run() calls. Once we put a h
andler | |
| 494 // onto the stack here, we can no longer call its callback in a nested m
anner | |
| 495 // from the RunLoop. I could just enable nesting with this one restricti
on, that | |
| 496 // the handler calling run() will always be ignored, but this is unintui
tive. | |
| 497 let (mut handler, deadline) = match self.handlers.get_mut(&token) { | |
| 498 Some(ref_info) => { | |
| 499 (match ref_info.take() { | |
| 500 Some(handler) => handler, | |
| 501 None => return, | |
| 502 }, | |
| 503 ref_info.deadline()) | |
| 504 } | |
| 505 None => return, | |
| 506 }; | |
| 507 // Call the closure that will invoke the callbacks. | |
| 508 invoker(self, &mut handler, token.clone(), deadline); | |
| 509 // Restore the handler to its location in the HashMap | |
| 510 if let Some(ref_info) = self.handlers.get_mut(&token) { | |
| 511 ref_info.give(handler); | |
| 512 } | |
| 513 } | |
| 514 | |
| 515 /// For all the results we received, we notify the respective handle | |
| 516 /// owners of the results by calling their given callbacks. | |
| 517 /// | |
| 518 /// We do NOT dequeue notified handles. | |
| 519 fn notify_of_results(&mut self, results: &Vec<system::WaitSetResult>) { | |
| 520 debug_assert!(!self.handlers.is_empty()); | |
| 521 for wsr in results.iter() { | |
| 522 let token = Token(wsr.cookie()); | |
| 523 self.get_handler_with(&token, move |runloop, boxed_handler, token, _
dl| { | |
| 524 let handler = boxed_handler.as_mut(); | |
| 525 match wsr.result() { | |
| 526 MojoResult::Okay => handler.on_ready(runloop, token), | |
| 527 MojoResult::Cancelled => { | |
| 528 handler.on_error(runloop, token, WaitError::HandleClosed
) | |
| 529 } | |
| 530 MojoResult::Busy => handler.on_error(runloop, token, WaitErr
or::HandleBusy), | |
| 531 MojoResult::FailedPrecondition => { | |
| 532 handler.on_error(runloop, token, WaitError::Unsatisfiabl
e) | |
| 533 } | |
| 534 other => panic!("Unexpected result received after waiting: {
}", other), | |
| 535 } | |
| 536 }); | |
| 537 // In order to quit as soon as possible, we should check to quit aft
er every | |
| 538 // potential handler call, as any of them could have signaled to qui
t. | |
| 539 if self.should_quit { | |
| 540 break; | |
| 541 } | |
| 542 } | |
| 543 } | |
| 544 | |
| 545 /// Since the deadline expired, we notify the relevant handle | |
| 546 /// owners of the expiration by calling their given callbacks. | |
| 547 /// | |
| 548 /// We do NOT dequeue notified handles. | |
| 549 fn notify_of_expired(&mut self, expired_deadline: system::MojoTimeTicks) { | |
| 550 debug_assert!(!self.handlers.is_empty()); | |
| 551 let mut top = match self.deadlines.peek() { | |
| 552 Some(info) => info.clone(), | |
| 553 None => panic!("Should not be in notify_of_expired without at least
one deadline!"), | |
| 554 }; | |
| 555 while expired_deadline >= top.deadline() { | |
| 556 let next_deadline = top.deadline(); | |
| 557 self.get_handler_with(top.token(), | |
| 558 move |runloop, boxed_handler, token, expected_
dl| { | |
| 559 let handler = boxed_handler.as_mut(); | |
| 560 if next_deadline == expected_dl { | |
| 561 handler.on_timeout(runloop, token); | |
| 562 } | |
| 563 }); | |
| 564 // In order to quit as soon as possible, we should check to quit aft
er every | |
| 565 // potential handler call, as any of them could have signaled to qui
t. | |
| 566 if self.should_quit { | |
| 567 break; | |
| 568 } | |
| 569 // Remove the deadline | |
| 570 self.deadlines.pop(); | |
| 571 // Break if the next deadline has not yet expired. | |
| 572 top = match self.deadlines.peek() { | |
| 573 Some(info) => info.clone(), | |
| 574 None => break, | |
| 575 }; | |
| 576 } | |
| 577 } | |
| 578 | |
| 579 /// Iterates through all tasks whose deadline has passed and executes | |
| 580 /// them, consuming their information object. | |
| 581 /// | |
| 582 /// These tasks all have access to the RunLoop so that they may reschedule | |
| 583 /// themselves or manipulate the RunLoop in some other way. | |
| 584 fn execute_ready_tasks(&mut self) { | |
| 585 let now = core::get_time_ticks_now(); | |
| 586 let mut deadline = match self.tasks.peek() { | |
| 587 Some(info) => info.deadline(), | |
| 588 None => return, | |
| 589 }; | |
| 590 while deadline < now { | |
| 591 let top = self.tasks.pop().expect("Sudden change to heap?"); | |
| 592 top.execute_task(self); | |
| 593 if self.should_quit { | |
| 594 return; | |
| 595 } | |
| 596 deadline = match self.tasks.peek() { | |
| 597 Some(info) => info.deadline(), | |
| 598 None => return, | |
| 599 }; | |
| 600 } | |
| 601 } | |
| 602 | |
| 603 /// Blocks on handle_set.wait_on_set using the information contained | |
| 604 /// within itself. | |
| 605 /// | |
| 606 /// This method blocks for only as long as the shortest deadline among all | |
| 607 /// handles this thread has registered. This method returns immediately as | |
| 608 /// soon as any one handle has its signals satisfied, fails to ever have its | |
| 609 /// signals satisfied, or reaches its deadline. | |
| 610 fn wait(&mut self, results_buffer: &mut Vec<system::WaitSetResult>) { | |
| 611 debug_assert!(!self.handlers.is_empty()); | |
| 612 self.execute_ready_tasks(); | |
| 613 // If after executing a task we quit or there are no handles, | |
| 614 // we have no reason to continue. | |
| 615 if self.handlers.is_empty() || self.should_quit { | |
| 616 return; | |
| 617 } | |
| 618 let deadline = self.get_next_deadline(); | |
| 619 let until_deadline = relative_deadline(deadline, core::get_time_ticks_no
w()); | |
| 620 // Perform the wait | |
| 621 match self.handle_set.wait_on_set(until_deadline, results_buffer) { | |
| 622 Ok(max_results) => { | |
| 623 self.notify_of_results(results_buffer); | |
| 624 // Clear the buffer since we don't need the results anymore. | |
| 625 // Helps prevent a copy if we resize the buffer. | |
| 626 results_buffer.clear(); | |
| 627 // Increase the size of the buffer if there are more results | |
| 628 // we could be holding. | |
| 629 let capacity = results_buffer.capacity(); | |
| 630 if capacity < MAXIMUM_WAIT_SET_NUM_RESULTS && capacity < (max_re
sults) as usize { | |
| 631 results_buffer.reserve(capacity); | |
| 632 } | |
| 633 } | |
| 634 Err(result) => { | |
| 635 assert_eq!(result, MojoResult::DeadlineExceeded); | |
| 636 self.notify_of_expired(deadline); | |
| 637 } | |
| 638 } | |
| 639 } | |
| 640 | |
| 641 /// Loop forever until a callback tells us to quit. | |
| 642 pub fn run(&mut self) { | |
| 643 // It's an error it already be running... | |
| 644 if self.running { | |
| 645 panic!("RunLoop is already running!"); | |
| 646 } | |
| 647 self.running = true; | |
| 648 self.should_quit = false; | |
| 649 let mut buffer: Vec<system::WaitSetResult> = | |
| 650 Vec::with_capacity(INITIAL_WAIT_SET_NUM_RESULTS); | |
| 651 // Loop while we haven't been signaled to quit, and there's something to
wait on. | |
| 652 while !self.should_quit && !self.handlers.is_empty() { | |
| 653 self.wait(&mut buffer) | |
| 654 } | |
| 655 self.running = false; | |
| 656 } | |
| 657 | |
| 658 /// Set a flag to quit at the next available moment. | |
| 659 pub fn quit(&mut self) { | |
| 660 self.should_quit = true; | |
| 661 } | |
| 662 } | |
| 663 | |
| 664 /// Provides a scope to modify the current thread's runloop. | |
| 665 pub fn with_current<F>(modifier: F) | |
| 666 where F: FnOnce(&mut RunLoop) | |
| 667 { | |
| 668 TL_RUN_LOOP.with(|ref_runloop| { | |
| 669 let mut runloop = ref_runloop.borrow_mut(); | |
| 670 modifier(&mut *runloop); | |
| 671 }); | |
| 672 } | |
| OLD | NEW |