about summary refs log tree commit diff
path: root/src/libnative
diff options
context:
space:
mode:
authorAaron Turon <aturon@mozilla.com>2014-10-16 18:57:11 -0700
committerAaron Turon <aturon@mozilla.com>2014-11-08 20:40:39 -0800
commitb8f1193bb1bb66610f479cd78e3dc5526e93058d (patch)
tree4fbf269f6f0e31069f62ce6539c7d2ccfb7c0f35 /src/libnative
parent0f98e75b69d16edce9ca60d7961b8440856a3f72 (diff)
downloadrust-b8f1193bb1bb66610f479cd78e3dc5526e93058d.tar.gz
rust-b8f1193bb1bb66610f479cd78e3dc5526e93058d.zip
Runtime removal: refactor timer
This patch continues runtime removal by moving out timer-related code
into `sys`.

Because this eliminates APIs in `libnative` and `librustrt`, it is a:

[breaking-change]

This functionality is likely to be available publicly, in some form,
from `std` in the future.
Diffstat (limited to 'src/libnative')
-rw-r--r--src/libnative/io/mod.rs17
-rw-r--r--src/libnative/io/timer_unix.rs285
-rw-r--r--src/libnative/io/timer_windows.rs210
3 files changed, 0 insertions, 512 deletions
diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs
index 29370dee88b..5d6d23f5f03 100644
--- a/src/libnative/io/mod.rs
+++ b/src/libnative/io/mod.rs
@@ -29,19 +29,6 @@ use std::os;
 use std::rt::rtio::{mod, IoResult, IoError};
 use std::num;
 
-#[cfg(any(target_os = "macos",
-          target_os = "ios",
-          target_os = "freebsd",
-          target_os = "dragonfly",
-          target_os = "android",
-          target_os = "linux"))]
-#[path = "timer_unix.rs"]
-pub mod timer;
-
-#[cfg(target_os = "windows")]
-#[path = "timer_windows.rs"]
-pub mod timer;
-
 #[cfg(windows)]
 #[path = "tty_windows.rs"]
 mod tty;
