diff --git a/include/boost/asio/detail/eventfd_select_interrupter.hpp b/include/boost/asio/detail/eventfd_select_interrupter.hpp new file mode 100644 index 00000000..f332aa2a --- /dev/null +++ b/include/boost/asio/detail/eventfd_select_interrupter.hpp @@ -0,0 +1,124 @@ +// +// eventfd_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP +#define BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +#if defined(linux) +# if !defined(BOOST_ASIO_DISABLE_EVENTFD) +# include +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define BOOST_ASIO_HAS_EVENTFD +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +#endif // defined(linux) + +#if defined(BOOST_ASIO_HAS_EVENTFD) + +#include +#include +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class eventfd_select_interrupter +{ +public: + // Constructor. + eventfd_select_interrupter() + { +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + read_descriptor_ = syscall(__NR_eventfd, 0); +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + read_descriptor_ = ::eventfd(0, 0); +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::system::system_error e(ec, "eventfd_select_interrupter"); + boost::throw_exception(e); + } + } + + // Destructor. + ~eventfd_select_interrupter() + { + if (read_descriptor_ != -1) + ::close(read_descriptor_); + } + + // Interrupt the select call. + void interrupt() + { + uint64_t counter(1UL); + ::write(read_descriptor_, &counter, sizeof(uint64_t)); + } + + // Reset the select interrupt. Returns true if the call was interrupted. + bool reset() + { + // Only perform one read. The kernel maintains an atomic counter. + uint64_t counter(0); + int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); + bool was_interrupted = (bytes_read > 0); + return was_interrupted; + } + + // Get the read descriptor to be passed to select. + int read_descriptor() const + { + return read_descriptor_; + } + +private: + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // 64bit value will be written on the other end of the connection and this + // descriptor will become readable. + int read_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_EVENTFD) + +#include + +#endif // BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP diff --git a/include/boost/asio/detail/select_interrupter.hpp b/include/boost/asio/detail/select_interrupter.hpp index 31cbc59b..8bb952cf 100644 --- a/include/boost/asio/detail/select_interrupter.hpp +++ b/include/boost/asio/detail/select_interrupter.hpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -30,6 +31,8 @@ namespace detail { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef socket_select_interrupter select_interrupter; +#elif defined(BOOST_ASIO_HAS_EVENTFD) +typedef eventfd_select_interrupter select_interrupter; #else typedef pipe_select_interrupter select_interrupter; #endif