Chris@16: // Chris@16: // detail/impl/eventfd_select_interrupter.ipp Chris@16: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Chris@16: // Chris@101: // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) Chris@16: // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: Chris@16: #ifndef BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP Chris@16: #define BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: # pragma once Chris@16: #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: Chris@16: #include Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_EVENTFD) Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 Chris@16: # include Chris@16: #else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 Chris@16: # include Chris@16: #endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace asio { Chris@16: namespace detail { Chris@16: Chris@16: eventfd_select_interrupter::eventfd_select_interrupter() Chris@16: { Chris@16: open_descriptors(); Chris@16: } Chris@16: Chris@16: void eventfd_select_interrupter::open_descriptors() Chris@16: { Chris@16: #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 Chris@16: write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); Chris@16: if (read_descriptor_ != -1) Chris@16: { Chris@16: ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); Chris@16: ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); Chris@16: } Chris@16: #else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 Chris@16: # if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) Chris@16: write_descriptor_ = read_descriptor_ = Chris@16: ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); Chris@16: # else // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) Chris@16: errno = EINVAL; Chris@16: write_descriptor_ = read_descriptor_ = -1; Chris@16: # endif // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) Chris@16: if (read_descriptor_ == -1 && errno == EINVAL) Chris@16: { Chris@16: write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); Chris@16: if (read_descriptor_ != -1) Chris@16: { Chris@16: ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); Chris@16: ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); Chris@16: } Chris@16: } Chris@16: #endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 Chris@16: Chris@16: if (read_descriptor_ == -1) Chris@16: { Chris@16: int pipe_fds[2]; Chris@16: if (pipe(pipe_fds) == 0) Chris@16: { Chris@16: read_descriptor_ = pipe_fds[0]; Chris@16: ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); Chris@16: ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); Chris@16: write_descriptor_ = pipe_fds[1]; Chris@16: ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); Chris@16: ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC); Chris@16: } Chris@16: else Chris@16: { Chris@16: boost::system::error_code ec(errno, Chris@16: boost::asio::error::get_system_category()); Chris@16: boost::asio::detail::throw_error(ec, "eventfd_select_interrupter"); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: eventfd_select_interrupter::~eventfd_select_interrupter() Chris@16: { Chris@16: close_descriptors(); Chris@16: } Chris@16: Chris@16: void eventfd_select_interrupter::close_descriptors() Chris@16: { Chris@16: if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) Chris@16: ::close(write_descriptor_); Chris@16: if (read_descriptor_ != -1) Chris@16: ::close(read_descriptor_); Chris@16: } Chris@16: Chris@16: void eventfd_select_interrupter::recreate() Chris@16: { Chris@16: close_descriptors(); Chris@16: Chris@16: write_descriptor_ = -1; Chris@16: read_descriptor_ = -1; Chris@16: Chris@16: open_descriptors(); Chris@16: } Chris@16: Chris@16: void eventfd_select_interrupter::interrupt() Chris@16: { Chris@16: uint64_t counter(1UL); Chris@16: int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); Chris@16: (void)result; Chris@16: } Chris@16: Chris@16: bool eventfd_select_interrupter::reset() Chris@16: { Chris@16: if (write_descriptor_ == read_descriptor_) Chris@16: { Chris@16: for (;;) Chris@16: { Chris@16: // Only perform one read. The kernel maintains an atomic counter. Chris@16: uint64_t counter(0); Chris@16: errno = 0; Chris@16: int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); Chris@16: if (bytes_read < 0 && errno == EINTR) Chris@16: continue; Chris@16: bool was_interrupted = (bytes_read > 0); Chris@16: return was_interrupted; Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: for (;;) Chris@16: { Chris@16: // Clear all data from the pipe. Chris@16: char data[1024]; Chris@16: int bytes_read = ::read(read_descriptor_, data, sizeof(data)); Chris@16: if (bytes_read < 0 && errno == EINTR) Chris@16: continue; Chris@16: bool was_interrupted = (bytes_read > 0); Chris@16: while (bytes_read == sizeof(data)) Chris@16: bytes_read = ::read(read_descriptor_, data, sizeof(data)); Chris@16: return was_interrupted; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // defined(BOOST_ASIO_HAS_EVENTFD) Chris@16: Chris@16: #endif // BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP