(index<- )        ./libstd/io/signal.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 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  /*!
  12  
  13  Signal handling
  14  
  15  This modules provides bindings to receive signals safely, built on top of the
  16  local I/O factory. There are a number of defined signals which can be caught,
  17  but not all signals will work across all platforms (windows doesn't have
  18  definitions for a number of signals.
  19  
  20  */
  21  
  22  use clone::Clone;
  23  use comm::{Sender, Receiver, channel};
  24  use io;
  25  use iter::Iterator;
  26  use kinds::Send;
  27  use mem::drop;
  28  use option::{Some, None};
  29  use owned::Box;
  30  use result::{Ok, Err};
  31  use rt::rtio::{IoFactory, LocalIo, RtioSignal};
  32  use slice::ImmutableVector;
  33  use vec::Vec;
  34  
  35  /// Signals that can be sent and received
  36  #[repr(int)]
  37  #[deriving(Eq, Hash, Show)]
  38  pub enum Signum {
  39      /// Equivalent to SIGBREAK, delivered when the user presses Ctrl-Break.
  40      Break = 21i,
  41      /// Equivalent to SIGHUP, delivered when the user closes the terminal
  42      /// window. On delivery of HangUp, the program is given approximately
  43      /// 10 seconds to perform any cleanup. After that, Windows will
  44      /// unconditionally terminate it.
  45      HangUp = 1i,
  46      /// Equivalent to SIGINT, delivered when the user presses Ctrl-c.
  47      Interrupt = 2i,
  48      /// Equivalent to SIGQUIT, delivered when the user presses Ctrl-\.
  49      Quit = 3i,
  50      /// Equivalent to SIGTSTP, delivered when the user presses Ctrl-z.
  51      StopTemporarily = 20i,
  52      /// Equivalent to SIGUSR1.
  53      User1 = 10i,
  54      /// Equivalent to SIGUSR2.
  55      User2 = 12i,
  56      /// Equivalent to SIGWINCH, delivered when the console has been resized.
  57      /// WindowSizeChange may not be delivered in a timely manner; size change
  58      /// will only be detected when the cursor is being moved.
  59      WindowSizeChange = 28i,
  60  }
  61  
  62  /// Listener provides a receiver to listen for registered signals.
  63  ///
  64  /// Listener automatically unregisters its handles once it is out of scope.
  65  /// However, clients can still unregister signums manually.
  66  ///
  67  /// # Example
  68  ///
  69  /// ```rust,no_run
  70  /// # #![allow(unused_must_use)]
  71  /// use std::io::signal::{Listener, Interrupt};
  72  ///
  73  /// let mut listener = Listener::new();
  74  /// listener.register(Interrupt);
  75  ///
  76  /// loop {
  77  ///     match listener.rx.recv() {
  78  ///         Interrupt => println!("Got Interrupt'ed"),
  79  ///         _ => (),
  80  ///     }
  81  /// }
  82  /// ```
  83  pub struct Listener {
  84      /// A map from signums to handles to keep the handles in memory
  85      handles: Vec<(Signum, Box<RtioSignal:Send>)>,
  86      /// This is where all the handles send signums, which are received by
  87      /// the clients from the receiver.
  88      tx: Sender<Signum>,
  89  
  90      /// Clients of Listener can `recv()` on this receiver. This is exposed to
  91      /// allow selection over it as well as manipulation of the receiver
  92      /// directly.
  93      pub rx: Receiver<Signum>,
  94  }
  95  
  96  impl Listener {
  97      /// Creates a new listener for signals. Once created, signals are bound via
  98      /// the `register` method (otherwise nothing will ever be received)
  99      pub fn new() -> Listener {
 100          let (tx, rx) = channel();
 101          Listener {
 102              tx: tx,
 103              rx: rx,
 104              handles: vec!(),
 105          }
 106      }
 107  
 108      /// Listen for a signal, returning true when successfully registered for
 109      /// signum. Signals can be received using `recv()`.
 110      ///
 111      /// Once a signal is registered, this listener will continue to receive
 112      /// notifications of signals until it is unregistered. This occurs
 113      /// regardless of the number of other listeners registered in other tasks
 114      /// (or on this task).
 115      ///
 116      /// Signals are still received if there is no task actively waiting for
 117      /// a signal, and a later call to `recv` will return the signal that was
 118      /// received while no task was waiting on it.
 119      ///
 120      /// # Error
 121      ///
 122      /// If this function fails to register a signal handler, then an error will
 123      /// be returned.
 124      pub fn register(&mut self, signumSignum) -> io::IoResult<()> {
 125          if self.handles.iter().any(|&(sig, _)| sig == signum) {
 126              return Ok(()); // self is already listening to signum, so succeed
 127          }
 128          match LocalIo::maybe_raise(|io| {
 129              io.signal(signum, self.tx.clone())
 130          }) {
 131              Ok(handle) => {
 132                  self.handles.push((signum, handle));
 133                  Ok(())
 134              }
 135              Err(e) => Err(e)
 136          }
 137      }
 138  
 139      /// Unregisters a signal. If this listener currently had a handler
 140      /// registered for the signal, then it will stop receiving any more
 141      /// notification about the signal. If the signal has already been received,
 142      /// it may still be returned by `recv`.
 143      pub fn unregister(&mut self, signumSignum) {
 144          match self.handles.iter().position(|&(i, _)| i == signum) {
 145              Some(i) => drop(self.handles.remove(i)),
 146              None => {}
 147          }
 148      }
 149  }
 150  
 151  #[cfg(test, unix)]
 152  mod test_unix {
 153      use prelude::*;
 154      use libc;
 155      use comm::Empty;
 156      use io::timer;
 157      use super::{Listener, Interrupt};
 158  
 159      fn sigint() {
 160          unsafe {
 161              libc::funcs::posix88::signal::kill(libc::getpid(), libc::SIGINT);
 162          }
 163      }
 164  
 165      #[test] #[cfg(not(target_os="android"))] // FIXME(#10378)
 166      fn test_io_signal_smoketest() {
 167          let mut signal = Listener::new();
 168          signal.register(Interrupt).unwrap();
 169          sigint();
 170          timer::sleep(10);
 171          match signal.rx.recv() {
 172              Interrupt => (),
 173              s => fail!("Expected Interrupt, got {:?}", s),
 174          }
 175      }
 176  
 177      #[test] #[cfg(not(target_os="android"))] // FIXME(#10378)
 178      fn test_io_signal_two_signal_one_signum() {
 179          let mut s1 = Listener::new();
 180          let mut s2 = Listener::new();
 181          s1.register(Interrupt).unwrap();
 182          s2.register(Interrupt).unwrap();
 183          sigint();
 184          timer::sleep(10);
 185          match s1.rx.recv() {
 186              Interrupt => (),
 187              s => fail!("Expected Interrupt, got {:?}", s),
 188          }
 189          match s2.rx.recv() {
 190              Interrupt => (),
 191              s => fail!("Expected Interrupt, got {:?}", s),
 192          }
 193      }
 194  
 195      #[test] #[cfg(not(target_os="android"))] // FIXME(#10378)
 196      fn test_io_signal_unregister() {
 197          let mut s1 = Listener::new();
 198          let mut s2 = Listener::new();
 199          s1.register(Interrupt).unwrap();
 200          s2.register(Interrupt).unwrap();
 201          s2.unregister(Interrupt);
 202          sigint();
 203          timer::sleep(10);
 204          assert_eq!(s2.rx.try_recv(), Err(Empty));
 205      }
 206  }
 207  
 208  #[cfg(test, windows)]
 209  mod test_windows {
 210      use super::{User1, Listener};
 211      use result::{Ok, Err};
 212  
 213      #[test]
 214      fn test_io_signal_invalid_signum() {
 215          let mut s = Listener::new();
 216          match s.register(User1) {
 217              Ok(..) => {
 218                  fail!("Unexpected successful registry of signum {:?}", User1);
 219              }
 220              Err(..) => {}
 221          }
 222      }
 223  }


