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
32extern "C" {
33#endif
34
35#if defined(_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#ifdef _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#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
80static inline ssize_t
81default_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
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 (__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
140done:
141 CloseHandle(overlapped.hEvent);
142 SetLastError(dwErrCode);
143 return dwNumberOfBytesRead;
144
145error_dwNumberOfBytesRead:
146error_GetOverlappedResult:
147error_CancelIoEx:
148error_ReadFile:
149 CloseHandle(overlapped.hEvent);
150error_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
164static inline ssize_t
165default_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
181retry:
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
224done:
225 CloseHandle(overlapped.hEvent);
226 SetLastError(dwErrCode);
227 return dwNumberOfBytesWritten;
228
229error_dwNumberOfBytesWritten:
230error_GetOverlappedResult:
231error_CancelIoEx:
232error_WriteFile:
233 CloseHandle(overlapped.hEvent);
234error_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_
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
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
#define __likely(x)
Indicates to the compiler that the expression is most-likely true.
Definition: features.h:273
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 I/O library.
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
ptrdiff_t ssize_t
Used for a count of bytes or an error indication.
Definition: types.h:43