Fix a bug with the scheduler and destructor order

The PausibleIdleCallback must have some handle into the event loop, and because
struct destructors are run in order of top-to-bottom in order of fields, this
meant that the event loop was getting destroyed before the idle callback was
getting destroyed.

I can't confirm that this fixes a problem in how we use libuv, but it does
semantically fix a problem for usage with other event loops.
This commit is contained in:
Alex Crichton 2013-10-22 14:59:21 -07:00
parent 3f5b2219cc
commit 3b30377e14
2 changed files with 63 additions and 1 deletions

View File

@ -85,7 +85,17 @@ pub struct Scheduler {
priv yield_check_count: uint,
/// A flag to tell the scheduler loop it needs to do some stealing
/// in order to introduce randomness as part of a yield
priv steal_for_yield: bool
priv steal_for_yield: bool,
// n.b. currently destructors of an object are run in top-to-bottom in order
// of field declaration. Due to its nature, the pausible idle callback
// must have some sort of handle to the event loop, so it needs to get
// destroyed before the event loop itself. For this reason, we destroy
// the event loop last to ensure that any unsafe references to it are
// destroyed before it's actually destroyed.
/// The event loop used to drive the scheduler and perform I/O
event_loop: ~EventLoopObject,
}
/// An indication of how hard to work on a given operation, the difference

View File

@ -0,0 +1,52 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// In theory, it doesn't matter what order destructors are run in for rust
// because we have explicit ownership of values meaning that there's no need to
// run one before another. With unsafe code, however, there may be a safe
// interface which relies on fields having their destructors run in a particular
// order. At the time of this writing, std::rt::sched::Scheduler is an example
// of a structure which contains unsafe handles to FFI-like types, and the
// destruction order of the fields matters in the sense that some handles need
// to get destroyed before others.
//
// In C++, destruction order happens bottom-to-top in order of field
// declarations, but we currently run them top-to-bottom. I don't think the
// order really matters that much as long as we define what it is.
struct A;
struct B;
struct C {
a: A,
b: B,
}
static mut hit: bool = false;
impl Drop for A {
fn drop(&mut self) {
unsafe {
assert!(!hit);
hit = true;
}
}
}
impl Drop for B {
fn drop(&mut self) {
unsafe {
assert!(hit);
}
}
}
pub fn main() {
let _c = C { a: A, b: B };
}