libstd/io/signal.rs:37:28-37:28 -enum- definition:
pub enum Signum {
    /// Equivalent to SIGBREAK, delivered when the user presses Ctrl-Break.
    Break = 21i,
references:- 12
84:     /// A map from signums to handles to keep the handles in memory
85:     handles: Vec<(Signum, Box<RtioSignal:Send>)>,
86:     /// This is where all the handles send signums, which are received by
--
142:     /// it may still be returned by `recv`.
143:     pub fn unregister(&mut self, signum: Signum) {
144:         match self.handles.iter().position(|&(i, _)| i == signum) {
libstd/rt/rtio.rs:
198:             -> IoResult<Box<RtioTTY:Send>>;
199:     fn signal(&mut self, signal: Signum, channel: Sender<Signum>)
200:         -> IoResult<Box<RtioSignal:Send>>;
libstd/io/signal.rs:
87:     /// the clients from the receiver.
88:     tx: Sender<Signum>,


libstd/io/signal.rs:82:8-82:8 -struct- definition:
/// ```
pub struct Listener {
    /// A map from signums to handles to keep the handles in memory
references:- 3
96: impl Listener {
97:     /// Creates a new listener for signals. Once created, signals are bound via
98:     /// the `register` method (otherwise nothing will ever be received)
99:     pub fn new() -> Listener {
100:         let (tx, rx) = channel();
101:         Listener {
102:             tx: tx,