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