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