(index<- )        ./libnative/io/timer_helper.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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(helperfn(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(reqReq) {
  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 _chanBox<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(fdlibc::c_int) {
 110          FileDesc::new(fd, false).inner_write([0]).unwrap();
 111      }
 112  
 113      pub fn close(fdlibc::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  }