8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
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
+
11
22
use comm:: { Port , SharedChan , stream} ;
12
23
use hashmap;
13
24
use option:: { Some , None } ;
14
25
use result:: { Err , Ok } ;
15
26
use rt:: io:: io_error;
16
- use rt:: local:: Local ;
17
- use rt:: rtio:: { EventLoop , RtioSignalObject } ;
18
- use rt:: sched:: Scheduler ;
27
+ use rt:: rtio:: { IoFactory , RtioSignal , with_local_io} ;
19
28
20
29
#[ deriving( Eq , IterBytes ) ]
21
30
pub enum Signum {
@@ -47,19 +56,18 @@ pub enum Signum {
47
56
/// Listener automatically unregisters its handles once it is out of scope.
48
57
/// However, clients can still unregister signums manually.
49
58
///
50
- /// Example usage:
59
+ /// # Example
51
60
///
52
61
/// ```rust
53
- /// use std::rt::io::signal;
54
- /// use std::task;
62
+ /// use std::rt::io::signal::{Listener, Interrupt};
55
63
///
56
- /// let mut listener = signal::Listener ();
64
+ /// let mut listener = Listener::new ();
57
65
/// listener.register(signal::Interrupt);
58
66
///
59
- /// do task:: spawn {
67
+ /// do spawn {
60
68
/// loop {
61
- /// match listener.recv() {
62
- /// signal:: Interrupt => println("Got Interrupt'ed"),
69
+ /// match listener.port. recv() {
70
+ /// Interrupt => println("Got Interrupt'ed"),
63
71
/// _ => (),
64
72
/// }
65
73
/// }
@@ -68,15 +76,20 @@ pub enum Signum {
68
76
/// ```
69
77
pub struct Listener {
70
78
/// A map from signums to handles to keep the handles in memory
71
- priv handles : hashmap:: HashMap < Signum , ~RtioSignalObject > ,
79
+ priv handles : hashmap:: HashMap < Signum , ~RtioSignal > ,
72
80
/// chan is where all the handles send signums, which are received by
73
81
/// the clients from port.
74
82
priv chan : SharedChan < Signum > ,
75
- /// Clients of Listener can `recv()` from this port
83
+
84
+ /// Clients of Listener can `recv()` from this port. This is exposed to
85
+ /// allow selection over this port as well as manipulation of the port
86
+ /// directly.
76
87
port : Port < Signum > ,
77
88
}
78
89
79
90
impl Listener {
91
+ /// Creates a new listener for signals. Once created, signals are bound via
92
+ /// the `register` method (otherwise nothing will ever be received)
80
93
pub fn new ( ) -> Listener {
81
94
let ( port, chan) = stream ( ) ;
82
95
Listener {
@@ -88,33 +101,43 @@ impl Listener {
88
101
89
102
/// Listen for a signal, returning true when successfully registered for
90
103
/// signum. Signals can be received using `recv()`.
104
+ ///
105
+ /// Once a signal is registered, this listener will continue to receive
106
+ /// notifications of signals until it is unregistered. This occurs
107
+ /// regardless of the number of other listeners registered in other tasks
108
+ /// (or on this task).
109
+ ///
110
+ /// Signals are still received if there is no task actively waiting for
111
+ /// a signal, and a later call to `recv` will return the signal that was
112
+ /// received while no task was waiting on it.
113
+ ///
114
+ /// # Failure
115
+ ///
116
+ /// If this function fails to register a signal handler, then an error will
117
+ /// be raised on the `io_error` condition and the function will return
118
+ /// false.
91
119
pub fn register ( & mut self , signum : Signum ) -> bool {
92
- match self . handles . find ( & signum) {
93
- Some ( _) => true , // self is already listening to signum, so succeed
94
- None => {
95
- let chan = self . chan . clone ( ) ;
96
- let handle = unsafe {
97
- rtdebug ! ( "Listener::register: borrowing io to init UvSignal" ) ;
98
- let sched: * mut Scheduler = Local :: unsafe_borrow ( ) ;
99
- rtdebug ! ( "about to init handle" ) ;
100
- ( * sched) . event_loop . signal ( signum, chan)
101
- } ;
102
- match handle {
103
- Ok ( w) => {
104
- self . handles . insert ( signum, w) ;
105
- true
106
- } ,
107
- Err ( ioerr) => {
108
- rtdebug ! ( "Listener::register: failed to init: {:?}" , ioerr) ;
109
- io_error:: cond. raise ( ioerr) ;
110
- false
111
- } ,
112
- }
113
- } ,
120
+ if self . handles . contains_key ( & signum) {
121
+ return true ; // self is already listening to signum, so succeed
114
122
}
123
+ do with_local_io |io| {
124
+ match io. signal ( signum, self . chan . clone ( ) ) {
125
+ Ok ( w) => {
126
+ self . handles . insert ( signum, w) ;
127
+ Some ( ( ) )
128
+ } ,
129
+ Err ( ioerr) => {
130
+ io_error:: cond. raise ( ioerr) ;
131
+ None
132
+ }
133
+ }
134
+ } . is_some ( )
115
135
}
116
136
117
- /// Unregister a signal.
137
+ /// Unregisters a signal. If this listener currently had a handler
138
+ /// registered for the signal, then it will stop receiving any more
139
+ /// notification about the signal. If the signal has already been received,
140
+ /// it may still be returned by `recv`.
118
141
pub fn unregister ( & mut self , signum : Signum ) {
119
142
self . handles . pop ( & signum) ;
120
143
}
0 commit comments