Lely core libraries 2.3.4
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
32extern "C" {
33#endif
34
35#if _WIN32 || _POSIX_C_SOURCE >= 200112L
36
37static inline void default_fini(struct io_handle *handle);
38static inline int default_flags(struct io_handle *handle, int flags);
39static inline ssize_t default_read(
40 struct io_handle *handle, void *buf, size_t nbytes);
41static inline ssize_t default_write(
42 struct io_handle *handle, const void *buf, size_t nbytes);
43
44static inline void
45default_fini(struct io_handle *handle)
46{
47 assert(handle);
48
49 if (!(handle->flags & IO_FLAG_NO_CLOSE))
50#if _WIN32
51 CloseHandle(handle->fd);
52#else
53 close(handle->fd);
54#endif
55}
56
57static inline int
58default_flags(struct io_handle *handle, int flags)
59{
60 assert(handle);
61
62#if _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
80static inline ssize_t
81default_read(struct io_handle *handle, void *buf, size_t nbytes)
82{
83 assert(handle);
84
85#if _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
97retry:
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
138done:
139 CloseHandle(overlapped.hEvent);
140 SetLastError(dwErrCode);
141 return dwNumberOfBytesRead;
142
143error_dwNumberOfBytesRead:
144error_GetOverlappedResult:
145error_CancelIoEx:
146error_ReadFile:
147 CloseHandle(overlapped.hEvent);
148error_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
162static inline ssize_t
163default_write(struct io_handle *handle, const void *buf, size_t nbytes)
164{
165 assert(handle);
166
167#if _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
179retry:
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
220done:
221 CloseHandle(overlapped.hEvent);
222 SetLastError(dwErrCode);
223 return dwNumberOfBytesWritten;
224
225error_dwNumberOfBytesWritten:
226error_GetOverlappedResult:
227error_CancelIoEx:
228error_WriteFile:
229 CloseHandle(overlapped.hEvent);
230error_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:810
@ ERRNUM_AGAIN
Resource unavailable, try again.
Definition: errnum.h:89
void io_handle_unlock(struct io_handle *handle)
Unlocks a locked I/O device handle.
Definition: handle.c:151
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:143
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:33
int fd
The native file descriptor.
Definition: handle.h:48
int flags
The I/O device flags (any combination of IO_FLAG_NO_CLOSE and IO_FLAG_NONBLOCK).
Definition: handle.h:54