1 // Copyright 2013-2014 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::bookkeeping;
25 use std::rt;
26 use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
27
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 Sender<Req> = 0 as *mut Sender<Req>;
37 static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal;
38
39 static mut TIMER_HELPER_EXIT: StaticNativeMutex = NATIVE_MUTEX_INIT;
40
41 pub fn boot(helper: fn(imp::signal, Receiver<Req>)) {
42 static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
43 static mut INITIALIZED: bool = false;
44
45 unsafe {
46 let mut _guard = LOCK.lock();
47 if !INITIALIZED {
48 let (tx, rx) = channel();
49 // promote this to a shared channel
50 drop(tx.clone());
51 HELPER_CHAN = cast::transmute(box tx);
52 let (receive, send) = imp::new();
53 HELPER_SIGNAL = send;
54
55 task::spawn(proc() {
56 bookkeeping::decrement();
57 helper(receive, rx);
58 TIMER_HELPER_EXIT.lock().signal()
59 });
60
61 rt::at_exit(proc() { shutdown() });
62 INITIALIZED = true;
63 }
64 }
65 }
66
67 pub fn send(req: Req) {
68 unsafe {
69 assert!(!HELPER_CHAN.is_null());
70 (*HELPER_CHAN).send(req);
71 imp::signal(HELPER_SIGNAL);
72 }
73 }
74
75 fn shutdown() {
76 // Request a shutdown, and then wait for the task to exit
77 unsafe {
78 let guard = TIMER_HELPER_EXIT.lock();
79 send(Shutdown);
80 guard.wait();
81 drop(guard);
82 TIMER_HELPER_EXIT.destroy();
83 }
84
85
86 // Clean up after ther helper thread
87 unsafe {
88 imp::close(HELPER_SIGNAL);
89 let _chan: Box<Sender<Req>> = cast::transmute(HELPER_CHAN);
90 HELPER_CHAN = 0 as *mut Sender<Req>;
91 HELPER_SIGNAL = 0 as imp::signal;
92 }
93 }
94
95 #[cfg(unix)]
96 mod imp {
97 use libc;
98 use std::os;
99
100 use io::file::FileDesc;
101
102 pub type signal = libc::c_int;
103
104 pub fn new() -> (signal, signal) {
105 let pipe = os::pipe();
106 (pipe.input, pipe.out)
107 }
108
109 pub fn signal(fd: libc::c_int) {
110 FileDesc::new(fd, false).inner_write([0]).unwrap();
111 }
112
113 pub fn close(fd: libc::c_int) {
114 let _fd = FileDesc::new(fd, true);
115 }
116 }
117
118 #[cfg(windows)]
119 mod imp {
120 use libc::{BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle};
121 use std::ptr;
122 use libc;
123
124 pub type signal = HANDLE;
125
126 pub fn new() -> (HANDLE, HANDLE) {
127 unsafe {
128 let handle = CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
129 ptr::null());
130 (handle, handle)
131 }
132 }
133
134 pub fn signal(handle: HANDLE) {
135 assert!(unsafe { SetEvent(handle) != 0 });
136 }
137
138 pub fn close(handle: HANDLE) {
139 assert!(unsafe { CloseHandle(handle) != 0 });
140 }
141
142 extern "system" {
143 fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
144 bManualReset: BOOL,
145 bInitialState: BOOL,
146 lpName: LPCSTR) -> HANDLE;
147 fn SetEvent(hEvent: HANDLE) -> BOOL;
148 }
149 }