/Src/Dependencies/Boost/boost/asio/detail/impl/signal_set_service.ipp

http://hadesmem.googlecode.com/ · C++ Header · 592 lines · 467 code · 91 blank · 34 comment · 110 complexity · 0aae66e6182200174514a7560dd6dee0 MD5 · raw file

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