Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: mojo/public/rust/src/bindings/run_loop.rs

Issue 2250183003: Make the fuchsia mojo/public repo the source of truth. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/public/rust/src/bindings/mojom.rs ('k') | mojo/public/rust/src/bindings/util.rs » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « mojo/public/rust/src/bindings/mojom.rs ('k') | mojo/public/rust/src/bindings/util.rs » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698