… | |
… | |
93 | L<EV> or L<AnyEvent>). This, of course, incurs the overhead of a C<read> |
93 | L<EV> or L<AnyEvent>). This, of course, incurs the overhead of a C<read> |
94 | and C<write> syscall. |
94 | and C<write> syscall. |
95 | |
95 | |
96 | =head1 USAGE EXAMPLES |
96 | =head1 USAGE EXAMPLES |
97 | |
97 | |
98 | =head2 Async::Interrupt to implement race-free signal handling |
98 | =head2 Implementing race-free signal handling |
99 | |
99 | |
100 | This example uses a single event pipe for all signals, and one |
100 | This example uses a single event pipe for all signals, and one |
101 | Async::Interrupt per signal. |
101 | Async::Interrupt per signal. This code is actually what the L<AnyEvent> |
|
|
102 | module uses itself when Async::Interrupt is available. |
102 | |
103 | |
103 | First, create the event pipe and hook it into the event loop (this code is |
104 | First, create the event pipe and hook it into the event loop |
104 | actually what L<AnyEvent> uses itself): |
|
|
105 | |
105 | |
106 | $SIGPIPE = new Async::Interrupt::EventPipe; |
106 | $SIGPIPE = new Async::Interrupt::EventPipe; |
107 | $SIGPIPE_W = AnyEvent->io ( |
107 | $SIGPIPE_W = AnyEvent->io ( |
108 | fh => $SIGPIPE->fileno, |
108 | fh => $SIGPIPE->fileno, |
109 | poll => "r", |
109 | poll => "r", |
110 | cb => \&_signal_check, |
110 | cb => \&_signal_check, # defined later |
111 | ); |
111 | ); |
112 | |
112 | |
113 | Then, for each signal to hook, create an Async::Interrupt object. The |
113 | Then, for each signal to hook, create an Async::Interrupt object. The |
114 | callback just sets a global variable, as we are only interested in |
114 | callback just sets a global variable, as we are only interested in |
115 | synchronous signals (i.e. when the event loop polls), which is why the |
115 | synchronous signals (i.e. when the event loop polls), which is why the |
116 | pipe draining is not done automatically. |
116 | pipe draining is not done automatically. |
117 | |
117 | |
118 | my $interrupt = new Async::Interrupt |
118 | my $interrupt = new Async::Interrupt |
119 | cb => sub { undef $SIGNAL_RECEIVED{$signum} } |
119 | cb => sub { undef $SIGNAL_RECEIVED{$signum} } |
120 | signal => $signal, |
120 | signal => $signum, |
121 | pipe => [$SIGPIPE_R->filenos], |
121 | pipe => [$SIGPIPE->filenos], |
122 | pipe_autodrain => 0, |
122 | pipe_autodrain => 0, |
123 | ; |
123 | ; |
124 | |
124 | |
125 | Finally, the I/O callback for the event pipe handles the signals: |
125 | Finally, the I/O callback for the event pipe handles the signals: |
126 | |
126 | |
… | |
… | |
135 | warn "signal $_ received\n"; |
135 | warn "signal $_ received\n"; |
136 | } |
136 | } |
137 | } |
137 | } |
138 | } |
138 | } |
139 | |
139 | |
|
|
140 | =head2 Interrupt perl from another thread |
140 | |
141 | |
|
|
142 | This example interrupts the Perl interpreter from another thread, via the |
|
|
143 | XS API. This is used by e.g. the L<EV::Loop::Async> module. |
|
|
144 | |
|
|
145 | #TODO# |
141 | |
146 | |
142 | =head1 THE Async::Interrupt CLASS |
147 | =head1 THE Async::Interrupt CLASS |
143 | |
148 | |
144 | =over 4 |
149 | =over 4 |
145 | |
150 | |
… | |
… | |
149 | |
154 | |
150 | use common::sense; |
155 | use common::sense; |
151 | |
156 | |
152 | BEGIN { |
157 | BEGIN { |
153 | # the next line forces initialisation of internal |
158 | # the next line forces initialisation of internal |
154 | # signal handling # variables |
159 | # signal handling variables, otherwise, PL_sig_pending |
|
|
160 | # etc. will be null pointers. |
155 | $SIG{KILL} = sub { }; |
161 | $SIG{KILL} = sub { }; |
156 | |
162 | |
157 | our $VERSION = '0.6'; |
163 | our $VERSION = '1.0'; |
158 | |
164 | |
159 | require XSLoader; |
165 | require XSLoader; |
160 | XSLoader::load ("Async::Interrupt", $VERSION); |
166 | XSLoader::load ("Async::Interrupt", $VERSION); |
161 | } |
167 | } |
162 | |
168 | |
… | |
… | |
185 | The exceptions are C<$!> and C<$@>, which are saved and restored by |
191 | The exceptions are C<$!> and C<$@>, which are saved and restored by |
186 | Async::Interrupt. |
192 | Async::Interrupt. |
187 | |
193 | |
188 | If the callback should throw an exception, then it will be caught, |
194 | If the callback should throw an exception, then it will be caught, |
189 | and C<$Async::Interrupt::DIED> will be called with C<$@> containing |
195 | and C<$Async::Interrupt::DIED> will be called with C<$@> containing |
190 | the exception. The default will simply C<warn> about the message and |
196 | the exception. The default will simply C<warn> about the message and |
191 | continue. |
197 | continue. |
192 | |
198 | |
193 | =item c_cb => [$c_func, $c_arg] |
199 | =item c_cb => [$c_func, $c_arg] |
194 | |
200 | |
195 | Registers a C callback the be invoked whenever the async interrupt is |
201 | Registers a C callback the be invoked whenever the async interrupt is |
… | |
… | |
229 | the given signal is caught by the process. |
235 | the given signal is caught by the process. |
230 | |
236 | |
231 | Only one async can hook a given signal, and the signal will be restored to |
237 | Only one async can hook a given signal, and the signal will be restored to |
232 | defaults when the Async::Interrupt object gets destroyed. |
238 | defaults when the Async::Interrupt object gets destroyed. |
233 | |
239 | |
|
|
240 | =item signal_hysteresis => $boolean |
|
|
241 | |
|
|
242 | Sets the initial signal hysteresis state, see the C<signal_hysteresis> |
|
|
243 | method, below. |
|
|
244 | |
234 | =item pipe => [$fileno_or_fh_for_reading, $fileno_or_fh_for_writing] |
245 | =item pipe => [$fileno_or_fh_for_reading, $fileno_or_fh_for_writing] |
235 | |
246 | |
236 | Specifies two file descriptors (or file handles) that should be signalled |
247 | Specifies two file descriptors (or file handles) that should be signalled |
237 | whenever the async interrupt is signalled. This means a single octet will |
248 | whenever the async interrupt is signalled. This means a single octet will |
238 | be written to it, and before the callback is being invoked, it will be |
249 | be written to it, and before the callback is being invoked, it will be |
… | |
… | |
251 | |
262 | |
252 | If you want to share a single event pipe between multiple Async::Interrupt |
263 | If you want to share a single event pipe between multiple Async::Interrupt |
253 | objects, you can use the C<Async::Interrupt::EventPipe> class to manage |
264 | objects, you can use the C<Async::Interrupt::EventPipe> class to manage |
254 | those. |
265 | those. |
255 | |
266 | |
|
|
267 | =item pipe_autodrain => $boolean |
|
|
268 | |
|
|
269 | Sets the initial autodrain state, see the C<pipe_autodrain> method, below. |
|
|
270 | |
256 | =back |
271 | =back |
257 | |
272 | |
258 | =cut |
273 | =cut |
259 | |
274 | |
260 | sub new { |
275 | sub new { |
261 | my ($class, %arg) = @_; |
276 | my ($class, %arg) = @_; |
262 | |
277 | |
263 | bless \(_alloc $arg{cb}, @{$arg{c_cb}}[0,1], @{$arg{pipe}}[0,1], $arg{signal}, $arg{var}), $class |
278 | my $self = bless \(_alloc $arg{cb}, @{$arg{c_cb}}[0,1], @{$arg{pipe}}[0,1], $arg{signal}, $arg{var}), $class; |
|
|
279 | |
|
|
280 | # urgs, reminds me of Event |
|
|
281 | for my $attr (qw(pipe_autodrain signal_hysteresis)) { |
|
|
282 | $self->$attr ($arg{$attr}) if exists $arg{$attr}; |
|
|
283 | } |
|
|
284 | |
|
|
285 | $self |
264 | } |
286 | } |
265 | |
287 | |
266 | =item ($signal_func, $signal_arg) = $async->signal_func |
288 | =item ($signal_func, $signal_arg) = $async->signal_func |
267 | |
289 | |
268 | Returns the address of a function to call asynchronously. The function |
290 | Returns the address of a function to call asynchronously. The function |