1//
2// detail/impl/pipe_select_interrupter.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2015 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 ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
12#define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
13
14
15#include "asio/detail/config.hpp"
16
17
18#include <fcntl.h>
19#include <sys/stat.h>
20#include <sys/types.h>
21#include <unistd.h>
22#include "asio/detail/pipe_select_interrupter.hpp"
23#include "asio/detail/socket_types.hpp"
24#include "asio/detail/throw_error.hpp"
25#include "asio/error.hpp"
26
27#include "asio/detail/push_options.hpp"
28
29namespace asio {
30namespace detail {
31
32pipe_select_interrupter::pipe_select_interrupter()
33{
34  open_descriptors();
35}
36
37void pipe_select_interrupter::open_descriptors()
38{
39  int pipe_fds[2];
40  if (pipe(pipe_fds) == 0)
41  {
42    read_descriptor_ = pipe_fds[0];
43    ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
44    write_descriptor_ = pipe_fds[1];
45    ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
46
47#if defined(FD_CLOEXEC)
48    ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
49    ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC);
50#endif // defined(FD_CLOEXEC)
51  }
52  else
53  {
54    asio::error_code ec(errno,
55        asio::error::get_system_category());
56    asio::detail::throw_error(ec, "pipe_select_interrupter");
57  }
58}
59
60pipe_select_interrupter::~pipe_select_interrupter()
61{
62  close_descriptors();
63}
64
65void pipe_select_interrupter::close_descriptors()
66{
67  if (read_descriptor_ != -1)
68    ::close(read_descriptor_);
69  if (write_descriptor_ != -1)
70    ::close(write_descriptor_);
71}
72
73void pipe_select_interrupter::recreate()
74{
75  close_descriptors();
76
77  write_descriptor_ = -1;
78  read_descriptor_ = -1;
79
80  open_descriptors();
81}
82
83void pipe_select_interrupter::interrupt()
84{
85  char byte = 0;
86  signed_size_type result = ::write(write_descriptor_, &byte, 1);
87  (void)result;
88}
89
90bool pipe_select_interrupter::reset()
91{
92  for (;;)
93  {
94    char data[1024];
95    signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data));
96    if (bytes_read < 0 && errno == EINTR)
97      continue;
98    bool was_interrupted = (bytes_read > 0);
99    while (bytes_read == sizeof(data))
100      bytes_read = ::read(read_descriptor_, data, sizeof(data));
101    return was_interrupted;
102  }
103}
104
105} // namespace detail
106} // namespace asio
107
108#include "asio/detail/pop_options.hpp"
109
110
111#endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
112