Lely core libraries  1.9.2
default.h
Go to the documentation of this file.
1 
22 #ifndef LELY_IO_INTERN_DEFAULT_H_
23 #define LELY_IO_INTERN_DEFAULT_H_
24 
25 #include "handle.h"
26 #include "io.h"
27 #include <lely/util/errnum.h>
28 
29 #include <assert.h>
30 
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34 
35 #if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
36 
37 static inline void default_fini(struct io_handle *handle);
38 static inline int default_flags(struct io_handle *handle, int flags);
39 static inline ssize_t default_read(
40  struct io_handle *handle, void *buf, size_t nbytes);
41 static inline ssize_t default_write(
42  struct io_handle *handle, const void *buf, size_t nbytes);
43 
44 static inline void
45 default_fini(struct io_handle *handle)
46 {
47  assert(handle);
48 
49  if (!(handle->flags & IO_FLAG_NO_CLOSE))
50 #ifdef _WIN32
51  CloseHandle(handle->fd);
52 #else
53  close(handle->fd);
54 #endif
55 }
56 
57 static inline int
58 default_flags(struct io_handle *handle, int flags)
59 {
60  assert(handle);
61 
62 #ifdef _WIN32
63  (void)handle;
64  (void)flags;
65 
66  return 0;
67 #else
68  int arg = fcntl(handle->fd, F_GETFL, 0);
69  if (__unlikely(arg == -1))
70  return -1;
71 
72  if ((flags & IO_FLAG_NONBLOCK) && !(arg & O_NONBLOCK))
73  return fcntl(handle->fd, F_SETFL, arg | O_NONBLOCK);
74  else if (!(flags & IO_FLAG_NONBLOCK) && (arg & O_NONBLOCK))
75  return fcntl(handle->fd, F_SETFL, arg & ~O_NONBLOCK);
76  return 0;
77 #endif
78 }
79 
80 static inline ssize_t
81 default_read(struct io_handle *handle, void *buf, size_t nbytes)
82 {
83  assert(handle);
84 
85 #ifdef _WIN32
86  DWORD dwErrCode = GetLastError();
87 
88  OVERLAPPED overlapped = { 0 };
89  overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
90  if (__unlikely(!overlapped.hEvent)) {
91  dwErrCode = GetLastError();
92  goto error_CreateEvent;
93  }
94 
95  DWORD dwNumberOfBytesRead = 0;
96 
97 retry:
98  io_handle_lock(handle);
99  int flags = handle->flags;
100  io_handle_unlock(handle);
101 
102  // clang-format off
103  if (ReadFile(handle->fd, buf, nbytes, &dwNumberOfBytesRead,
104  &overlapped))
105  // clang-format on
106  goto done;
107 
108  switch (GetLastError()) {
109  case ERROR_IO_PENDING: break;
110  case ERROR_OPERATION_ABORTED:
111  if (__likely(ClearCommError(handle->fd, NULL, NULL)))
112  goto retry;
113  // ... falls through ...
114  default: dwErrCode = GetLastError(); goto error_ReadFile;
115  }
116 
117  // clang-format off
118  if ((flags & IO_FLAG_NONBLOCK) && __unlikely(!CancelIoEx(handle->fd,
119  &overlapped) && GetLastError() == ERROR_NOT_FOUND)) {
120  // clang-format on
121  dwErrCode = GetLastError();
122  goto error_CancelIoEx;
123  }
124 
125  // clang-format off
126  if (__unlikely(!GetOverlappedResult(handle->fd, &overlapped,
127  &dwNumberOfBytesRead, TRUE))) {
128  // clang-format on
129  dwErrCode = GetLastError();
130  goto error_GetOverlappedResult;
131  }
132 
133  if (__unlikely(nbytes && !dwNumberOfBytesRead)) {
134  if (!(flags & IO_FLAG_NONBLOCK))
135  goto retry;
136  dwErrCode = errnum2c(ERRNUM_AGAIN);
137  goto error_dwNumberOfBytesRead;
138  }
139 
140 done:
141  CloseHandle(overlapped.hEvent);
142  SetLastError(dwErrCode);
143  return dwNumberOfBytesRead;
144 
145 error_dwNumberOfBytesRead:
146 error_GetOverlappedResult:
147 error_CancelIoEx:
148 error_ReadFile:
149  CloseHandle(overlapped.hEvent);
150 error_CreateEvent:
151  SetLastError(dwErrCode);
152  return -1;
153 #else
154  ssize_t result;
155  int errsv = errno;
156  do {
157  errno = errsv;
158  result = read(handle->fd, buf, nbytes);
159  } while (__unlikely(result == -1 && errno == EINTR));
160  return result;
161 #endif
162 }
163 
164 static inline ssize_t
165 default_write(struct io_handle *handle, const void *buf, size_t nbytes)
166 {
167  assert(handle);
168 
169 #ifdef _WIN32
170  DWORD dwErrCode = GetLastError();
171 
172  OVERLAPPED overlapped = { 0 };
173  overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
174  if (__unlikely(!overlapped.hEvent)) {
175  dwErrCode = GetLastError();
176  goto error_CreateEvent;
177  }
178 
179  DWORD dwNumberOfBytesWritten = 0;
180 
181 retry:
182  io_handle_lock(handle);
183  int flags = handle->flags;
184  io_handle_unlock(handle);
185 
186  // clang-format off
187  if (WriteFile(handle->fd, buf, nbytes, &dwNumberOfBytesWritten,
188  &overlapped))
189  // clang-format on
190  goto done;
191 
192  switch (GetLastError()) {
193  case ERROR_IO_PENDING: break;
194  case ERROR_OPERATION_ABORTED:
195  if (__likely(ClearCommError(handle->fd, NULL, NULL)))
196  goto retry;
197  // ... falls through ...
198  default: dwErrCode = GetLastError(); goto error_WriteFile;
199  }
200 
201  // clang-format off
202  if ((flags & IO_FLAG_NONBLOCK) && __unlikely(!CancelIoEx(handle->fd,
203  &overlapped) && GetLastError() == ERROR_NOT_FOUND)) {
204  // clang-format on
205  dwErrCode = GetLastError();
206  goto error_CancelIoEx;
207  }
208 
209  // clang-format off
210  if (__unlikely(!GetOverlappedResult(handle->fd, &overlapped,
211  &dwNumberOfBytesWritten, TRUE))) {
212  // clang-format on
213  dwErrCode = GetLastError();
214  goto error_GetOverlappedResult;
215  }
216 
217  if (__unlikely(nbytes && !dwNumberOfBytesWritten)) {
218  if (!(flags & IO_FLAG_NONBLOCK))
219  goto retry;
220  dwErrCode = errnum2c(ERRNUM_AGAIN);
221  goto error_dwNumberOfBytesWritten;
222  }
223 
224 done:
225  CloseHandle(overlapped.hEvent);
226  SetLastError(dwErrCode);
227  return dwNumberOfBytesWritten;
228 
229 error_dwNumberOfBytesWritten:
230 error_GetOverlappedResult:
231 error_CancelIoEx:
232 error_WriteFile:
233  CloseHandle(overlapped.hEvent);
234 error_CreateEvent:
235  SetLastError(dwErrCode);
236  return -1;
237 #else
238  ssize_t result;
239  int errsv = errno;
240  do {
241  errno = errsv;
242  result = write(handle->fd, buf, nbytes);
243  } while (__unlikely(result == -1 && errno == EINTR));
244  return result;
245 #endif
246 }
247 
248 #endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
249 
250 #ifdef __cplusplus
251 }
252 #endif
253 
254 #endif // !LELY_IO_INTERN_DEFAULT_H_
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:825
void io_handle_unlock(struct io_handle *handle)
Unlocks a locked I/O device handle.
Definition: handle.c:147
This is the internal header file of the I/O handle declarations.
This header file is part of the utilities library; it contains the native and platform-independent er...
#define __likely(x)
Indicates to the compiler that the expression is most-likely true.
Definition: features.h:273
Do not close the native file descriptor when closing an I/O device.
Definition: io.h:60
Resource unavailable, try again.
Definition: errnum.h:86
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
This is the internal header file of the I/O library.
int flags
The I/O device flags (any combination of IO_FLAG_NO_CLOSE and IO_FLAG_NONBLOCK).
Definition: handle.h:62
Perform I/O operations in non-blocking mode.
Definition: io.h:62
int fd
The native file descriptor.
Definition: handle.h:56
void io_handle_lock(struct io_handle *handle)
Locks an unlocked I/O device handle, so the flags (and other device-specific fields) can safely be ac...
Definition: handle.c:139
An I/O device handle.
Definition: handle.h:41