@@ -112,10 +99,6 @@ impl IoFactory {
 }
 
 impl rtio::IoFactory for IoFactory {
-    // misc
-    fn timer_init(&mut self) -> IoResult<Box<rtio::RtioTimer + Send>> {
-        timer::Timer::new().map(|t| box t as Box<rtio::RtioTimer + Send>)
-    }
     #[cfg(unix)]
     fn tty_open(&mut self, fd: c_int, _readable: bool)
                 -> IoResult<Box<rtio::RtioTTY + Send>> {
diff --git a/src/libnative/io/timer_unix.rs b/src/libnative/io/timer_unix.rs
deleted file mode 100644
index c26e2e76cee..00000000000
--- a/src/libnative/io/timer_unix.rs
+++ /dev/null
@@ -1,285 +0,0 @@
-// 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.
-
-//! Timers for non-Linux/non-Windows OSes
-//!
-//! This module implements timers with a worker thread, select(), and a lot of
-//! witchcraft that turns out to be horribly inaccurate timers. The unfortunate
-//! part is that I'm at a loss of what else to do one these OSes. This is also
-//! why Linux has a specialized timerfd implementation and windows has its own
-//! implementation (they're more accurate than this one).
-//!
-//! The basic idea is that there is a worker thread that's communicated to via a
-//! channel and a pipe, the pipe is used by the worker thread in a select()
-//! syscall with a timeout. The timeout is the "next timer timeout" while the
-//! channel is used to send data over to the worker thread.
-//!
-//! Whenever the call to select() times out, then a channel receives a message.
-//! Whenever the call returns that the file descriptor has information, then the
-//! channel from timers is drained, enqueuing all incoming requests.
-//!
-//! The actual implementation of the helper thread is a sorted array of
-//! timers in terms of target firing date. The target is the absolute time at
-//! which the timer should fire. Timers are then re-enqueued after a firing if
-//! the repeat boolean is set.
-//!
-//! Naturally, all this logic of adding times and keeping track of
-//! relative/absolute time is a little lossy and not quite exact. I've done the
-//! best I could to reduce the amount of calls to 'now()', but there's likely
-//! still inaccuracies trickling in here and there.
-//!
-//! One of the tricky parts of this implementation is that whenever a timer is
-//! acted upon, it must cancel whatever the previous action was (if one is
-//! active) in order to act like the other implementations of this timer. In
-//! order to do this, the timer's inner pointer is transferred to the worker
-//! thread. Whenever the timer is modified, it first takes ownership back from
-//! the worker thread in order to modify the same data structure. This has the
-//! side effect of "cancelling" the previous requests while allowing a
-//! re-enqueuing later on.
-//!
-//! Note that all time units in this file are in *milliseconds*.
-
-use libc;
-use std::mem;
-use std::os;
-use std::ptr;
-use std::rt::rtio;
-use std::rt::rtio::IoResult;
-use std::sync::atomic;
-use std::comm;
-
-use io::c;
-use platform_imp::fs::FileDesc;
-use io::helper_thread::Helper;
-
-helper_init!(static HELPER: Helper<Req>)
-
-pub struct Timer {
-    id: uint,
-    inner: Option<Box<Inner>>,
-}
-
-pub struct Inner {
-    cb: Option<Box<rtio::Callback + Send>>,
-    interval: u64,
-    repeat: bool,
-    target: u64,
-    id: uint,
-}
-
-pub enum Req {
-    // Add a new timer to the helper thread.
-    NewTimer(Box<Inner>),
-
-    // Remove a timer based on its id and then send it back on the channel
-    // provided
-    RemoveTimer(uint, Sender<Box<Inner>>),
-}
-
-// returns the current time (in milliseconds)
-pub fn now() -> u64 {
-    unsafe {
-        let mut now: libc::timeval = mem::zeroed();
-        assert_eq!(c::gettimeofday(&mut now, ptr::null_mut()), 0);
-        return (now.tv_sec as u64) * 1000 + (now.tv_usec as u64) / 1000;
-    }
-}
-
-fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
-    let mut set: c::fd_set = unsafe { mem::zeroed() };
-
-    let mut fd = FileDesc::new(input, true);
-    let mut timeout: libc::timeval = unsafe { mem::zeroed() };
-
-    // active timers are those which are able to be selected upon (and it's a
-    // sorted list, and dead timers are those which have expired, but ownership
-    // hasn't yet been transferred back to the timer itself.
-    let mut active: Vec<Box<Inner>> = vec![];
-    let mut dead = vec![];
-
-    // inserts a timer into an array of timers (sorted by firing time)
-    fn insert(t: Box<Inner>, active: &mut Vec<Box<Inner>>) {
-        match active.iter().position(|tm| tm.target > t.target) {
-            Some(pos) => { active.insert(pos, t); }
-            None => { active.push(t); }
-        }
-    }
-
-    // signals the first requests in the queue, possible re-enqueueing it.
-    fn signal(active: &mut Vec<Box<Inner>>,
-              dead: &mut Vec<(uint, Box<Inner>)>) {
-        let mut timer = match active.remove(0) {
-            Some(timer) => timer, None => return
-        };
-        let mut cb = timer.cb.take().unwrap();
-        cb.call();
-        if timer.repeat {
-            timer.cb = Some(cb);
-            timer.target += timer.interval;
-            insert(timer, active);
-        } else {
-            dead.push((timer.id, timer));
-        }
-    }
-
-    'outer: loop {
-        let timeout = if active.len() == 0 {
-            // Empty array? no timeout (wait forever for the next request)
-            ptr::null_mut()
-        } else {
-            let now = now();
-            // If this request has already expired, then signal it and go
-            // through another iteration
-            if active[0].target <= now {
-                signal(&mut active, &mut dead);
-                continue;
-            }
-
-            // The actual timeout listed in the requests array is an
-            // absolute date, so here we translate the absolute time to a
-            // relative time.
-            let tm = active[0].target - now;
-            timeout.tv_sec = (tm / 1000) as libc::time_t;
-            timeout.tv_usec = ((tm % 1000) * 1000) as libc::suseconds_t;
-            &mut timeout as *mut libc::timeval
-        };
-
-        c::fd_set(&mut set, input);
-        match unsafe {
-            c::select(input + 1, &mut set, ptr::null_mut(),
-                      ptr::null_mut(), timeout)
-        } {
-            // timed out
-            0 => signal(&mut active, &mut dead),
-
-            // file descriptor write woke us up, we've got some new requests
-            1 => {
-                loop {
-                    match messages.try_recv() {
-                        Err(comm::Disconnected) => {
-                            assert!(active.len() == 0);
-                            break 'outer;
-                        }
-
-                        Ok(NewTimer(timer)) => insert(timer, &mut active),
-
-                        Ok(RemoveTimer(id, ack)) => {
-                            match dead.iter().position(|&(i, _)| id == i) {
-                                Some(i) => {
-                                    let (_, i) = dead.remove(i).unwrap();
-                                    ack.send(i);
-                                    continue
-                                }
-                                None => {}
-                            }
-                            let i = active.iter().position(|i| i.id == id);
-                            let i = i.expect("no timer found");
-                            let t = active.remove(i).unwrap();
-                            ack.send(t);
-                        }
-                        Err(..) => break
-                    }
-                }
-
-                // drain the file descriptor
-                let mut buf = [0];
-                assert_eq!(fd.inner_read(buf).ok().unwrap(), 1);
-            }
-
-            -1 if os::errno() == libc::EINTR as int => {}
-            n => panic!("helper thread panicked in select() with error: {} ({})",
-                       n, os::last_os_error())
-        }
-    }
-}
-
-impl Timer {
-    pub fn new() -> IoResult<Timer> {
-        // See notes above regarding using int return value
-        // instead of ()
-        HELPER.boot(|| {}, helper);
-
-        static ID: atomic::AtomicUint = atomic::INIT_ATOMIC_UINT;
-        let id = ID.fetch_add(1, atomic::Relaxed);
-        Ok(Timer {
-            id: id,
-            inner: Some(box Inner {
-                cb: None,
-                interval: 0,
-                target: 0,
-                repeat: false,
-                id: id,
-            })
-        })
-    }
-
-    pub fn sleep(ms: u64) {
-        let mut to_sleep = libc::timespec {
-            tv_sec: (ms / 1000) as libc::time_t,
-            tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
-        };
-        while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
-            if os::errno() as int != libc::EINTR as int {
-                panic!("failed to sleep, but not because of EINTR?");
-            }
-        }
-    }
-
-    fn inner(&mut self) -> Box<Inner> {
-        match self.inner.take() {
-            Some(i) => i,
-            None => {
-                let (tx, rx) = channel();
-                HELPER.send(RemoveTimer(self.id, tx));
-                rx.recv()
-            }
-        }
-    }
-}
-
-impl rtio::RtioTimer for Timer {
-    fn sleep(&mut self, msecs: u64) {
-        let mut inner = self.inner();
-        inner.cb = None; // cancel any previous request
-        self.inner = Some(inner);
-
-        Timer::sleep(msecs);
-    }
-
-    fn oneshot(&mut self, msecs: u64, cb: Box<rtio::Callback + Send>) {
-        let now = now();
-        let mut inner = self.inner();
-
-        inner.repeat = false;
-        inner.cb = Some(cb);
-        inner.interval = msecs;
-        inner.target = now + msecs;
-
-        HELPER.send(NewTimer(inner));
-    }
-
-    fn period(&mut self, msecs: u64, cb: Box<rtio::Callback + Send>) {
-        let now = now();
-        let mut inner = self.inner();
-
-        inner.repeat = true;
-        inner.cb = Some(cb);
-        inner.interval = msecs;
-        inner.target = now + msecs;
-
-        HELPER.send(NewTimer(inner));
-    }
-}
-
-impl Drop for Timer {
-    fn drop(&mut self) {
-        self.inner = Some(self.inner());
-    }
-}
diff --git a/src/libnative/io/timer_windows.rs b/src/libnative/io/timer_windows.rs
deleted file mode 100644
index c17c541fc01..00000000000
--- a/src/libnative/io/timer_windows.rs
+++ /dev/null
@@ -1,210 +0,0 @@
-// 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.
-
-//! Timers based on Windows WaitableTimers
-//!
-//! This implementation is meant to be used solely on windows. As with other
-//! implementations, there is a worker thread which is doing all the waiting on
-//! a large number of timers for all active timers in the system. This worker
-//! thread uses the select() equivalent, WaitForMultipleObjects. One of the
-//! objects being waited on is a signal into the worker thread to notify that
-//! the incoming channel should be looked at.
-//!
-//! Other than that, the implementation is pretty straightforward in terms of
-//! the other two implementations of timers with nothing *that* new showing up.
-
-use libc;
-use std::ptr;
-use std::rt::rtio;
-use std::rt::rtio::{IoResult, Callback};
-use std::comm;
-
-use io::helper_thread::Helper;
-
-helper_init!(static HELPER: Helper<Req>)
-
-pub struct Timer {
-    obj: libc::HANDLE,
-    on_worker: bool,
-}
-
-pub enum Req {
-    NewTimer(libc::HANDLE, Box<Callback + Send>, bool),
-    RemoveTimer(libc::HANDLE, Sender<()>),
-}
-
-fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
-    let mut objs = vec![input];
-    let mut chans = vec![];
-
-    'outer: loop {
-        let idx = unsafe {
-            imp::WaitForMultipleObjects(objs.len() as libc::DWORD,
-                                        objs.as_ptr(),
-                                        0 as libc::BOOL,
-                                        libc::INFINITE)
-        };
-
-        if idx == 0 {
-            loop {
-                match messages.try_recv() {
-                    Ok(NewTimer(obj, c, one)) => {
-                        objs.push(obj);
-                        chans.push((c, one));
-                    }
-                    Ok(RemoveTimer(obj, c)) => {
-                        c.send(());
-                        match objs.iter().position(|&o| o == obj) {
-                            Some(i) => {
-                                drop(objs.remove(i));
-                                drop(chans.remove(i - 1));
-                            }
-                            None => {}
-                        }
-                    }
-                    Err(comm::Disconnected) => {
-                        assert_eq!(objs.len(), 1);
-                        assert_eq!(chans.len(), 0);
-                        break 'outer;
-                    }
-                    Err(..) => break
-                }
-            }
-        } else {
-            let remove = {
-                match &mut chans[idx as uint - 1] {
-                    &(ref mut c, oneshot) => { c.call(); oneshot }
-                }
-            };
-            if remove {
-                drop(objs.remove(idx as uint));
-                drop(chans.remove(idx as uint - 1));
-            }
-        }
-    }
-}
-
-// returns the current time (in milliseconds)
-pub fn now() -> u64 {
-    let mut ticks_per_s = 0;
-    assert_eq!(unsafe { libc::QueryPerformanceFrequency(&mut ticks_per_s) }, 1);
-    let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s};
-    let mut ticks = 0;
-    assert_eq!(unsafe { libc::QueryPerformanceCounter(&mut ticks) }, 1);
-
-    return (ticks as u64 * 1000) / (ticks_per_s as u64);
-}
-
-impl Timer {
-    pub fn new() -> IoResult<Timer> {
-        HELPER.boot(|| {}, helper);
-
-        let obj = unsafe {
-            imp::CreateWaitableTimerA(ptr::null_mut(), 0, ptr::null())
-        };
-        if obj.is_null() {
-            Err(super::last_error())
-        } else {
-            Ok(Timer { obj: obj, on_worker: false, })
-        }
-    }
-
-    pub fn sleep(ms: u64) {
-        use std::rt::rtio::RtioTimer;
-        let mut t = Timer::new().ok().expect("must allocate a timer!");
-        t.sleep(ms);
-    }
-
-    fn remove(&mut self) {
-        if !self.on_worker { return }
-
-        let (tx, rx) = channel();
-        HELPER.send(RemoveTimer(self.obj, tx));
-        rx.recv();
-
-        self.on_worker = false;
-    }
-}
-
-impl rtio::RtioTimer for Timer {
-    fn sleep(&mut self, msecs: u64) {
-        self.remove();
-
-        // there are 10^6 nanoseconds in a millisecond, and the parameter is in
-        // 100ns intervals, so we multiply by 10^4.
-        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
-        assert_eq!(unsafe {
-            imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(),
-                                  ptr::null_mut(), 0)
-        }, 1);
-
-        let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) };
-    }
-
-    fn oneshot(&mut self, msecs: u64, cb: Box<Callback + Send>) {
-        self.remove();
-
-        // see above for the calculation
-        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
-        assert_eq!(unsafe {
-            imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(),
-                                  ptr::null_mut(), 0)
-        }, 1);
-
-        HELPER.send(NewTimer(self.obj, cb, true));
-        self.on_worker = true;
-    }
-
-    fn period(&mut self, msecs: u64, cb: Box<Callback + Send>) {
-        self.remove();
-
-        // see above for the calculation
-        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
-        assert_eq!(unsafe {
-            imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG,
-                                  ptr::null_mut(), ptr::null_mut(), 0)
-        }, 1);
-
-        HELPER.send(NewTimer(self.obj, cb, false));
-        self.on_worker = true;
-    }
-}
-
-impl Drop for Timer {
-    fn drop(&mut self) {
-        self.remove();
-        assert!(unsafe { libc::CloseHandle(self.obj) != 0 });
-    }
-}
-
-mod imp {
-    use libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER,
-                    LONG, LPVOID, DWORD, c_void};
-
-    pub type PTIMERAPCROUTINE = *mut c_void;
-
-    extern "system" {
-        pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES,
-                                    bManualReset: BOOL,
-                                    lpTimerName: LPCSTR) -> HANDLE;
-        pub fn SetWaitableTimer(hTimer: HANDLE,
-                                pDueTime: *const LARGE_INTEGER,
-                                lPeriod: LONG,
-                                pfnCompletionRoutine: PTIMERAPCROUTINE,
-                                lpArgToCompletionRoutine: LPVOID,
-                                fResume: BOOL) -> BOOL;
-        pub fn WaitForMultipleObjects(nCount: DWORD,
-                                      lpHandles: *const HANDLE,
-                                      bWaitAll: BOOL,
-                                      dwMilliseconds: DWORD) -> DWORD;
-        pub fn WaitForSingleObject(hHandle: HANDLE,
-                                   dwMilliseconds: DWORD) -> DWORD;
-    }
-}