annotate DEPENDENCIES/generic/include/boost/asio/detail/impl/signal_set_service.ipp @ 133:4acb5d8d80b6 tip

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