1    	//
2    	// detail/impl/eventfd_select_interrupter.ipp
3    	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4    	//
5    	// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6    	// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
7    	//
8    	// Distributed under the Boost Software License, Version 1.0. (See accompanying
9    	// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10   	//
11   	
12   	#ifndef BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
13   	#define BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
14   	
15   	#if defined(_MSC_VER) && (_MSC_VER >= 1200)
16   	# pragma once
17   	#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18   	
19   	#include <boost/asio/detail/config.hpp>
20   	
21   	#if defined(BOOST_ASIO_HAS_EVENTFD)
22   	
23   	#include <sys/stat.h>
24   	#include <sys/types.h>
25   	#include <fcntl.h>
26   	#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
27   	# include <asm/unistd.h>
28   	#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
29   	# include <sys/eventfd.h>
30   	#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
31   	#include <boost/asio/detail/cstdint.hpp>
32   	#include <boost/asio/detail/eventfd_select_interrupter.hpp>
33   	#include <boost/asio/detail/throw_error.hpp>
34   	#include <boost/asio/error.hpp>
35   	
36   	#include <boost/asio/detail/push_options.hpp>
37   	
38   	namespace boost {
39   	namespace asio {
40   	namespace detail {
41   	
42   	eventfd_select_interrupter::eventfd_select_interrupter()
43   	{
44   	  open_descriptors();
45   	}
46   	
47   	void eventfd_select_interrupter::open_descriptors()
48   	{
49   	#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
50   	  write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
51   	  if (read_descriptor_ != -1)
52   	  {
53   	    ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
54   	    ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
55   	  }
56   	#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
57   	# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
58   	  write_descriptor_ = read_descriptor_ =
59   	    ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
60   	# else // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
61   	  errno = EINVAL;
62   	  write_descriptor_ = read_descriptor_ = -1;
63   	# endif // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
(1) Event cond_true: Condition "this->read_descriptor_ == -1", taking true branch.
(2) Event cond_true: Condition "*__errno_location() == 22", taking true branch.
64   	  if (read_descriptor_ == -1 && errno == EINVAL)
65   	  {
66   	    write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
(3) Event cond_false: Condition "this->read_descriptor_ != -1", taking false branch.
67   	    if (read_descriptor_ != -1)
68   	    {
69   	      ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
70   	      ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
(4) Event if_end: End of if statement.
71   	    }
72   	  }
73   	#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
74   	
(5) Event cond_true: Condition "this->read_descriptor_ == -1", taking true branch.
75   	  if (read_descriptor_ == -1)
76   	  {
77   	    int pipe_fds[2];
(6) Event cond_true: Condition "pipe(pipe_fds) == 0", taking true branch.
78   	    if (pipe(pipe_fds) == 0)
79   	    {
80   	      read_descriptor_ = pipe_fds[0];
81   	      ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
82   	      ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
83   	      write_descriptor_ = pipe_fds[1];
(7) Event check_return: Calling "fcntl(this->write_descriptor_, 4, 2048)" without checking return value. This library function may fail and return an error code.
84   	      ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
85   	      ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC);
86   	    }
87   	    else
88   	    {
89   	      boost::system::error_code ec(errno,
90   	          boost::asio::error::get_system_category());
91   	      boost::asio::detail::throw_error(ec, "eventfd_select_interrupter");
92   	    }
93   	  }
94   	}
95   	
96   	eventfd_select_interrupter::~eventfd_select_interrupter()
97   	{
98   	  close_descriptors();
99   	}
100  	
101  	void eventfd_select_interrupter::close_descriptors()
102  	{
103  	  if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
104  	    ::close(write_descriptor_);
105  	  if (read_descriptor_ != -1)
106  	    ::close(read_descriptor_);
107  	}
108  	
109  	void eventfd_select_interrupter::recreate()
110  	{
111  	  close_descriptors();
112  	
113  	  write_descriptor_ = -1;
114  	  read_descriptor_ = -1;
115  	
116  	  open_descriptors();
117  	}
118  	
119  	void eventfd_select_interrupter::interrupt()
120  	{
121  	  uint64_t counter(1UL);
122  	  int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));
123  	  (void)result;
124  	}
125  	
126  	bool eventfd_select_interrupter::reset()
127  	{
128  	  if (write_descriptor_ == read_descriptor_)
129  	  {
130  	    for (;;)
131  	    {
132  	      // Only perform one read. The kernel maintains an atomic counter.
133  	      uint64_t counter(0);
134  	      errno = 0;
135  	      int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
136  	      if (bytes_read < 0 && errno == EINTR)
137  	        continue;
138  	      bool was_interrupted = (bytes_read > 0);
139  	      return was_interrupted;
140  	    }
141  	  }
142  	  else
143  	  {
144  	    for (;;)
145  	    {
146  	      // Clear all data from the pipe.
147  	      char data[1024];
148  	      int bytes_read = ::read(read_descriptor_, data, sizeof(data));
149  	      if (bytes_read < 0 && errno == EINTR)
150  	        continue;
151  	      bool was_interrupted = (bytes_read > 0);
152  	      while (bytes_read == sizeof(data))
153  	        bytes_read = ::read(read_descriptor_, data, sizeof(data));
154  	      return was_interrupted;
155  	    }
156  	  }
157  	}
158  	
159  	} // namespace detail
160  	} // namespace asio
161  	} // namespace boost
162  	
163  	#include <boost/asio/detail/pop_options.hpp>
164  	
165  	#endif // defined(BOOST_ASIO_HAS_EVENTFD)
166  	
167  	#endif // BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
168