Skip to content

Commit 3b30377

Browse files
committed
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.
1 parent 3f5b221 commit 3b30377

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

src/libstd/rt/sched.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,17 @@ pub struct Scheduler {
8585
priv yield_check_count: uint,
8686
/// A flag to tell the scheduler loop it needs to do some stealing
8787
/// in order to introduce randomness as part of a yield
88-
priv steal_for_yield: bool
88+
priv steal_for_yield: bool,
89+
90+
// n.b. currently destructors of an object are run in top-to-bottom in order
91+
// of field declaration. Due to its nature, the pausible idle callback
92+
// must have some sort of handle to the event loop, so it needs to get
93+
// destroyed before the event loop itself. For this reason, we destroy
94+
// the event loop last to ensure that any unsafe references to it are
95+
// destroyed before it's actually destroyed.
96+
97+
/// The event loop used to drive the scheduler and perform I/O
98+
event_loop: ~EventLoopObject,
8999
}
90100

91101
/// An indication of how hard to work on a given operation, the difference
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// In theory, it doesn't matter what order destructors are run in for rust
12+
// because we have explicit ownership of values meaning that there's no need to
13+
// run one before another. With unsafe code, however, there may be a safe
14+
// interface which relies on fields having their destructors run in a particular
15+
// order. At the time of this writing, std::rt::sched::Scheduler is an example
16+
// of a structure which contains unsafe handles to FFI-like types, and the
17+
// destruction order of the fields matters in the sense that some handles need
18+
// to get destroyed before others.
19+
//
20+
// In C++, destruction order happens bottom-to-top in order of field
21+
// declarations, but we currently run them top-to-bottom. I don't think the
22+
// order really matters that much as long as we define what it is.
23+
24+
struct A;
25+
struct B;
26+
struct C {
27+
a: A,
28+
b: B,
29+
}
30+
31+
static mut hit: bool = false;
32+
33+
impl Drop for A {
34+
fn drop(&mut self) {
35+
unsafe {
36+
assert!(!hit);
37+
hit = true;
38+
}
39+
}
40+
}
41+
42+
impl Drop for B {
43+
fn drop(&mut self) {
44+
unsafe {
45+
assert!(hit);
46+
}
47+
}
48+
}
49+
50+
pub fn main() {
51+
let _c = C { a: A, b: B };
52+
}

0 commit comments

Comments
 (0)