Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 //! This module contains a thread-local run-loop. | 5 //! This module contains a thread-local run-loop. |
| 6 //! | 6 //! |
| 7 //! The run-loop may have handles and handlers pre-registers | 7 //! The run-loop may have handles and handlers pre-registers |
| 8 //! (and in fact, must) in order to keep running. The run-loop | 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, | 9 //! executes until it has no more handles or handlers on itself, |
| 10 //! or until it is told to quit via stop(). | 10 //! or until it is told to quit via stop(). |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 197 if deadline <= max_time_ticks { | 197 if deadline <= max_time_ticks { |
| 198 let now = core::get_time_ticks_now(); | 198 let now = core::get_time_ticks_now(); |
| 199 if deadline <= (max_time_ticks - (now as u64)) { | 199 if deadline <= (max_time_ticks - (now as u64)) { |
| 200 converted = (deadline as system::MojoTimeTicks) + now | 200 converted = (deadline as system::MojoTimeTicks) + now |
| 201 } | 201 } |
| 202 } | 202 } |
| 203 converted | 203 converted |
| 204 } | 204 } |
| 205 | 205 |
| 206 /// Convert an absolute deadline to a mojo deadline which is relative to some | 206 /// Convert an absolute deadline to a mojo deadline which is relative to some |
| 207 /// notion of "now". | 207 /// notion of "now". |
|
mknyszek
2016/08/08 22:47:25
Oops, this was an accident. Running rustfmt appare
| |
| 208 /// | 208 /// |
| 209 /// If the deadline is earlier than "now", this routine rounds up to "now". | 209 /// If the deadline is earlier than "now", this routine rounds up to "now". |
| 210 fn relative_deadline(deadline: system::MojoTimeTicks, now: system::MojoTimeTicks ) -> system::MojoDeadline { | 210 fn relative_deadline(deadline: system::MojoTimeTicks, |
| 211 now: system::MojoTimeTicks) | |
| 212 -> system::MojoDeadline { | |
| 211 if deadline == MOJO_INDEFINITE_ABSOLUTE { | 213 if deadline == MOJO_INDEFINITE_ABSOLUTE { |
| 212 MOJO_INDEFINITE | 214 MOJO_INDEFINITE |
| 213 } else if now >= deadline { | 215 } else if now >= deadline { |
| 214 0 | 216 0 |
| 215 } else { | 217 } else { |
| 216 (deadline - now) as system::MojoDeadline | 218 (deadline - now) as system::MojoDeadline |
| 217 } | 219 } |
| 218 } | 220 } |
| 219 | 221 |
| 220 /// This structure contains all information necessary to wait on handles | 222 /// This structure contains all information necessary to wait on handles |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 280 { | 282 { |
| 281 | 283 |
| 282 let token = self.generate_token(); | 284 let token = self.generate_token(); |
| 283 let abs_deadline = absolute_deadline(deadline); | 285 let abs_deadline = absolute_deadline(deadline); |
| 284 self.handle_set.add(handle, signals, token.as_cookie(), wsflags!(Add::No ne)); | 286 self.handle_set.add(handle, signals, token.as_cookie(), wsflags!(Add::No ne)); |
| 285 self.deadlines.push(DeadlineInfo { | 287 self.deadlines.push(DeadlineInfo { |
| 286 token: token.clone(), | 288 token: token.clone(), |
| 287 deadline: abs_deadline, | 289 deadline: abs_deadline, |
| 288 }); | 290 }); |
| 289 debug_assert!(!self.handlers.contains_key(&token)); | 291 debug_assert!(!self.handlers.contains_key(&token)); |
| 290 self.handlers.insert(token.clone(), HandlerInfo { | 292 self.handlers.insert(token.clone(), |
| 291 handle: handle.get_native_handle(), | 293 HandlerInfo { |
| 292 handler: Some(Box::new(handler)), | 294 handle: handle.get_native_handle(), |
| 293 deadline: abs_deadline, | 295 handler: Some(Box::new(handler)), |
| 294 }); | 296 deadline: abs_deadline, |
| 297 }); | |
| 295 token | 298 token |
| 296 } | 299 } |
| 297 | 300 |
| 298 /// Updates the signals and deadline of an existing handler in the | 301 /// Updates the signals and deadline of an existing handler in the |
| 299 /// runloop via token. The token remains unchanged and valid. | 302 /// runloop via token. The token remains unchanged and valid. |
| 300 /// | 303 /// |
| 301 /// Returns true on a successful update and false if the token was not | 304 /// Returns true on a successful update and false if the token was not |
| 302 /// found. | 305 /// found. |
| 303 pub fn reregister(&mut self, | 306 pub fn reregister(&mut self, |
| 304 token: &Token, | 307 token: &Token, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 321 }); | 324 }); |
| 322 // Acquire the raw handle held by the HandlerInfo in order to | 325 // Acquire the raw handle held by the HandlerInfo in order to |
| 323 // call the wait_set's add method. Invalidate it immediately aft er | 326 // call the wait_set's add method. Invalidate it immediately aft er |
| 324 // in order to prevent the handle from being closed. | 327 // in order to prevent the handle from being closed. |
| 325 // | 328 // |
| 326 // It's perfectly okay for the handle to be invalid, so although this | 329 // It's perfectly okay for the handle to be invalid, so although this |
| 327 // is all unsafe, the whole system should just call the handler with an | 330 // is all unsafe, the whole system should just call the handler with an |
| 328 // error. | 331 // error. |
| 329 let mut dummy = unsafe { system::acquire(info.handle()) }; | 332 let mut dummy = unsafe { system::acquire(info.handle()) }; |
| 330 self.handle_set.add(&dummy, signals, token.as_cookie(), wsflags! (Add::None)); | 333 self.handle_set.add(&dummy, signals, token.as_cookie(), wsflags! (Add::None)); |
| 331 unsafe { dummy.invalidate(); } | 334 unsafe { |
| 335 dummy.invalidate(); | |
| 336 } | |
| 332 true | 337 true |
| 333 }, | 338 } |
| 334 None => false, | 339 None => false, |
| 335 } | 340 } |
| 336 } | 341 } |
| 337 | 342 |
| 338 /// Removes an entry from the runloop. | 343 /// Removes an entry from the runloop. |
| 339 /// | 344 /// |
| 340 /// Since we cannot remove from the deadlines heap, we just leave the deadli ne | 345 /// Since we cannot remove from the deadlines heap, we just leave the deadli ne |
| 341 /// in there as "stale", and we handle those when trying to find the next cl osest | 346 /// in there as "stale", and we handle those when trying to find the next cl osest |
| 342 /// deadline. | 347 /// deadline. |
| 343 pub fn deregister(&mut self, token: Token) -> bool { | 348 pub fn deregister(&mut self, token: Token) -> bool { |
| 344 match self.handlers.remove(&token) { | 349 match self.handlers.remove(&token) { |
| 345 Some(_) => { | 350 Some(_) => { |
| 346 let _result = self.handle_set.remove(token.as_cookie()); | 351 let _result = self.handle_set.remove(token.as_cookie()); |
| 347 debug_assert_eq!(_result, MojoResult::Okay); | 352 debug_assert_eq!(_result, MojoResult::Okay); |
| 348 true | 353 true |
| 349 }, | 354 } |
| 350 None => false, | 355 None => false, |
| 351 } | 356 } |
| 352 } | 357 } |
| 353 | 358 |
| 354 /// Uses the binary heap to get the next closest deadline. | 359 /// Uses the binary heap to get the next closest deadline. |
| 355 /// | 360 /// |
| 356 /// Removes stale deadline entries as they are found, but | 361 /// Removes stale deadline entries as they are found, but |
| 357 /// does not otherwise modify the heap of deadlines. | 362 /// does not otherwise modify the heap of deadlines. |
| 358 fn get_next_deadline(&mut self) -> system::MojoTimeTicks { | 363 fn get_next_deadline(&mut self) -> system::MojoTimeTicks { |
| 359 debug_assert!(!self.handlers.is_empty()); | 364 debug_assert!(!self.handlers.is_empty()); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 370 } | 375 } |
| 371 top.deadline() | 376 top.deadline() |
| 372 } | 377 } |
| 373 | 378 |
| 374 /// Gets a handler by token to be manipulated in a consistent environment. | 379 /// Gets a handler by token to be manipulated in a consistent environment. |
| 375 /// | 380 /// |
| 376 /// This method provides a method of accessing a handler in order to manipul ate | 381 /// This method provides a method of accessing a handler in order to manipul ate |
| 377 /// it in a manner that avoids a borrow cycle, that is, it take()s the handl er | 382 /// it in a manner that avoids a borrow cycle, that is, it take()s the handl er |
| 378 /// out of the HashMap, and returns it when manipulation has completed. | 383 /// out of the HashMap, and returns it when manipulation has completed. |
| 379 fn get_handler_with<F>(&mut self, token: &Token, invoker: F) | 384 fn get_handler_with<F>(&mut self, token: &Token, invoker: F) |
| 380 where F: FnOnce(&mut Self, &mut Box<Handler + 'h>, Token, system::MojoTi meTicks) | 385 where F: FnOnce(&mut Self, |
| 386 &mut Box<Handler + 'h>, | |
| 387 Token, | |
| 388 system::MojoTimeTicks) | |
| 381 { | 389 { |
| 382 // Logic for pulling out the handler as well as its current deadline. | 390 // Logic for pulling out the handler as well as its current deadline. |
| 383 // | 391 // |
| 384 // Unfortunately, pulling out the handler value here and "onto the stack " | 392 // Unfortunately, pulling out the handler value here and "onto the stack " |
| 385 // (it probably won't actually end up on the stack thanks to optimizatio ns) | 393 // (it probably won't actually end up on the stack thanks to optimizatio ns) |
| 386 // is necessary since otherwise the borrow checker complains that we pas s | 394 // is necessary since otherwise the borrow checker complains that we pas s |
| 387 // a mutable reference to the RunLoop and the handler (as &mut self) to | 395 // a mutable reference to the RunLoop and the handler (as &mut self) to |
| 388 // the callbacks at the same time. This is understandably unsafe since | 396 // the callbacks at the same time. This is understandably unsafe since |
| 389 // modifying the hashmap with register and deregister can invalidate the | 397 // modifying the hashmap with register and deregister can invalidate the |
| 390 // reference to self in the callback. In the C++ bindings and in other R ust | 398 // reference to self in the callback. In the C++ bindings and in other R ust |
| 391 // event loops this is exactly what happens, but I avoided this. The dow nside | 399 // event loops this is exactly what happens, but I avoided this. The dow nside |
| 392 // is that we can no longer nest event loop run() calls. Once we put a h andler | 400 // is that we can no longer nest event loop run() calls. Once we put a h andler |
| 393 // onto the stack here, we can no longer call its callback in a nested m anner | 401 // onto the stack here, we can no longer call its callback in a nested m anner |
| 394 // from the RunLoop. I could just enable nesting with this one restricti on, that | 402 // from the RunLoop. I could just enable nesting with this one restricti on, that |
| 395 // the handler calling run() will always be ignored, but this is unintui tive. | 403 // the handler calling run() will always be ignored, but this is unintui tive. |
| 396 let (mut handler, deadline) = match self.handlers.get_mut(&token) { | 404 let (mut handler, deadline) = match self.handlers.get_mut(&token) { |
| 397 Some(ref_info) => (match ref_info.take() { | 405 Some(ref_info) => { |
| 398 Some(handler) => handler, | 406 (match ref_info.take() { |
| 399 None => return, | 407 Some(handler) => handler, |
| 400 }, ref_info.deadline()), | 408 None => return, |
| 409 }, | |
| 410 ref_info.deadline()) | |
| 411 } | |
| 401 None => return, | 412 None => return, |
| 402 }; | 413 }; |
| 403 // Call the closure that will invoke the callbacks. | 414 // Call the closure that will invoke the callbacks. |
| 404 invoker(self, &mut handler, token.clone(), deadline); | 415 invoker(self, &mut handler, token.clone(), deadline); |
| 405 // Restore the handler to its location in the HashMap | 416 // Restore the handler to its location in the HashMap |
| 406 if let Some(ref_info) = self.handlers.get_mut(&token) { | 417 if let Some(ref_info) = self.handlers.get_mut(&token) { |
| 407 ref_info.give(handler); | 418 ref_info.give(handler); |
| 408 } | 419 } |
| 409 } | 420 } |
| 410 | 421 |
| 411 /// For all the results we received, we notify the respective handle | 422 /// For all the results we received, we notify the respective handle |
| 412 /// owners of the results by calling their given callbacks. | 423 /// owners of the results by calling their given callbacks. |
| 413 /// | 424 /// |
| 414 /// We do NOT dequeue notified handles. | 425 /// We do NOT dequeue notified handles. |
| 415 fn notify_of_results(&mut self, results: &Vec<system::WaitSetResult>) { | 426 fn notify_of_results(&mut self, results: &Vec<system::WaitSetResult>) { |
| 416 debug_assert!(!self.handlers.is_empty()); | 427 debug_assert!(!self.handlers.is_empty()); |
| 417 for wsr in results.iter() { | 428 for wsr in results.iter() { |
| 418 let token = Token(wsr.cookie()); | 429 let token = Token(wsr.cookie()); |
| 419 self.get_handler_with(&token, move |runloop, boxed_handler, token, _ dl| { | 430 self.get_handler_with(&token, move |runloop, boxed_handler, token, _ dl| { |
| 420 let handler = boxed_handler.as_mut(); | 431 let handler = boxed_handler.as_mut(); |
| 421 match wsr.result() { | 432 match wsr.result() { |
| 422 MojoResult::Okay => { | 433 MojoResult::Okay => handler.on_ready(runloop, token), |
| 423 handler.on_ready(runloop, token) | |
| 424 }, | |
| 425 MojoResult::Cancelled => { | 434 MojoResult::Cancelled => { |
| 426 handler.on_error(runloop, token, WaitError::HandleClosed ) | 435 handler.on_error(runloop, token, WaitError::HandleClosed ) |
| 427 }, | 436 } |
| 428 MojoResult::Busy => { | 437 MojoResult::Busy => handler.on_error(runloop, token, WaitErr or::HandleBusy), |
| 429 handler.on_error(runloop, token, WaitError::HandleBusy) | |
| 430 }, | |
| 431 MojoResult::FailedPrecondition => { | 438 MojoResult::FailedPrecondition => { |
| 432 handler.on_error(runloop, token, WaitError::Unsatisfiabl e) | 439 handler.on_error(runloop, token, WaitError::Unsatisfiabl e) |
| 433 }, | 440 } |
| 434 other => panic!("Unexpected result received after waiting: { }", other), | 441 other => panic!("Unexpected result received after waiting: { }", other), |
| 435 } | 442 } |
| 436 }); | 443 }); |
| 437 // In order to quit as soon as possible, we should check to quit aft er every | 444 // In order to quit as soon as possible, we should check to quit aft er every |
| 438 // potential handler call, as any of them could have signaled to qui t. | 445 // potential handler call, as any of them could have signaled to qui t. |
| 439 if self.should_quit { | 446 if self.should_quit { |
| 440 break; | 447 break; |
| 441 } | 448 } |
| 442 } | 449 } |
| 443 } | 450 } |
| 444 | 451 |
| 445 /// Since the deadline expired, we notify the relevant handle | 452 /// Since the deadline expired, we notify the relevant handle |
| 446 /// owners of the expiration by calling their given callbacks. | 453 /// owners of the expiration by calling their given callbacks. |
| 447 /// | 454 /// |
| 448 /// We do NOT dequeue notified handles. | 455 /// We do NOT dequeue notified handles. |
| 449 fn notify_of_expired(&mut self, expired_deadline: system::MojoTimeTicks) { | 456 fn notify_of_expired(&mut self, expired_deadline: system::MojoTimeTicks) { |
| 450 debug_assert!(!self.handlers.is_empty()); | 457 debug_assert!(!self.handlers.is_empty()); |
| 451 let mut top = match self.deadlines.peek() { | 458 let mut top = match self.deadlines.peek() { |
| 452 Some(info) => info.clone(), | 459 Some(info) => info.clone(), |
| 453 None => panic!("Should not be in notify_of_expired without at least one deadline!"), | 460 None => panic!("Should not be in notify_of_expired without at least one deadline!"), |
| 454 }; | 461 }; |
| 455 while expired_deadline >= top.deadline() { | 462 while expired_deadline >= top.deadline() { |
| 456 let next_deadline = top.deadline(); | 463 let next_deadline = top.deadline(); |
| 457 self.get_handler_with(top.token(), move |runloop, boxed_handler, tok en, expected_dl| { | 464 self.get_handler_with(top.token(), |
| 458 let handler = boxed_handler.as_mut(); | 465 move |runloop, boxed_handler, token, expected_ dl| { |
| 459 if next_deadline == expected_dl { | 466 let handler = boxed_handler.as_mut(); |
| 460 handler.on_timeout(runloop, token); | 467 if next_deadline == expected_dl { |
| 461 } | 468 handler.on_timeout(runloop, token); |
| 462 }); | 469 } |
| 470 }); | |
| 463 // In order to quit as soon as possible, we should check to quit aft er every | 471 // In order to quit as soon as possible, we should check to quit aft er every |
| 464 // potential handler call, as any of them could have signaled to qui t. | 472 // potential handler call, as any of them could have signaled to qui t. |
| 465 if self.should_quit { | 473 if self.should_quit { |
| 466 break; | 474 break; |
| 467 } | 475 } |
| 468 // Remove the deadline | 476 // Remove the deadline |
| 469 self.deadlines.pop(); | 477 self.deadlines.pop(); |
| 470 // Break if the next deadline has not yet expired. | 478 // Break if the next deadline has not yet expired. |
| 471 top = match self.deadlines.peek() { | 479 top = match self.deadlines.peek() { |
| 472 Some(info) => info.clone(), | 480 Some(info) => info.clone(), |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 492 self.notify_of_results(results_buffer); | 500 self.notify_of_results(results_buffer); |
| 493 // Clear the buffer since we don't need the results anymore. | 501 // Clear the buffer since we don't need the results anymore. |
| 494 // Helps prevent a copy if we resize the buffer. | 502 // Helps prevent a copy if we resize the buffer. |
| 495 results_buffer.clear(); | 503 results_buffer.clear(); |
| 496 // Increase the size of the buffer if there are more results | 504 // Increase the size of the buffer if there are more results |
| 497 // we could be holding. | 505 // we could be holding. |
| 498 let capacity = results_buffer.capacity(); | 506 let capacity = results_buffer.capacity(); |
| 499 if capacity < MAXIMUM_WAIT_SET_NUM_RESULTS && capacity < (max_re sults) as usize { | 507 if capacity < MAXIMUM_WAIT_SET_NUM_RESULTS && capacity < (max_re sults) as usize { |
| 500 results_buffer.reserve(capacity); | 508 results_buffer.reserve(capacity); |
| 501 } | 509 } |
| 502 }, | 510 } |
| 503 Err(result) => { | 511 Err(result) => { |
| 504 assert_eq!(result, MojoResult::DeadlineExceeded); | 512 assert_eq!(result, MojoResult::DeadlineExceeded); |
| 505 self.notify_of_expired(deadline); | 513 self.notify_of_expired(deadline); |
| 506 }, | 514 } |
| 507 } | 515 } |
| 508 } | 516 } |
| 509 | 517 |
| 510 /// Loop forever until a callback tells us to quit. | 518 /// Loop forever until a callback tells us to quit. |
| 511 pub fn run(&mut self) { | 519 pub fn run(&mut self) { |
| 512 // It's an error it already be running... | 520 // It's an error it already be running... |
| 513 if self.running { | 521 if self.running { |
| 514 panic!("RunLoop is already running!"); | 522 panic!("RunLoop is already running!"); |
| 515 } | 523 } |
| 516 self.running = true; | 524 self.running = true; |
| 517 self.should_quit = false; | 525 self.should_quit = false; |
| 518 let mut buffer: Vec<system::WaitSetResult> = Vec::with_capacity(INITIAL_ WAIT_SET_NUM_RESULTS); | 526 let mut buffer: Vec<system::WaitSetResult> = |
| 527 Vec::with_capacity(INITIAL_WAIT_SET_NUM_RESULTS); | |
| 519 // Loop while we haven't been signaled to quit, and there's something to wait on. | 528 // Loop while we haven't been signaled to quit, and there's something to wait on. |
| 520 while !self.should_quit && !self.handlers.is_empty() { | 529 while !self.should_quit && !self.handlers.is_empty() { |
| 521 self.wait(&mut buffer) | 530 self.wait(&mut buffer) |
| 522 } | 531 } |
| 523 self.running = false; | 532 self.running = false; |
| 524 } | 533 } |
| 525 | 534 |
| 526 /// Set a flag to quit at the next available moment. | 535 /// Set a flag to quit at the next available moment. |
| 527 pub fn quit(&mut self) { | 536 pub fn quit(&mut self) { |
| 528 self.should_quit = true; | 537 self.should_quit = true; |
| 529 } | 538 } |
| 530 } | 539 } |
| 531 | 540 |
| 532 /// Provides a scope to modify the current thread's runloop. | 541 /// Provides a scope to modify the current thread's runloop. |
| 533 pub fn with_current<F>(modifier: F) | 542 pub fn with_current<F>(modifier: F) |
| 534 where F: FnOnce(&mut RunLoop) | 543 where F: FnOnce(&mut RunLoop) |
| 535 { | 544 { |
| 536 TL_RUN_LOOP.with(|ref_runloop| { | 545 TL_RUN_LOOP.with(|ref_runloop| { |
| 537 let mut runloop = ref_runloop.borrow_mut(); | 546 let mut runloop = ref_runloop.borrow_mut(); |
| 538 modifier(&mut *runloop); | 547 modifier(&mut *runloop); |
| 539 }); | 548 }); |
| 540 } | 549 } |
| OLD | NEW |