Skip to content

Commit 7ea063e

Browse files
committed
auto merge of #11294 : alexcrichton/rust/native-timer, r=brson
Commit messages have the fun details Closes #10925
2 parents fce7922 + b8e4383 commit 7ea063e

File tree

11 files changed

+1236
-30
lines changed

11 files changed

+1236
-30
lines changed

src/libnative/bookkeeping.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ pub fn wait_for_other_tasks() {
4545
TASK_LOCK.wait();
4646
}
4747
TASK_LOCK.unlock();
48+
TASK_LOCK.destroy();
4849
}
4950
}

src/libnative/io/mod.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ pub mod file;
4646
pub mod process;
4747
pub mod net;
4848

49+
#[cfg(target_os = "macos")]
50+
#[cfg(target_os = "freebsd")]
51+
#[path = "timer_other.rs"]
52+
pub mod timer;
53+
54+
#[cfg(target_os = "linux")]
55+
#[cfg(target_os = "android")]
56+
#[path = "timer_timerfd.rs"]
57+
pub mod timer;
58+
59+
#[cfg(target_os = "win32")]
60+
#[path = "timer_win32.rs"]
61+
pub mod timer;
62+
63+
mod timer_helper;
64+
4965
type IoResult<T> = Result<T, IoError>;
5066

5167
fn unimpl() -> IoError {
@@ -249,7 +265,7 @@ impl rtio::IoFactory for IoFactory {
249265

250266
// misc
251267
fn timer_init(&mut self) -> IoResult<~RtioTimer> {
252-
Err(unimpl())
268+
timer::Timer::new().map(|t| ~t as ~RtioTimer)
253269
}
254270
fn spawn(&mut self, config: ProcessConfig)
255271
-> IoResult<(~RtioProcess, ~[Option<~RtioPipe>])> {

src/libnative/io/timer_helper.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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+
//! Implementation of the helper thread for the timer module
12+
//!
13+
//! This module contains the management necessary for the timer worker thread.
14+
//! This thread is responsible for performing the send()s on channels for timers
15+
//! that are using channels instead of a blocking call.
16+
//!
17+
//! The timer thread is lazily initialized, and it's shut down via the
18+
//! `shutdown` function provided. It must be maintained as an invariant that
19+
//! `shutdown` is only called when the entire program is finished. No new timers
20+
//! can be created in the future and there must be no active timers at that
21+
//! time.
22+
23+
use std::cast;
24+
use std::rt;
25+
use std::unstable::mutex::{Once, ONCE_INIT};
26+
27+
use bookkeeping;
28+
use io::timer::{Req, Shutdown};
29+
use task;
30+
31+
// You'll note that these variables are *not* protected by a lock. These
32+
// variables are initialized with a Once before any Timer is created and are
33+
// only torn down after everything else has exited. This means that these
34+
// variables are read-only during use (after initialization) and both of which
35+
// are safe to use concurrently.
36+
static mut HELPER_CHAN: *mut SharedChan<Req> = 0 as *mut SharedChan<Req>;
37+
static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal;
38+
39+
pub fn boot(helper: fn(imp::signal, Port<Req>)) {
40+
static mut INIT: Once = ONCE_INIT;
41+
42+
unsafe {
43+
INIT.doit(|| {
44+
let (msgp, msgc) = SharedChan::new();
45+
HELPER_CHAN = cast::transmute(~msgc);
46+
let (receive, send) = imp::new();
47+
HELPER_SIGNAL = send;
48+
49+
do task::spawn {
50+
bookkeeping::decrement();
51+
helper(receive, msgp);
52+
}
53+
54+
rt::at_exit(proc() { shutdown() });
55+
})
56+
}
57+
}
58+
59+
pub fn send(req: Req) {
60+
unsafe {
61+
assert!(!HELPER_CHAN.is_null());
62+
(*HELPER_CHAN).send(req);
63+
imp::signal(HELPER_SIGNAL);
64+
}
65+
}
66+
67+
fn shutdown() {
68+
// We want to wait for the entire helper task to exit, and in doing so it
69+
// will attempt to decrement the global task count. When the helper was
70+
// created, it decremented the count so it wouldn't count towards preventing
71+
// the program to exit, so here we pair that manual decrement with a manual
72+
// increment. We will then wait for the helper thread to exit by calling
73+
// wait_for_other_tasks.
74+
bookkeeping::increment();
75+
76+
// Request a shutdown, and then wait for the task to exit
77+
send(Shutdown);
78+
bookkeeping::wait_for_other_tasks();
79+
80+
// Clean up after ther helper thread
81+
unsafe {
82+
imp::close(HELPER_SIGNAL);
83+
let _chan: ~SharedChan<Req> = cast::transmute(HELPER_CHAN);
84+
HELPER_CHAN = 0 as *mut SharedChan<Req>;
85+
HELPER_SIGNAL = 0 as imp::signal;
86+
}
87+
}
88+
89+
#[cfg(unix)]
90+
mod imp {
91+
use std::libc;
92+
use std::os;
93+
94+
use io::file::FileDesc;
95+
96+
pub type signal = libc::c_int;
97+
98+
pub fn new() -> (signal, signal) {
99+
let pipe = os::pipe();
100+
(pipe.input, pipe.out)
101+
}
102+
103+
pub fn signal(fd: libc::c_int) {
104+
FileDesc::new(fd, false).inner_write([0]);
105+
}
106+
107+
pub fn close(fd: libc::c_int) {
108+
let _fd = FileDesc::new(fd, true);
109+
}
110+
}
111+
112+
#[cfg(windows)]
113+
mod imp {
114+
use std::libc::{BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle};
115+
use std::ptr;
116+
use std::libc;
117+
118+
pub type signal = HANDLE;
119+
120+
pub fn new() -> (HANDLE, HANDLE) {
121+
unsafe {
122+
let handle = CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
123+
ptr::null());
124+
(handle, handle)
125+
}
126+
}
127+
128+
pub fn signal(handle: HANDLE) {
129+
unsafe { SetEvent(handle); }
130+
}
131+
132+
pub fn close(handle: HANDLE) {
133+
unsafe { CloseHandle(handle); }
134+
}
135+
136+
extern "system" {
137+
fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
138+
bManualReset: BOOL,
139+
bInitialState: BOOL,
140+
lpName: LPCSTR) -> HANDLE;
141+
fn SetEvent(hEvent: HANDLE) -> BOOL;
142+
}
143+
}

0 commit comments

Comments
 (0)