CppCommon  1.0.4.1
C++ Common Library
pipe.cpp
Go to the documentation of this file.
1 
9 #include "system/pipe.h"
10 
11 #include "errors/fatal.h"
13 
14 #include <cassert>
15 
16 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
17 #include <unistd.h>
18 #elif defined(_WIN32) || defined(_WIN64)
19 #include <windows.h>
20 #endif
21 
22 namespace CppCommon {
23 
25 
26 class Pipe::Impl
27 {
28 public:
29  Impl()
30  {
31 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
32  int result = pipe(_pipe);
33  if (result != 0)
34  throwex SystemException("Failed to create a new pipe!");
35 #elif defined(_WIN32) || defined(_WIN64)
36  if (!CreatePipe(&_pipe[0], &_pipe[1], nullptr, 0))
37  throwex SystemException("Failed to create a new pipe!");
38 #endif
39  }
40 
41  ~Impl()
42  {
43  try
44  {
45  if (IsPipeOpened())
46  Close();
47  }
48  catch (const SystemException& ex)
49  {
50  fatality(SystemException(ex.string()));
51  }
52  }
53 
54  void* reader() const noexcept
55  {
56  return (void*)(size_t)_pipe[0];
57  }
58 
59  void* writer() const noexcept
60  {
61  return (void*)(size_t)_pipe[1];
62  }
63 
64  bool IsPipeOpened() const noexcept
65  {
66  return IsPipeReadOpened() || IsPipeWriteOpened();
67  }
68 
69  bool IsPipeReadOpened() const noexcept
70  {
71 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
72  return (_pipe[0] >= 0);
73 #elif defined(_WIN32) || defined(_WIN64)
74  return (_pipe[0] != INVALID_HANDLE_VALUE);
75 #endif
76  }
77 
78  bool IsPipeWriteOpened() const noexcept
79  {
80 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
81  return (_pipe[1] >= 0);
82 #elif defined(_WIN32) || defined(_WIN64)
83  return (_pipe[1] != INVALID_HANDLE_VALUE);
84 #endif
85  }
86 
87  size_t Read(void* buffer, size_t size)
88  {
89  if ((buffer == nullptr) || (size == 0))
90  return 0;
91 
92  assert(IsPipeReadOpened() && "Pipe is not opened for reading!");
93  if (!IsPipeReadOpened())
94  throwex SystemException("Cannot read from the closed pipe!");
95 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
96  ssize_t result = read(_pipe[0], buffer, size);
97  if (result < 0)
98  throwex SystemException("Cannot read from the pipe!");
99  return (size_t)result;
100 #elif defined(_WIN32) || defined(_WIN64)
101  DWORD result = 0;
102  if (!ReadFile(_pipe[0], buffer, (DWORD)size, &result, nullptr))
103  if (GetLastError() != ERROR_BROKEN_PIPE)
104  throwex SystemException("Cannot read from the pipe!");
105  return (size_t)result;
106 #endif
107  }
108 
109  size_t Write(const void* buffer, size_t size)
110  {
111  if ((buffer == nullptr) || (size == 0))
112  return 0;
113 
114  assert(IsPipeWriteOpened() && "Pipe is not opened for writing!");
115  if (!IsPipeWriteOpened())
116  throwex SystemException("Cannot write into the closed pipe!");
117 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
118  ssize_t result = write(_pipe[1], buffer, size);
119  if (result < 0)
120  throwex SystemException("Cannot write into the pipe!");
121  return (size_t)result;
122 #elif defined(_WIN32) || defined(_WIN64)
123  DWORD result = 0;
124  if (!WriteFile(_pipe[1], buffer, (DWORD)size, &result, nullptr))
125  if (GetLastError() != ERROR_BROKEN_PIPE)
126  throwex SystemException("Cannot write into the pipe!");
127  return (size_t)result;
128 #endif
129  }
130 
131  void CloseRead()
132  {
133  assert(IsPipeReadOpened() && "Pipe is not opened for reading!");
134  if (!IsPipeReadOpened())
135  throwex SystemException("Pipe is not opened for reading!");
136 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
137  int result = close(_pipe[0]);
138  if (result != 0)
139  throwex SystemException("Cannot close the read pipe endpoint!");
140  _pipe[0] = -1;
141 #elif defined(_WIN32) || defined(_WIN64)
142  if (!CloseHandle(_pipe[0]))
143  throwex SystemException("Cannot close the read pipe endpoint!");
144  _pipe[0] = INVALID_HANDLE_VALUE;
145 #endif
146  }
147 
148  void CloseWrite()
149  {
150  assert(IsPipeWriteOpened() && "Pipe is not opened for writing!");
151  if (!IsPipeWriteOpened())
152  throwex SystemException("Pipe is not opened for writing!");
153 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
154  int result = close(_pipe[1]);
155  if (result != 0)
156  throwex SystemException("Cannot close the write pipe endpoint!");
157  _pipe[1] = -1;
158 #elif defined(_WIN32) || defined(_WIN64)
159  if (!CloseHandle(_pipe[1]))
160  throwex SystemException("Cannot close the write pipe endpoint!");
161  _pipe[1] = INVALID_HANDLE_VALUE;
162 #endif
163  }
164 
165  void Close()
166  {
167  if (IsPipeReadOpened())
168  CloseRead();
169  if (IsPipeWriteOpened())
170  CloseWrite();
171  }
172 
173 private:
174 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
175  int _pipe[2];
176 #elif defined(_WIN32) || defined(_WIN64)
177  HANDLE _pipe[2];
178 #endif
179 };
180 
182 
184 {
185  // Check implementation storage parameters
186  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
187  static_assert((StorageSize >= sizeof(Impl)), "Pipe::StorageSize must be increased!");
188  static_assert(((StorageAlign % alignof(Impl)) == 0), "Pipe::StorageAlign must be adjusted!");
189 
190  // Create the implementation instance
191  new(&_storage)Impl();
192 }
193 
195 {
196  // Delete the implementation instance
197  reinterpret_cast<Impl*>(&_storage)->~Impl();
198 }
199 
200 void* Pipe::reader() const noexcept { return impl().reader(); }
201 void* Pipe::writer() const noexcept { return impl().writer(); }
202 
203 bool Pipe::IsPipeOpened() const noexcept { return impl().IsPipeOpened(); }
204 bool Pipe::IsPipeReadOpened() const noexcept { return impl().IsPipeReadOpened(); }
205 bool Pipe::IsPipeWriteOpened() const noexcept { return impl().IsPipeWriteOpened(); }
206 
207 size_t Pipe::Read(void* buffer, size_t size) { return impl().Read(buffer, size); }
208 size_t Pipe::Write(const void* buffer, size_t size) { return impl().Write(buffer, size); }
209 
210 void Pipe::CloseRead() { return impl().CloseRead(); }
211 void Pipe::CloseWrite() { return impl().CloseWrite(); }
212 void Pipe::Close() { return impl().Close(); }
213 
214 void Pipe::swap(Pipe& pipe) noexcept
215 {
216  using std::swap;
217  swap(_storage, pipe._storage);
218 }
219 
220 } // namespace CppCommon
Pipe.
Definition: pipe.h:31
bool IsPipeOpened() const noexcept
Is pipe opened for reading or writing?
Definition: pipe.cpp:203
void CloseWrite()
Close the write pipe endpoint.
Definition: pipe.cpp:211
virtual size_t Write(const void *buffer, size_t size)=0
Write a byte buffer base method.
size_t Read(void *buffer, size_t size) override
Read a bytes buffer from the pipe.
Definition: pipe.cpp:207
void Close()
Close all pipe endpoints.
Definition: pipe.cpp:212
bool IsPipeWriteOpened() const noexcept
Is pipe opened for writing?
Definition: pipe.cpp:205
bool IsPipeReadOpened() const noexcept
Is pipe opened for reading?
Definition: pipe.cpp:204
void * reader() const noexcept
Get the native read endpoint handler.
Definition: pipe.cpp:200
void * writer() const noexcept
Get the native write endpoint handler.
Definition: pipe.cpp:201
void CloseRead()
Close the read pipe endpoint.
Definition: pipe.cpp:210
void swap(Pipe &pipe) noexcept
Swap two instances.
Definition: pipe.cpp:214
virtual ~Pipe()
Definition: pipe.cpp:194
#define throwex
Throw extended exception macro.
Definition: exceptions.h:23
Fatal abort execution definition.
#define fatality(...)
Fatal abort execution extended macro.
Definition: fatal.h:22
C++ Common project definitions.
Definition: token_bucket.h:15
void swap(FileCache &cache1, FileCache &cache2) noexcept
Definition: filecache.inl:23
Pipe definition.
Aligned storage validator definition.