signal_set_service.ipp 20 KB

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