/// Mock implementations for testing
mod mock;
+/// Signal handling
+pub mod signal;
+
/// The default buffer size for various I/O operations
static DEFAULT_BUF_SIZE: uint = 1024 * 64;
--- /dev/null
+// 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.
+
+use comm::{Port, SharedChan, stream};
+use hashmap;
+use option::{Some, None};
+use result::{Err, Ok};
+use rt::io::io_error;
+use rt::local::Local;
+use rt::rtio::{EventLoop, RtioSignalObject};
+use rt::sched::Scheduler;
+
+#[deriving(Eq, IterBytes)]
+pub enum Signum {
+ /// Equivalent to SIGBREAK, delivered when the user presses Ctrl-Break.
+ Break = 21i,
+ /// Equivalent to SIGHUP, delivered when the user closes the terminal
+ /// window. On delivery of HangUp, the program is given approximately
+ /// 10 seconds to perfom any cleanup. After that, Windows will
+ /// unconditionally terminate it.
+ HangUp = 1i,
+ /// Equivalent to SIGINT, delivered when the user presses Ctrl-c.
+ Interrupt = 2i,
+ /// Equivalent to SIGQUIT, delivered when the user presses Ctrl-\.
+ Quit = 3i,
+ /// Equivalent to SIGTSTP, delivered when the user presses Ctrl-z.
+ StopTemporarily = 20i,
+ /// Equivalent to SIGUSR1.
+ User1 = 10i,
+ /// Equivalent to SIGUSR2.
+ User2 = 12i,
+ /// Equivalent to SIGWINCH, delivered when the console has been resized.
+ /// WindowSizeChange may not be delivered in a timely manner; size change
+ /// will only be detected when the cursor is being moved.
+ WindowSizeChange = 28i,
+}
+
+/// Listener provides a port to listen for registered signals.
+///
+/// Listener automatically unregisters its handles once it is out of scope.
+/// However, clients can still unregister signums manually.
+///
+/// Example usage:
+///
+/// ```rust
+/// use std::rt::io::signal;
+/// use std::task;
+///
+/// let mut listener = signal::Listener();
+/// listener.register(signal::Interrupt);
+///
+/// do task::spawn {
+/// loop {
+/// match listener.recv() {
+/// signal::Interrupt => println("Got Interrupt'ed"),
+/// _ => (),
+/// }
+/// }
+/// }
+///
+/// ```
+pub struct Listener {
+ /// A map from signums to handles to keep the handles in memory
+ priv handles: hashmap::HashMap<Signum, ~RtioSignalObject>,
+ /// chan is where all the handles send signums, which are received by
+ /// the clients from port.
+ priv chan: SharedChan<Signum>,
+ /// Clients of Listener can `recv()` from this port
+ port: Port<Signum>,
+}
+
+impl Listener {
+ pub fn new() -> Listener {
+ let (port, chan) = stream();
+ Listener {
+ chan: SharedChan::new(chan),
+ port: port,
+ handles: hashmap::HashMap::new(),
+ }
+ }
+
+ /// Listen for a signal, returning true when successfully registered for
+ /// signum. Signals can be received using `recv()`.
+ pub fn register(&mut self, signum: Signum) -> bool {
+ match self.handles.find(&signum) {
+ Some(_) => true, // self is already listening to signum, so succeed
+ None => {
+ let chan = self.chan.clone();
+ let handle = unsafe {
+ rtdebug!("Listener::register: borrowing io to init UvSignal");
+ let sched: *mut Scheduler = Local::unsafe_borrow();
+ rtdebug!("about to init handle");
+ (*sched).event_loop.signal(signum, chan)
+ };
+ match handle {
+ Ok(w) => {
+ self.handles.insert(signum, w);
+ true
+ },
+ Err(ioerr) => {
+ rtdebug!("Listener::register: failed to init: {:?}", ioerr);
+ io_error::cond.raise(ioerr);
+ false
+ },
+ }
+ },
+ }
+ }
+
+ /// Unregister a signal.
+ pub fn unregister(&mut self, signum: Signum) {
+ self.handles.pop(&signum);
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use libc;
+ use rt::io::timer;
+ use super::*;
+
+ // kill is only available on Unixes
+ #[cfg(unix)]
+ #[fixed_stack_segment]
+ fn sigint() {
+ unsafe {
+ libc::funcs::posix88::signal::kill(libc::getpid(), libc::SIGINT);
+ }
+ }
+
+ #[test]
+ fn test_io_signal_smoketest() {
+ let mut signal = Listener::new();
+ signal.register(Interrupt);
+ sigint();
+ timer::sleep(10);
+ match signal.port.recv() {
+ Interrupt => (),
+ s => fail2!("Expected Interrupt, got {:?}", s),
+ }
+ }
+
+ #[test]
+ fn test_io_signal_two_signal_one_signum() {
+ let mut s1 = Listener::new();
+ let mut s2 = Listener::new();
+ s1.register(Interrupt);
+ s2.register(Interrupt);
+ sigint();
+ timer::sleep(10);
+ match s1.port.recv() {
+ Interrupt => (),
+ s => fail2!("Expected Interrupt, got {:?}", s),
+ }
+ match s1.port.recv() {
+ Interrupt => (),
+ s => fail2!("Expected Interrupt, got {:?}", s),
+ }
+ }
+
+ #[test]
+ fn test_io_signal_unregister() {
+ let mut s1 = Listener::new();
+ let mut s2 = Listener::new();
+ s1.register(Interrupt);
+ s2.register(Interrupt);
+ s2.unregister(Interrupt);
+ sigint();
+ timer::sleep(10);
+ if s2.port.peek() {
+ fail2!("Unexpected {:?}", s2.port.recv());
+ }
+ }
+
+ #[cfg(windows)]
+ #[test]
+ fn test_io_signal_invalid_signum() {
+ let mut s = Listener::new();
+ if s.register(User1) {
+ fail2!("Unexpected successful registry of signum {:?}", User1);
+ }
+ }
+}
use libc;
use option::*;
use result::*;
+use comm::SharedChan;
use libc::c_int;
use c_str::CString;
use ai = rt::io::net::addrinfo;
use rt::io::IoError;
+use rt::io::signal::Signum;
use super::io::process::ProcessConfig;
use super::io::net::ip::{IpAddr, SocketAddr};
use path::Path;
fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>;
fn tty_open(&mut self, fd: c_int, readable: bool)
-> Result<~RtioTTY, IoError>;
+ fn signal(&mut self, signal: Signum, channel: SharedChan<Signum>)
+ -> Result<~RtioSignal, IoError>;
}
pub trait RtioTcpListener : RtioSocket {
fn resume(&mut self);
fn close(&mut self);
}
+
+pub trait RtioSignal {}
use ptr::null;
use unstable::finally::Finally;
use rt::io::net::ip::SocketAddr;
+use rt::io::signal::Signum;
use rt::io::IoError;
pub use self::async::AsyncWatcher;
pub use self::process::Process;
pub use self::pipe::Pipe;
+pub use self::signal::SignalWatcher;
/// The implementation of `rtio` for libuv
pub mod uvio;
pub mod process;
pub mod pipe;
pub mod tty;
+pub mod signal;
/// XXX: Loop(*handle) is buggy with destructors. Normal structs
/// with dtors may not be destructured, but tuple structs can,
pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>);
pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>);
pub type UdpSendCallback = ~fn(UdpWatcher, Option<UvError>);
+pub type SignalCallback = ~fn(SignalWatcher, Signum);
/// Callbacks used by StreamWatchers, set as custom data on the foreign handle.
udp_recv_cb: Option<UdpReceiveCallback>,
udp_send_cb: Option<UdpSendCallback>,
exit_cb: Option<ExitCallback>,
+ signal_cb: Option<SignalCallback>,
}
pub trait WatcherInterop {
udp_recv_cb: None,
udp_send_cb: None,
exit_cb: None,
+ signal_cb: None,
};
let data = transmute::<~WatcherData, *c_void>(data);
uvll::set_data_for_uv_handle(self.native_handle(), data);
--- /dev/null
+// 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.
+
+use cast;
+use option::Some;
+use libc::{c_int, c_void};
+use result::{Err, Ok, Result};
+use rt::io::IoError;
+use rt::io::signal::Signum;
+use rt::uv::{Loop, NativeHandle, NullCallback, SignalCallback, UvError, Watcher};
+use rt::uv::uv_error_to_io_error;
+use rt::uv::uvll;
+
+pub struct SignalWatcher(*uvll::uv_signal_t);
+
+impl Watcher for SignalWatcher { }
+
+impl SignalWatcher {
+ pub fn new(loop_: &mut Loop) -> SignalWatcher {
+ unsafe {
+ let handle = uvll::malloc_handle(uvll::UV_SIGNAL);
+ assert!(handle.is_not_null());
+ assert!(0 == uvll::signal_init(loop_.native_handle(), handle));
+ let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle);
+ watcher.install_watcher_data();
+ return watcher;
+ }
+ }
+
+ pub fn start(&mut self, signum: Signum, callback: SignalCallback) -> Result<(), IoError> {
+ {
+ let data = self.get_watcher_data();
+ data.signal_cb = Some(callback);
+ }
+
+ let ret = unsafe {
+ uvll::signal_start(self.native_handle(), signal_cb, signum as c_int)
+ };
+
+ return match ret {
+ 0 => Ok(()),
+ _ => Err(uv_error_to_io_error(UvError(ret))),
+ };
+
+ extern fn signal_cb(handle: *uvll::uv_signal_t, signum: c_int) {
+ let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle);
+ let data = watcher.get_watcher_data();
+ let cb = data.signal_cb.get_ref();
+ (*cb)(watcher, unsafe { cast::transmute(signum as i64) });
+ }
+ }
+
+ pub fn stop(&mut self) {
+ unsafe {
+ uvll::signal_stop(self.native_handle());
+ }
+ }
+
+ pub fn close(self, cb: NullCallback) {
+ let mut watcher = self;
+ {
+ let data = watcher.get_watcher_data();
+ assert!(data.close_cb.is_none());
+ data.close_cb = Some(cb);
+ }
+
+ unsafe {
+ uvll::close(watcher.native_handle(), close_cb);
+ }
+
+ extern fn close_cb(handle: *uvll::uv_signal_t) {
+ let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle);
+ {
+ let data = watcher.get_watcher_data();
+ data.close_cb.take_unwrap()();
+ }
+ watcher.drop_watcher_data();
+ unsafe {
+ uvll::free_handle(handle as *c_void);
+ }
+ }
+ }
+}
+
+impl NativeHandle<*uvll::uv_signal_t> for SignalWatcher {
+ fn from_native_handle(handle: *uvll::uv_signal_t) -> SignalWatcher {
+ SignalWatcher(handle)
+ }
+
+ fn native_handle(&self) -> *uvll::uv_signal_t {
+ match self { &SignalWatcher(ptr) => ptr }
+ }
+}
use cast;
use cell::Cell;
use clone::Clone;
+use comm::{SendDeferred, SharedChan};
use libc::{c_int, c_uint, c_void, pid_t};
use ops::Drop;
use option::*;
use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create,
CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite,
FileStat};
+use rt::io::signal::Signum;
use task;
use ai = rt::io::net::addrinfo;
Err(e) => Err(uv_error_to_io_error(e))
}
}
+
+ fn signal(&mut self, signum: Signum, channel: SharedChan<Signum>)
+ -> Result<~RtioSignalObject, IoError> {
+ let watcher = SignalWatcher::new(self.uv_loop());
+ let home = get_handle_to_current_scheduler!();
+ let mut signal = ~UvSignal::new(watcher, home);
+ match signal.watcher.start(signum, |_, _| channel.send_deferred(signum)) {
+ Ok(()) => Ok(signal),
+ Err(e) => Err(uv_error_to_io_error(e)),
+ }
+ }
}
pub struct UvTcpListener {
}
}
+pub struct UvSignal {
+ watcher: signal::SignalWatcher,
+ home: SchedHandle,
+}
+
+impl HomingIO for UvSignal {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
+
+impl UvSignal {
+ fn new(w: signal::SignalWatcher, home: SchedHandle) -> UvSignal {
+ UvSignal { watcher: w, home: home }
+ }
+}
+
+impl RtioSignal for UvSignal {}
+
+impl Drop for UvSignal {
+ fn drop(&mut self) {
+ do self.home_for_io_with_sched |self_, scheduler| {
+ rtdebug!("closing UvSignal");
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do self_.watcher.close {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+ }
+ }
+}
+
// this function is full of lies
unsafe fn local_io() -> &'static mut IoFactory {
do Local::borrow |sched: &mut Scheduler| {
pub type uv_process_t = c_void;
pub type uv_pipe_t = c_void;
pub type uv_tty_t = c_void;
+pub type uv_signal_t = c_void;
pub struct uv_timespec_t {
tv_sec: libc::c_long,
pub type uv_exit_cb = extern "C" fn(handle: *uv_process_t,
exit_status: c_int,
term_signal: c_int);
+pub type uv_signal_cb = extern "C" fn(handle: *uv_signal_t,
+ signum: c_int);
pub type sockaddr = c_void;
pub type sockaddr_in = c_void;
rust_uv_guess_handle(fd)
}
+pub unsafe fn signal_init(loop_: *uv_loop_t, handle: *uv_signal_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ return rust_uv_signal_init(loop_, handle);
+}
+pub unsafe fn signal_start(handle: *uv_signal_t,
+ signal_cb: uv_signal_cb,
+ signum: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ return rust_uv_signal_start(handle, signal_cb, signum);
+}
+pub unsafe fn signal_stop(handle: *uv_signal_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ return rust_uv_signal_stop(handle);
+}
+
pub struct uv_err_data {
priv err_name: ~str,
priv err_msg: ~str,
//#[rust_stack] pub fn rust_AI_NUMERICSERV() -> c_int;
//#[rust_stack] pub fn rust_AI_PASSIVE() -> c_int;
//#[rust_stack] pub fn rust_AI_V4MAPPED() -> c_int;
+
+ fn rust_uv_signal_init(loop_: *uv_loop_t, handle: *uv_signal_t) -> c_int;
+ fn rust_uv_signal_start(handle: *uv_signal_t,
+ signal_cb: uv_signal_cb,
+ signum: c_int) -> c_int;
+ fn rust_uv_signal_stop(handle: *uv_signal_t) -> c_int;
}
rust_uv_guess_handle(int fd) {
return uv_guess_handle(fd);
}
+
+extern "C" int
+rust_uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
+ return uv_signal_init(loop, handle);
+}
+
+extern "C" int
+rust_uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+ return uv_signal_start(handle, signal_cb, signum);
+}
+
+extern "C" int
+rust_uv_signal_stop(uv_signal_t* handle) {
+ return uv_signal_stop(handle);
+}
rust_set_stdio_container_stream
rust_uv_process_pid
rust_uv_pipe_init
+rust_uv_signal_init
+rust_uv_signal_start
+rust_uv_signal_stop
sdhtml_renderer
sd_markdown_new
sd_markdown_render