Lely core libraries  2.2.5
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 (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 (!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 (ClearCommError(handle->fd, NULL, NULL))
112  goto retry;
113  // ... falls through ...
114  default: dwErrCode = GetLastError(); goto error_ReadFile;
115  }
116 
117  if ((flags & IO_FLAG_NONBLOCK) && !CancelIoEx(handle->fd, &overlapped)
118  && GetLastError() == ERROR_NOT_FOUND) {
119  dwErrCode = GetLastError();
120  goto error_CancelIoEx;
121  }
122 
123  // clang-format off
124  if (!GetOverlappedResult(handle->fd, &overlapped, &dwNumberOfBytesRead,
125  TRUE)) {
126  // clang-format on
127  dwErrCode = GetLastError();
128  goto error_GetOverlappedResult;
129  }
130 
131  if (nbytes && !dwNumberOfBytesRead) {
132  if (!(flags & IO_FLAG_NONBLOCK))
133  goto retry;
134  dwErrCode = errnum2c(ERRNUM_AGAIN);
135  goto error_dwNumberOfBytesRead;
136  }
137 
138 done:
139  CloseHandle(overlapped.hEvent);
140  SetLastError(dwErrCode);
141  return dwNumberOfBytesRead;
142 
143 error_dwNumberOfBytesRead:
144 error_GetOverlappedResult:
145 error_CancelIoEx:
146 error_ReadFile:
147  CloseHandle(overlapped.hEvent);
148 error_CreateEvent:
149  SetLastError(dwErrCode);
150  return -1;
151 #else
152  ssize_t result;
153  int errsv = errno;
154  do {
155  errno = errsv;
156  result = read(handle->fd, buf, nbytes);
157  } while (result == -1 && errno == EINTR);
158  return result;
159 #endif
160 }
161 
162 static inline ssize_t
163 default_write(struct io_handle *handle, const void *buf, size_t nbytes)
164 {
165  assert(handle);
166 
167 #ifdef _WIN32
168  DWORD dwErrCode = GetLastError();
169 
170  OVERLAPPED overlapped = { 0 };
171  overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
172  if (!overlapped.hEvent) {
173  dwErrCode = GetLastError();
174  goto error_CreateEvent;
175  }
176 
177  DWORD dwNumberOfBytesWritten = 0;
178 
179 retry:
180  io_handle_lock(handle);
181  int flags = handle->flags;
182  io_handle_unlock(handle);
183 
184  // clang-format off
185  if (WriteFile(handle->fd, buf, nbytes, &dwNumberOfBytesWritten,
186  &overlapped))
187  // clang-format on
188  goto done;
189 
190  switch (GetLastError()) {
191  case ERROR_IO_PENDING: break;
192  case ERROR_OPERATION_ABORTED:
193  if (ClearCommError(handle->fd, NULL, NULL))
194  goto retry;
195  // ... falls through ...
196  default: dwErrCode = GetLastError(); goto error_WriteFile;
197  }
198 
199  if ((flags & IO_FLAG_NONBLOCK) && !CancelIoEx(handle->fd, &overlapped)
200  && GetLastError() == ERROR_NOT_FOUND) {
201  dwErrCode = GetLastError();
202  goto error_CancelIoEx;
203  }
204 
205  // clang-format off
206  if (!GetOverlappedResult(handle->fd, &overlapped,
207  &dwNumberOfBytesWritten, TRUE)) {
208  // clang-format on
209  dwErrCode = GetLastError();
210  goto error_GetOverlappedResult;
211  }
212 
213  if (nbytes && !dwNumberOfBytesWritten) {
214  if (!(flags & IO_FLAG_NONBLOCK))
215  goto retry;
216  dwErrCode = errnum2c(ERRNUM_AGAIN);
217  goto error_dwNumberOfBytesWritten;
218  }
219 
220 done:
221  CloseHandle(overlapped.hEvent);
222  SetLastError(dwErrCode);
223  return dwNumberOfBytesWritten;
224 
225 error_dwNumberOfBytesWritten:
226 error_GetOverlappedResult:
227 error_CancelIoEx:
228 error_WriteFile:
229  CloseHandle(overlapped.hEvent);
230 error_CreateEvent:
231  SetLastError(dwErrCode);
232  return -1;
233 #else
234  ssize_t result;
235  int errsv = errno;
236  do {
237  errno = errsv;
238  result = write(handle->fd, buf, nbytes);
239  } while (result == -1 && errno == EINTR);
240  return result;
241 #endif
242 }
243 
244 #endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
245 
246 #ifdef __cplusplus
247 }
248 #endif
249 
250 #endif // !LELY_IO_INTERN_DEFAULT_H_
This header file is part of the utilities library; it contains the native and platform-independent er...
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:825
@ ERRNUM_AGAIN
Resource unavailable, try again.
Definition: errnum.h:86
void io_handle_unlock(struct io_handle *handle)
Unlocks a locked I/O device handle.
Definition: handle.c:147
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
This is the internal header file of the I/O handle declarations.
@ IO_FLAG_NONBLOCK
Perform I/O operations in non-blocking mode.
Definition: io.h:62
@ IO_FLAG_NO_CLOSE
Do not close the native file descriptor when closing an I/O device.
Definition: io.h:60
This is the internal header file of the Windows-specific I/O declarations.
An I/O device handle.
Definition: handle.h:41
int fd
The native file descriptor.
Definition: handle.h:56
int flags
The I/O device flags (any combination of IO_FLAG_NO_CLOSE and IO_FLAG_NONBLOCK).
Definition: handle.h:62