signal_set_service.ipp 26 KB

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