1 | // |
2 | // detail/impl/signal_set_service.ipp |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
6 | // |
7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
9 | // |
10 | |
11 | #ifndef BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP |
12 | #define BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP |
13 | |
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
15 | # pragma once |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
17 | |
18 | #include <boost/asio/detail/config.hpp> |
19 | |
20 | #include <cstring> |
21 | #include <boost/asio/detail/reactor.hpp> |
22 | #include <boost/asio/detail/signal_blocker.hpp> |
23 | #include <boost/asio/detail/signal_set_service.hpp> |
24 | #include <boost/asio/detail/static_mutex.hpp> |
25 | |
26 | #include <boost/asio/detail/push_options.hpp> |
27 | |
28 | namespace boost { |
29 | namespace asio { |
30 | namespace detail { |
31 | |
32 | struct signal_state |
33 | { |
34 | // Mutex used for protecting global state. |
35 | static_mutex mutex_; |
36 | |
37 | // The read end of the pipe used for signal notifications. |
38 | int read_descriptor_; |
39 | |
40 | // The write end of the pipe used for signal notifications. |
41 | int write_descriptor_; |
42 | |
43 | // Whether the signal state has been prepared for a fork. |
44 | bool fork_prepared_; |
45 | |
46 | // The head of a linked list of all signal_set_service instances. |
47 | class signal_set_service* service_list_; |
48 | |
49 | // A count of the number of objects that are registered for each signal. |
50 | std::size_t registration_count_[max_signal_number]; |
51 | }; |
52 | |
53 | signal_state* get_signal_state() |
54 | { |
55 | static signal_state state = { |
56 | BOOST_ASIO_STATIC_MUTEX_INIT, .read_descriptor_: -1, .write_descriptor_: -1, .fork_prepared_: false, .service_list_: 0, .registration_count_: { 0 } }; |
57 | return &state; |
58 | } |
59 | |
60 | void boost_asio_signal_handler(int signal_number) |
61 | { |
62 | #if defined(BOOST_ASIO_WINDOWS) \ |
63 | || defined(BOOST_ASIO_WINDOWS_RUNTIME) \ |
64 | || defined(__CYGWIN__) |
65 | signal_set_service::deliver_signal(signal_number); |
66 | #else // defined(BOOST_ASIO_WINDOWS) |
67 | // || defined(BOOST_ASIO_WINDOWS_RUNTIME) |
68 | // || defined(__CYGWIN__) |
69 | int saved_errno = errno; |
70 | signal_state* state = get_signal_state(); |
71 | signed_size_type result = ::write(fd: state->write_descriptor_, |
72 | buf: &signal_number, n: sizeof(signal_number)); |
73 | (void)result; |
74 | errno = saved_errno; |
75 | #endif // defined(BOOST_ASIO_WINDOWS) |
76 | // || defined(BOOST_ASIO_WINDOWS_RUNTIME) |
77 | // || defined(__CYGWIN__) |
78 | |
79 | #if defined(BOOST_ASIO_HAS_SIGNAL) && !defined(BOOST_ASIO_HAS_SIGACTION) |
80 | ::signal(signal_number, boost_asio_signal_handler); |
81 | #endif // defined(BOOST_ASIO_HAS_SIGNAL) && !defined(BOOST_ASIO_HAS_SIGACTION) |
82 | } |
83 | |
84 | #if !defined(BOOST_ASIO_WINDOWS) \ |
85 | && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ |
86 | && !defined(__CYGWIN__) |
87 | class signal_set_service::pipe_read_op : public reactor_op |
88 | { |
89 | public: |
90 | pipe_read_op() |
91 | : reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete) |
92 | { |
93 | } |
94 | |
95 | static bool do_perform(reactor_op*) |
96 | { |
97 | signal_state* state = get_signal_state(); |
98 | |
99 | int fd = state->read_descriptor_; |
100 | int signal_number = 0; |
101 | while (::read(fd: fd, buf: &signal_number, nbytes: sizeof(int)) == sizeof(int)) |
102 | if (signal_number >= 0 && signal_number < max_signal_number) |
103 | signal_set_service::deliver_signal(signal_number); |
104 | |
105 | return false; |
106 | } |
107 | |
108 | static void do_complete(io_service_impl* /*owner*/, operation* base, |
109 | const boost::system::error_code& /*ec*/, |
110 | std::size_t /*bytes_transferred*/) |
111 | { |
112 | pipe_read_op* o(static_cast<pipe_read_op*>(base)); |
113 | delete o; |
114 | } |
115 | }; |
116 | #endif // !defined(BOOST_ASIO_WINDOWS) |
117 | // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) |
118 | // && !defined(__CYGWIN__) |
119 | |
120 | signal_set_service::signal_set_service( |
121 | boost::asio::io_service& io_service) |
122 | : io_service_(boost::asio::use_service<io_service_impl>(ios&: io_service)), |
123 | #if !defined(BOOST_ASIO_WINDOWS) \ |
124 | && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ |
125 | && !defined(__CYGWIN__) |
126 | reactor_(boost::asio::use_service<reactor>(ios&: io_service)), |
127 | #endif // !defined(BOOST_ASIO_WINDOWS) |
128 | // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) |
129 | // && !defined(__CYGWIN__) |
130 | next_(0), |
131 | prev_(0) |
132 | { |
133 | get_signal_state()->mutex_.init(); |
134 | |
135 | #if !defined(BOOST_ASIO_WINDOWS) \ |
136 | && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ |
137 | && !defined(__CYGWIN__) |
138 | reactor_.init_task(); |
139 | #endif // !defined(BOOST_ASIO_WINDOWS) |
140 | // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) |
141 | // && !defined(__CYGWIN__) |
142 | |
143 | for (int i = 0; i < max_signal_number; ++i) |
144 | registrations_[i] = 0; |
145 | |
146 | add_service(service: this); |
147 | } |
148 | |
149 | signal_set_service::~signal_set_service() |
150 | { |
151 | remove_service(service: this); |
152 | } |
153 | |
154 | void signal_set_service::shutdown_service() |
155 | { |
156 | remove_service(service: this); |
157 | |
158 | op_queue<operation> ops; |
159 | |
160 | for (int i = 0; i < max_signal_number; ++i) |
161 | { |
162 | registration* reg = registrations_[i]; |
163 | while (reg) |
164 | { |
165 | ops.push(q&: *reg->queue_); |
166 | reg = reg->next_in_table_; |
167 | } |
168 | } |
169 | |
170 | io_service_.abandon_operations(ops); |
171 | } |
172 | |
173 | void signal_set_service::fork_service( |
174 | boost::asio::io_service::fork_event fork_ev) |
175 | { |
176 | #if !defined(BOOST_ASIO_WINDOWS) \ |
177 | && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ |
178 | && !defined(__CYGWIN__) |
179 | signal_state* state = get_signal_state(); |
180 | static_mutex::scoped_lock lock(state->mutex_); |
181 | |
182 | switch (fork_ev) |
183 | { |
184 | case boost::asio::io_service::fork_prepare: |
185 | { |
186 | int read_descriptor = state->read_descriptor_; |
187 | state->fork_prepared_ = true; |
188 | lock.unlock(); |
189 | reactor_.deregister_internal_descriptor(descriptor: read_descriptor, descriptor_data&: reactor_data_); |
190 | } |
191 | break; |
192 | case boost::asio::io_service::fork_parent: |
193 | if (state->fork_prepared_) |
194 | { |
195 | int read_descriptor = state->read_descriptor_; |
196 | state->fork_prepared_ = false; |
197 | lock.unlock(); |
198 | reactor_.register_internal_descriptor(op_type: reactor::read_op, |
199 | descriptor: read_descriptor, descriptor_data&: reactor_data_, op: new pipe_read_op); |
200 | } |
201 | break; |
202 | case boost::asio::io_service::fork_child: |
203 | if (state->fork_prepared_) |
204 | { |
205 | boost::asio::detail::signal_blocker blocker; |
206 | close_descriptors(); |
207 | open_descriptors(); |
208 | int read_descriptor = state->read_descriptor_; |
209 | state->fork_prepared_ = false; |
210 | lock.unlock(); |
211 | reactor_.register_internal_descriptor(op_type: reactor::read_op, |
212 | descriptor: read_descriptor, descriptor_data&: reactor_data_, op: new pipe_read_op); |
213 | } |
214 | break; |
215 | default: |
216 | break; |
217 | } |
218 | #else // !defined(BOOST_ASIO_WINDOWS) |
219 | // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) |
220 | // && !defined(__CYGWIN__) |
221 | (void)fork_ev; |
222 | #endif // !defined(BOOST_ASIO_WINDOWS) |
223 | // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) |
224 | // && !defined(__CYGWIN__) |
225 | } |
226 | |
227 | void signal_set_service::construct( |
228 | signal_set_service::implementation_type& impl) |
229 | { |
230 | impl.signals_ = 0; |
231 | } |
232 | |
233 | void signal_set_service::destroy( |
234 | signal_set_service::implementation_type& impl) |
235 | { |
236 | boost::system::error_code ignored_ec; |
237 | clear(impl, ec&: ignored_ec); |
238 | cancel(impl, ec&: ignored_ec); |
239 | } |
240 | |
241 | boost::system::error_code signal_set_service::add( |
242 | signal_set_service::implementation_type& impl, |
243 | int signal_number, boost::system::error_code& ec) |
244 | { |
245 | // Check that the signal number is valid. |
246 | if (signal_number < 0 || signal_number >= max_signal_number) |
247 | { |
248 | ec = boost::asio::error::invalid_argument; |
249 | return ec; |
250 | } |
251 | |
252 | signal_state* state = get_signal_state(); |
253 | static_mutex::scoped_lock lock(state->mutex_); |
254 | |
255 | // Find the appropriate place to insert the registration. |
256 | registration** insertion_point = &impl.signals_; |
257 | registration* next = impl.signals_; |
258 | while (next && next->signal_number_ < signal_number) |
259 | { |
260 | insertion_point = &next->next_in_set_; |
261 | next = next->next_in_set_; |
262 | } |
263 | |
264 | // Only do something if the signal is not already registered. |
265 | if (next == 0 || next->signal_number_ != signal_number) |
266 | { |
267 | registration* new_registration = new registration; |
268 | |
269 | #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) |
270 | // Register for the signal if we're the first. |
271 | if (state->registration_count_[signal_number] == 0) |
272 | { |
273 | # if defined(BOOST_ASIO_HAS_SIGACTION) |
274 | using namespace std; // For memset. |
275 | struct sigaction sa; |
276 | memset(s: &sa, c: 0, n: sizeof(sa)); |
277 | sa.sa_handler = boost_asio_signal_handler; |
278 | sigfillset(set: &sa.sa_mask); |
279 | if (::sigaction(sig: signal_number, act: &sa, oact: 0) == -1) |
280 | # else // defined(BOOST_ASIO_HAS_SIGACTION) |
281 | if (::signal(signal_number, boost_asio_signal_handler) == SIG_ERR) |
282 | # endif // defined(BOOST_ASIO_HAS_SIGACTION) |
283 | { |
284 | # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) |
285 | ec = boost::asio::error::invalid_argument; |
286 | # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) |
287 | ec = boost::system::error_code(errno, |
288 | boost::asio::error::get_system_category()); |
289 | # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) |
290 | delete new_registration; |
291 | return ec; |
292 | } |
293 | } |
294 | #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) |
295 | |
296 | // Record the new registration in the set. |
297 | new_registration->signal_number_ = signal_number; |
298 | new_registration->queue_ = &impl.queue_; |
299 | new_registration->next_in_set_ = next; |
300 | *insertion_point = new_registration; |
301 | |
302 | // Insert registration into the registration table. |
303 | new_registration->next_in_table_ = registrations_[signal_number]; |
304 | if (registrations_[signal_number]) |
305 | registrations_[signal_number]->prev_in_table_ = new_registration; |
306 | registrations_[signal_number] = new_registration; |
307 | |
308 | ++state->registration_count_[signal_number]; |
309 | } |
310 | |
311 | ec = boost::system::error_code(); |
312 | return ec; |
313 | } |
314 | |
315 | boost::system::error_code signal_set_service::remove( |
316 | signal_set_service::implementation_type& impl, |
317 | int signal_number, boost::system::error_code& ec) |
318 | { |
319 | // Check that the signal number is valid. |
320 | if (signal_number < 0 || signal_number >= max_signal_number) |
321 | { |
322 | ec = boost::asio::error::invalid_argument; |
323 | return ec; |
324 | } |
325 | |
326 | signal_state* state = get_signal_state(); |
327 | static_mutex::scoped_lock lock(state->mutex_); |
328 | |
329 | // Find the signal number in the list of registrations. |
330 | registration** deletion_point = &impl.signals_; |
331 | registration* reg = impl.signals_; |
332 | while (reg && reg->signal_number_ < signal_number) |
333 | { |
334 | deletion_point = ®->next_in_set_; |
335 | reg = reg->next_in_set_; |
336 | } |
337 | |
338 | if (reg != 0 && reg->signal_number_ == signal_number) |
339 | { |
340 | #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) |
341 | // Set signal handler back to the default if we're the last. |
342 | if (state->registration_count_[signal_number] == 1) |
343 | { |
344 | # if defined(BOOST_ASIO_HAS_SIGACTION) |
345 | using namespace std; // For memset. |
346 | struct sigaction sa; |
347 | memset(s: &sa, c: 0, n: sizeof(sa)); |
348 | sa.sa_handler = SIG_DFL; |
349 | if (::sigaction(sig: signal_number, act: &sa, oact: 0) == -1) |
350 | # else // defined(BOOST_ASIO_HAS_SIGACTION) |
351 | if (::signal(signal_number, SIG_DFL) == SIG_ERR) |
352 | # endif // defined(BOOST_ASIO_HAS_SIGACTION) |
353 | { |
354 | # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) |
355 | ec = boost::asio::error::invalid_argument; |
356 | # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) |
357 | ec = boost::system::error_code(errno, |
358 | boost::asio::error::get_system_category()); |
359 | # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) |
360 | return ec; |
361 | } |
362 | } |
363 | #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) |
364 | |
365 | // Remove the registration from the set. |
366 | *deletion_point = reg->next_in_set_; |
367 | |
368 | // Remove the registration from the registration table. |
369 | if (registrations_[signal_number] == reg) |
370 | registrations_[signal_number] = reg->next_in_table_; |
371 | if (reg->prev_in_table_) |
372 | reg->prev_in_table_->next_in_table_ = reg->next_in_table_; |
373 | if (reg->next_in_table_) |
374 | reg->next_in_table_->prev_in_table_ = reg->prev_in_table_; |
375 | |
376 | --state->registration_count_[signal_number]; |
377 | |
378 | delete reg; |
379 | } |
380 | |
381 | ec = boost::system::error_code(); |
382 | return ec; |
383 | } |
384 | |
385 | boost::system::error_code signal_set_service::clear( |
386 | signal_set_service::implementation_type& impl, |
387 | boost::system::error_code& ec) |
388 | { |
389 | signal_state* state = get_signal_state(); |
390 | static_mutex::scoped_lock lock(state->mutex_); |
391 | |
392 | while (registration* reg = impl.signals_) |
393 | { |
394 | #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) |
395 | // Set signal handler back to the default if we're the last. |
396 | if (state->registration_count_[reg->signal_number_] == 1) |
397 | { |
398 | # if defined(BOOST_ASIO_HAS_SIGACTION) |
399 | using namespace std; // For memset. |
400 | struct sigaction sa; |
401 | memset(s: &sa, c: 0, n: sizeof(sa)); |
402 | sa.sa_handler = SIG_DFL; |
403 | if (::sigaction(sig: reg->signal_number_, act: &sa, oact: 0) == -1) |
404 | # else // defined(BOOST_ASIO_HAS_SIGACTION) |
405 | if (::signal(reg->signal_number_, SIG_DFL) == SIG_ERR) |
406 | # endif // defined(BOOST_ASIO_HAS_SIGACTION) |
407 | { |
408 | # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) |
409 | ec = boost::asio::error::invalid_argument; |
410 | # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) |
411 | ec = boost::system::error_code(errno, |
412 | boost::asio::error::get_system_category()); |
413 | # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) |
414 | return ec; |
415 | } |
416 | } |
417 | #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) |
418 | |
419 | // Remove the registration from the registration table. |
420 | if (registrations_[reg->signal_number_] == reg) |
421 | registrations_[reg->signal_number_] = reg->next_in_table_; |
422 | if (reg->prev_in_table_) |
423 | reg->prev_in_table_->next_in_table_ = reg->next_in_table_; |
424 | if (reg->next_in_table_) |
425 | reg->next_in_table_->prev_in_table_ = reg->prev_in_table_; |
426 | |
427 | --state->registration_count_[reg->signal_number_]; |
428 | |
429 | impl.signals_ = reg->next_in_set_; |
430 | delete reg; |
431 | } |
432 | |
433 | ec = boost::system::error_code(); |
434 | return ec; |
435 | } |
436 | |
437 | boost::system::error_code signal_set_service::cancel( |
438 | signal_set_service::implementation_type& impl, |
439 | boost::system::error_code& ec) |
440 | { |
441 | BOOST_ASIO_HANDLER_OPERATION(("signal_set" , &impl, "cancel" )); |
442 | |
443 | op_queue<operation> ops; |
444 | { |
445 | signal_state* state = get_signal_state(); |
446 | static_mutex::scoped_lock lock(state->mutex_); |
447 | |
448 | while (signal_op* op = impl.queue_.front()) |
449 | { |
450 | op->ec_ = boost::asio::error::operation_aborted; |
451 | impl.queue_.pop(); |
452 | ops.push(h: op); |
453 | } |
454 | } |
455 | |
456 | io_service_.post_deferred_completions(ops); |
457 | |
458 | ec = boost::system::error_code(); |
459 | return ec; |
460 | } |
461 | |
462 | void signal_set_service::deliver_signal(int signal_number) |
463 | { |
464 | signal_state* state = get_signal_state(); |
465 | static_mutex::scoped_lock lock(state->mutex_); |
466 | |
467 | signal_set_service* service = state->service_list_; |
468 | while (service) |
469 | { |
470 | op_queue<operation> ops; |
471 | |
472 | registration* reg = service->registrations_[signal_number]; |
473 | while (reg) |
474 | { |
475 | if (reg->queue_->empty()) |
476 | { |
477 | ++reg->undelivered_; |
478 | } |
479 | else |
480 | { |
481 | while (signal_op* op = reg->queue_->front()) |
482 | { |
483 | op->signal_number_ = signal_number; |
484 | reg->queue_->pop(); |
485 | ops.push(h: op); |
486 | } |
487 | } |
488 | |
489 | reg = reg->next_in_table_; |
490 | } |
491 | |
492 | service->io_service_.post_deferred_completions(ops); |
493 | |
494 | service = service->next_; |
495 | } |
496 | } |
497 | |
498 | void signal_set_service::add_service(signal_set_service* service) |
499 | { |
500 | signal_state* state = get_signal_state(); |
501 | static_mutex::scoped_lock lock(state->mutex_); |
502 | |
503 | #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) |
504 | // If this is the first service to be created, open a new pipe. |
505 | if (state->service_list_ == 0) |
506 | open_descriptors(); |
507 | #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) |
508 | |
509 | // Insert service into linked list of all services. |
510 | service->next_ = state->service_list_; |
511 | service->prev_ = 0; |
512 | if (state->service_list_) |
513 | state->service_list_->prev_ = service; |
514 | state->service_list_ = service; |
515 | |
516 | #if !defined(BOOST_ASIO_WINDOWS) \ |
517 | && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ |
518 | && !defined(__CYGWIN__) |
519 | // Register for pipe readiness notifications. |
520 | int read_descriptor = state->read_descriptor_; |
521 | lock.unlock(); |
522 | service->reactor_.register_internal_descriptor(op_type: reactor::read_op, |
523 | descriptor: read_descriptor, descriptor_data&: service->reactor_data_, op: new pipe_read_op); |
524 | #endif // !defined(BOOST_ASIO_WINDOWS) |
525 | // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) |
526 | // && !defined(__CYGWIN__) |
527 | } |
528 | |
529 | void signal_set_service::remove_service(signal_set_service* service) |
530 | { |
531 | signal_state* state = get_signal_state(); |
532 | static_mutex::scoped_lock lock(state->mutex_); |
533 | |
534 | if (service->next_ || service->prev_ || state->service_list_ == service) |
535 | { |
536 | #if !defined(BOOST_ASIO_WINDOWS) \ |
537 | && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ |
538 | && !defined(__CYGWIN__) |
539 | // Disable the pipe readiness notifications. |
540 | int read_descriptor = state->read_descriptor_; |
541 | lock.unlock(); |
542 | service->reactor_.deregister_descriptor( |
543 | descriptor: read_descriptor, descriptor_data&: service->reactor_data_, closing: false); |
544 | lock.lock(); |
545 | #endif // !defined(BOOST_ASIO_WINDOWS) |
546 | // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) |
547 | // && !defined(__CYGWIN__) |
548 | |
549 | // Remove service from linked list of all services. |
550 | if (state->service_list_ == service) |
551 | state->service_list_ = service->next_; |
552 | if (service->prev_) |
553 | service->prev_->next_ = service->next_; |
554 | if (service->next_) |
555 | service->next_->prev_= service->prev_; |
556 | service->next_ = 0; |
557 | service->prev_ = 0; |
558 | |
559 | #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) |
560 | // If this is the last service to be removed, close the pipe. |
561 | if (state->service_list_ == 0) |
562 | close_descriptors(); |
563 | #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) |
564 | } |
565 | } |
566 | |
567 | void signal_set_service::open_descriptors() |
568 | { |
569 | #if !defined(BOOST_ASIO_WINDOWS) \ |
570 | && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ |
571 | && !defined(__CYGWIN__) |
572 | signal_state* state = get_signal_state(); |
573 | |
574 | int pipe_fds[2]; |
575 | if (::pipe(pipedes: pipe_fds) == 0) |
576 | { |
577 | state->read_descriptor_ = pipe_fds[0]; |
578 | ::fcntl(fd: state->read_descriptor_, F_SETFL, O_NONBLOCK); |
579 | |
580 | state->write_descriptor_ = pipe_fds[1]; |
581 | ::fcntl(fd: state->write_descriptor_, F_SETFL, O_NONBLOCK); |
582 | |
583 | #if defined(FD_CLOEXEC) |
584 | ::fcntl(fd: state->read_descriptor_, F_SETFD, FD_CLOEXEC); |
585 | ::fcntl(fd: state->write_descriptor_, F_SETFD, FD_CLOEXEC); |
586 | #endif // defined(FD_CLOEXEC) |
587 | } |
588 | else |
589 | { |
590 | boost::system::error_code ec(errno, |
591 | boost::asio::error::get_system_category()); |
592 | boost::asio::detail::throw_error(err: ec, location: "signal_set_service pipe" ); |
593 | } |
594 | #endif // !defined(BOOST_ASIO_WINDOWS) |
595 | // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) |
596 | // && !defined(__CYGWIN__) |
597 | } |
598 | |
599 | void signal_set_service::close_descriptors() |
600 | { |
601 | #if !defined(BOOST_ASIO_WINDOWS) \ |
602 | && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ |
603 | && !defined(__CYGWIN__) |
604 | signal_state* state = get_signal_state(); |
605 | |
606 | if (state->read_descriptor_ != -1) |
607 | ::close(fd: state->read_descriptor_); |
608 | state->read_descriptor_ = -1; |
609 | |
610 | if (state->write_descriptor_ != -1) |
611 | ::close(fd: state->write_descriptor_); |
612 | state->write_descriptor_ = -1; |
613 | #endif // !defined(BOOST_ASIO_WINDOWS) |
614 | // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) |
615 | // && !defined(__CYGWIN__) |
616 | } |
617 | |
618 | void signal_set_service::start_wait_op( |
619 | signal_set_service::implementation_type& impl, signal_op* op) |
620 | { |
621 | io_service_.work_started(); |
622 | |
623 | signal_state* state = get_signal_state(); |
624 | static_mutex::scoped_lock lock(state->mutex_); |
625 | |
626 | registration* reg = impl.signals_; |
627 | while (reg) |
628 | { |
629 | if (reg->undelivered_ > 0) |
630 | { |
631 | --reg->undelivered_; |
632 | op->signal_number_ = reg->signal_number_; |
633 | io_service_.post_deferred_completion(op); |
634 | return; |
635 | } |
636 | |
637 | reg = reg->next_in_set_; |
638 | } |
639 | |
640 | impl.queue_.push(h: op); |
641 | } |
642 | |
643 | } // namespace detail |
644 | } // namespace asio |
645 | } // namespace boost |
646 | |
647 | #include <boost/asio/detail/pop_options.hpp> |
648 | |
649 | #endif // BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP |
650 | |