1//
2// detail/impl/pipe_select_interrupter.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2021 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_PIPE_SELECT_INTERRUPTER_IPP
12#define BOOST_ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_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#if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
21#if !defined(BOOST_ASIO_WINDOWS)
22#if !defined(__CYGWIN__)
23#if !defined(__SYMBIAN32__)
24#if !defined(BOOST_ASIO_HAS_EVENTFD)
25
26#include <fcntl.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29#include <unistd.h>
30#include <boost/asio/detail/pipe_select_interrupter.hpp>
31#include <boost/asio/detail/socket_types.hpp>
32#include <boost/asio/detail/throw_error.hpp>
33#include <boost/asio/error.hpp>
34
35#include <boost/asio/detail/push_options.hpp>
36
37namespace boost {
38namespace asio {
39namespace detail {
40
41pipe_select_interrupter::pipe_select_interrupter()
42{
43  open_descriptors();
44}
45
46void pipe_select_interrupter::open_descriptors()
47{
48  int pipe_fds[2];
49  if (pipe(pipe_fds) == 0)
50  {
51    read_descriptor_ = pipe_fds[0];
52    ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
53    write_descriptor_ = pipe_fds[1];
54    ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
55
56#if defined(FD_CLOEXEC)
57    ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
58    ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC);
59#endif // defined(FD_CLOEXEC)
60  }
61  else
62  {
63    boost::system::error_code ec(errno,
64        boost::asio::error::get_system_category());
65    boost::asio::detail::throw_error(ec, "pipe_select_interrupter");
66  }
67}
68
69pipe_select_interrupter::~pipe_select_interrupter()
70{
71  close_descriptors();
72}
73
74void pipe_select_interrupter::close_descriptors()
75{
76  if (read_descriptor_ != -1)
77    ::close(read_descriptor_);
78  if (write_descriptor_ != -1)
79    ::close(write_descriptor_);
80}
81
82void pipe_select_interrupter::recreate()
83{
84  close_descriptors();
85
86  write_descriptor_ = -1;
87  read_descriptor_ = -1;
88
89  open_descriptors();
90}
91
92void pipe_select_interrupter::interrupt()
93{
94  char byte = 0;
95  signed_size_type result = ::write(write_descriptor_, &byte, 1);
96  (void)result;
97}
98
99bool pipe_select_interrupter::reset()
100{
101  for (;;)
102  {
103    char data[1024];
104    signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data));
105    if (bytes_read == sizeof(data))
106      continue;
107    if (bytes_read > 0)
108      return true;
109    if (bytes_read == 0)
110      return false;
111    if (errno == EINTR)
112      continue;
113    if (errno == EWOULDBLOCK || errno == EAGAIN)
114      return true;
115    return false;
116  }
117}
118
119} // namespace detail
120} // namespace asio
121} // namespace boost
122
123#include <boost/asio/detail/pop_options.hpp>
124
125#endif // !defined(BOOST_ASIO_HAS_EVENTFD)
126#endif // !defined(__SYMBIAN32__)
127#endif // !defined(__CYGWIN__)
128#endif // !defined(BOOST_ASIO_WINDOWS)
129#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
130
131#endif // BOOST_ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
132