Skip to content

Commit 352ac2e

Browse files
committed
Fixed a memory leak caused by the singleton idle callback failing to close correctly. The problem was that the close function requires running inside a callback in the event loop, but we were trying to close the idle watcher after the loop returned from run. The fix was to just call run again to process this callback. There is an additional tweak to move the initialization logic fully into bootstrap, so tasks that do not ever call run do not have problems destructing.
1 parent e5ccf13 commit 352ac2e

File tree

2 files changed

+17
-14
lines changed

2 files changed

+17
-14
lines changed

src/libstd/rt/sched.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ pub struct Scheduler {
8080
/// A fast XorShift rng for scheduler use
8181
rng: XorShiftRng,
8282
/// A toggleable idle callback
83-
idle_callback: ~PausibleIdleCallback
83+
idle_callback: Option<~PausibleIdleCallback>
8484
}
8585

8686
impl Scheduler {
@@ -107,9 +107,6 @@ impl Scheduler {
107107
friend: Option<SchedHandle>)
108108
-> Scheduler {
109109

110-
let mut event_loop = event_loop;
111-
let idle_callback = event_loop.pausible_idle_callback();
112-
113110
Scheduler {
114111
sleeper_list: sleeper_list,
115112
message_queue: MessageQueue::new(),
@@ -125,7 +122,7 @@ impl Scheduler {
125122
run_anything: run_anything,
126123
friend_handle: friend,
127124
rng: XorShiftRng::new(),
128-
idle_callback: idle_callback
125+
idle_callback: None
129126
}
130127
}
131128

@@ -140,6 +137,9 @@ impl Scheduler {
140137

141138
let mut this = self;
142139

140+
// Build an Idle callback.
141+
this.idle_callback = Some(this.event_loop.pausible_idle_callback());
142+
143143
// Initialize the TLS key.
144144
local_ptr::init_tls_key();
145145

@@ -153,7 +153,7 @@ impl Scheduler {
153153
// Before starting our first task, make sure the idle callback
154154
// is active. As we do not start in the sleep state this is
155155
// important.
156-
this.idle_callback.start(Scheduler::run_sched_once);
156+
this.idle_callback.get_mut_ref().start(Scheduler::run_sched_once);
157157

158158
// Now, as far as all the scheduler state is concerned, we are
159159
// inside the "scheduler" context. So we can act like the
@@ -169,6 +169,12 @@ impl Scheduler {
169169
rtdebug!("starting scheduler %u", sched.sched_id());
170170
sched.run();
171171

172+
// Close the idle callback.
173+
let mut sched = Local::take::<Scheduler>();
174+
sched.idle_callback.get_mut_ref().close();
175+
// Make one go through the loop to run the close callback.
176+
sched.run();
177+
172178
// Now that we are done with the scheduler, clean up the
173179
// scheduler task. Do so by removing it from TLS and manually
174180
// cleaning up the memory it uses. As we didn't actually call
@@ -182,9 +188,6 @@ impl Scheduler {
182188
let message = stask.sched.get_mut_ref().message_queue.pop();
183189
assert!(message.is_none());
184190

185-
// Close the idle callback.
186-
stask.sched.get_mut_ref().idle_callback.close();
187-
188191
stask.destroyed = true;
189192
}
190193

@@ -230,7 +233,7 @@ impl Scheduler {
230233

231234
// Assume that we need to continue idling unless we reach the
232235
// end of this function without performing an action.
233-
sched.idle_callback.resume();
236+
sched.idle_callback.get_mut_ref().resume();
234237

235238
// First we check for scheduler messages, these are higher
236239
// priority than regular tasks.
@@ -257,12 +260,12 @@ impl Scheduler {
257260
let handle = sched.make_handle();
258261
sched.sleeper_list.push(handle);
259262
// Since we are sleeping, deactivate the idle callback.
260-
sched.idle_callback.pause();
263+
sched.idle_callback.get_mut_ref().pause();
261264
} else {
262265
rtdebug!("not sleeping, already doing so or no_sleep set");
263266
// We may not be sleeping, but we still need to deactivate
264267
// the idle callback.
265-
sched.idle_callback.pause();
268+
sched.idle_callback.get_mut_ref().pause();
266269
}
267270

268271
// Finished a cycle without using the Scheduler. Place it back
@@ -461,7 +464,7 @@ impl Scheduler {
461464

462465
// We push the task onto our local queue clone.
463466
this.work_queue.push(task);
464-
this.idle_callback.resume();
467+
this.idle_callback.get_mut_ref().resume();
465468

466469
// We've made work available. Notify a
467470
// sleeping scheduler.

src/libstd/rt/uv/uvio.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl UvPausibleIdleCallback {
176176
self.pause();
177177
if !self.closed {
178178
self.closed = true;
179-
self.watcher.close(||());
179+
self.watcher.close(||{});
180180
}
181181
}
182182
}

0 commit comments

Comments
 (0)