tokenpipe.cpp raw

   1  // Copyright (c) 2021-2022 The Limenka developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  #include <util/tokenpipe.h>
   5  
   6  #include <limenka-build-config.h> // IWYU pragma: keep
   7  
   8  #ifndef WIN32
   9  
  10  #include <errno.h>
  11  #include <fcntl.h>
  12  #include <optional>
  13  #include <unistd.h>
  14  
  15  TokenPipeEnd TokenPipe::TakeReadEnd()
  16  {
  17      TokenPipeEnd res(m_fds[0]);
  18      m_fds[0] = -1;
  19      return res;
  20  }
  21  
  22  TokenPipeEnd TokenPipe::TakeWriteEnd()
  23  {
  24      TokenPipeEnd res(m_fds[1]);
  25      m_fds[1] = -1;
  26      return res;
  27  }
  28  
  29  TokenPipeEnd::TokenPipeEnd(int fd) : m_fd(fd)
  30  {
  31  }
  32  
  33  TokenPipeEnd::~TokenPipeEnd()
  34  {
  35      Close();
  36  }
  37  
  38  int TokenPipeEnd::TokenWrite(uint8_t token)
  39  {
  40      while (true) {
  41          ssize_t result = write(m_fd, &token, 1);
  42          if (result < 0) {
  43              // Failure. It's possible that the write was interrupted by a signal,
  44              // in that case retry.
  45              if (errno != EINTR) {
  46                  return TS_ERR;
  47              }
  48          } else if (result == 0) {
  49              return TS_EOS;
  50          } else { // ==1
  51              return 0;
  52          }
  53      }
  54  }
  55  
  56  int TokenPipeEnd::TokenRead()
  57  {
  58      uint8_t token;
  59      while (true) {
  60          ssize_t result = read(m_fd, &token, 1);
  61          if (result < 0) {
  62              // Failure. Check if the read was interrupted by a signal,
  63              // in that case retry.
  64              if (errno != EINTR) {
  65                  return TS_ERR;
  66              }
  67          } else if (result == 0) {
  68              return TS_EOS;
  69          } else { // ==1
  70              return token;
  71          }
  72      }
  73      return token;
  74  }
  75  
  76  void TokenPipeEnd::Close()
  77  {
  78      if (m_fd != -1) close(m_fd);
  79      m_fd = -1;
  80  }
  81  
  82  std::optional<TokenPipe> TokenPipe::Make()
  83  {
  84      int fds[2] = {-1, -1};
  85  #if HAVE_O_CLOEXEC && HAVE_DECL_PIPE2
  86      if (pipe2(fds, O_CLOEXEC) != 0) {
  87          return std::nullopt;
  88      }
  89  #else
  90      if (pipe(fds) != 0) {
  91          return std::nullopt;
  92      }
  93  #endif
  94      return TokenPipe(fds);
  95  }
  96  
  97  TokenPipe::~TokenPipe()
  98  {
  99      Close();
 100  }
 101  
 102  void TokenPipe::Close()
 103  {
 104      if (m_fds[0] != -1) close(m_fds[0]);
 105      if (m_fds[1] != -1) close(m_fds[1]);
 106      m_fds[0] = m_fds[1] = -1;
 107  }
 108  
 109  #endif // WIN32
 110