-
Notifications
You must be signed in to change notification settings - Fork 3
/
io.h
281 lines (230 loc) · 9.62 KB
/
io.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/* this header file comes from libowfat, http://www.fefe.de/libowfat/ */
#ifndef IO_H
#define IO_H
#ifdef __MINGW32__
#include_next <io.h>
#endif
/* http://cr.yp.to/lib/io.html */
#include <libowfat/uint64.h>
#include <libowfat/taia.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
extern "C" {
#endif
/* like open(s,O_RDONLY) */
/* return 1 if ok, 0 on error */
/* sandboxing: open(2) (glibc: openat(2)) */
__strin(2)
att_write(1)
int io_readfile(int64* d,const char* filename);
/* like open(s,O_WRONLY|O_CREAT|O_TRUNC,0600) */
/* return 1 if ok, 0 on error */
/* sandboxing: open(2) (glibc: openat(2)) */
__strin(2)
att_write(1)
int io_createfile(int64* d,const char* filename);
/* like open(s,O_RDWR) */
/* return 1 if ok, 0 on error */
/* sandboxing: open(2) (glibc: openat(2)) */
__strin(2)
att_write(1)
int io_readwritefile(int64* d,const char* filename);
/* like open(s,O_WRONLY|O_APPEND|O_CREAT,0600) */
/* return 1 if ok, 0 on error */
/* sandboxing: open(2) (glibc: openat(2)) */
__strin(2)
att_write(1)
int io_appendfile(int64* d,const char* filename);
/* like pipe(d) */
/* return 1 if ok, 0 on error */
/* sandboxing: pipe(2), close(2), mmap(2), munmap(2), linux: epoll_create(2), bsd: kqueue(2), solaris: open(2) on /dev/poll, oldlinux: sigprocmask(2), fcntl(2) */
att_write(1)
int io_pipe(int64* d);
/* like socketpair() */
/* return 1 if ok, 0 on error */
/* sandboxing: socketpair(2), close(2), mmap(2), munmap(2), linux: epoll_create(2), bsd: kqueue(2), solaris: open(2) /dev/poll, oldlinux: sigprocmask(2), fcntl(2) */
att_write(1)
int io_socketpair(int64* d);
/* non-blocking read(), -1 for EAGAIN and -3+errno for other errors */
/* sandboxing: poll(2), setitimer(2), read(2) */
__bufout(2, 3)
int64 io_tryread(int64 d,char* buf,int64 len);
/* blocking read(), with -3 instead of -1 for errors */
/* sandboxing: poll(2), read(2) */
__bufout(2, 3)
int64 io_waitread(int64 d,char* buf,int64 len);
/* non-blocking write(), -1 for EAGAIN and -3+errno for other errors */
/* sandboxing: poll(2), setitimer(2), write(2) */
__bufin(2, 3)
int64 io_trywrite(int64 d,const char* buf,int64 len);
/* blocking write(), with -3 instead of -1 for errors */
/* sandboxing: poll(2), write(2) */
__bufin(2, 3)
int64 io_waitwrite(int64 d,const char* buf,int64 len);
/* modify timeout attribute of file descriptor */
/* sandboxing: calls no syscalls */
void io_timeout(int64 d,tai6464 t);
/* like io_tryread but will return -2,errno=ETIMEDOUT if d has a timeout
* associated and it is passed without input being there */
/* sandboxing: poll(2), setitimer(2), gettimeofday(2), read(2) */
__bufout(2, 3)
int64 io_tryreadtimeout(int64 d,char* buf,int64 len);
/* like io_trywrite but will return -2,errno=ETIMEDOUT if d has a timeout
* associated and it is passed without being able to write */
/* sandboxing: poll(2), setitimer(2), gettimeofday(2), write(2) */
__bufin(2, 3)
int64 io_trywritetimeout(int64 d,const char* buf,int64 len);
/* sandboxing: linux: epoll_ctl(2), bsd: kevent(2), solaris: write(2), oldlinux: poll(2) */
void io_wantread(int64 d);
void io_wantwrite(int64 d);
void io_dontwantread(int64 d);
void io_dontwantwrite(int64 d);
/* sandboxing: close(2), linux: epoll_wait(2), linux: epoll_ctl(2), bsd: kevent(2), solaris: ioctl(2), oldlinux: sigwaitinfo(2), oldlinux: sigtimedwait(2), oldlinux: signal(2), realloc(3): mmap/mremap/munmap/brk/brk2, poll(2) */
void io_wait();
void io_waituntil(tai6464 t);
int64 io_waituntil2(int64 milliseconds);
void io_check();
/* signal that read/accept/whatever returned EAGAIN */
/* needed for SIGIO and epoll */
/* sandboxing: linux: epoll_ctl(2), bsd: kevent(2), solaris: write(2), oldlinux: poll(2) */
void io_eagain(int64 d); /* do not use, API was a bad idea */
#define HAVE_EAGAIN_READWRITE
void io_eagain_read(int64 d); /* use these ones */
void io_eagain_write(int64 d);
/* return next descriptor from io_wait that can be read from */
/* sandboxing: linux: epoll_ctl(2), bsd: kevent(2), solaris: write(2), oldlinux: poll(2) */
int64 io_canread();
/* return next descriptor from io_wait that can be written to */
/* sandboxing: linux: epoll_ctl(2), bsd: kevent(2), solaris: write(2), oldlinux: poll(2) */
int64 io_canwrite();
/* return next descriptor with expired timeout */
/* sandboxing: calls no syscalls */
int64 io_timeouted();
/* is this fd over its timeout? */
/* sandboxing: calls no syscalls */
int io_timedout(int64 d);
/* 1 means: have IO_FD_CANWRITE, IO_FD_BLOCK and IO_FD_NONBLOCK,
* will be incremented if API is extended in the future */
#define HAVE_IO_FD_FLAGS 1
enum io_fd_flags {
IO_FD_CANWRITE=1, /* new TCP connection, we know it's writable */
IO_FD_BLOCK=2, /* skip the fcntl, assume fd is set to blocking */
IO_FD_NONBLOCK=4, /* skip the fcntl, assume fd is set to non-blocking */
};
/* put d on internal data structure, return 1 on success, 0 on error */
/* sandboxing: fcntl(2), mmap(2), munmap(2), linux: epoll_create(2), bsd: kqueue(2), solaris: open(2) on /dev/poll, oldlinux: sigprocmask(2), fcntl(2) */
int io_fd(int64 d); /* use this for sockets before you called connect() or accept() */
int io_fd_canwrite(int64 d); /* use this for connected sockets (assumes socket is writable) */
int io_fd_flags(int64 d,int flags); /* can be used to tell io_fd to skip one syscall */
/* sandboxing: calls no syscalls */
att_write(2)
void io_setcookie(int64 d,void* cookie);
/* sandboxing: calls no syscalls */
void* io_getcookie(int64 d);
/* put descriptor in non-blocking mode */
/* sandboxing: fcntl(2) */
void io_nonblock(int64 d);
/* put descriptor in blocking mode */
/* sandboxing: fcntl(2) */
void io_block(int64 d);
/* put descriptor in close-on-exec mode */
/* sandboxing: fcntl(2) */
void io_closeonexec(int64 d);
/* sandboxing: munmap(2), close(2) */
void io_close(int64 d);
/* Free the internal data structures from libio.
* This only makes sense if you run your program in a malloc checker and
* these produce false alarms. Your OS will free these automatically on
* process termination. */
/* sandboxing: free(3): munmap(2) */
void io_finishandshutdown(void);
/* send n bytes from file fd starting at offset off to socket s */
/* return number of bytes written */
/* sandboxing: sendfile(2), fallback: write(2), fallback: mmap(2), fallback: munmap(2), fallback: lseek(2), fallback: pread(2), fallback: read(2), linux: epoll_ctl(2), bsd: kevent(2), solaris: write(2), oldlinux: poll(2) */
int64 io_sendfile(int64 s,int64 fd,uint64 off,uint64 n);
/* Pass fd over sock (must be a unix domain socket) to other process.
* Return 0 if ok, -1 on error, setting errno. */
/* sandboxing: sendmsg(2) */
int io_passfd(int64 sock,int64 fd);
/* Receive fd over sock (must be a unix domain socket) from other
* process. Return sock if ok, -1 on error, setting errno. */
/* sandboxing: recvmsg(2) */
int64 io_receivefd(int64 sock);
int io_starteventloopthread(unsigned int threads);
#define HAVE_IO_QUEUEFORREAD
/* Artificially queue a file descriptor as readable.
* The next call to io_canread will return this descriptor. */
int io_queueforread(int64 d);
/* Artificially queue a file descriptor as writable.
* The next call to io_canread will return this descriptor. */
int io_queueforwrite(int64 d);
typedef int64 (*io_write_callback)(int64 s,const void* buf,uint64 n);
typedef int64 (*io_sendfile_callback)(int64 out,int64 in,uint64 off,uint64 bytes,io_write_callback writecb);
/* used internally, but hey, who knows */
/* sandboxing: write(2), mmap(2), munmap(2), lseek(2), pread(2), read(2), linux: epoll_ctl(2), bsd: kevent(2), solaris: write(2), oldlinux: poll(2) */
int64 io_mmapwritefile(int64 out,int64 in,uint64 off,uint64 bytes,io_write_callback writecb);
/* only needed for debugging, will print some stats into the buffer to
* aid in debugging the state machine if a descriptor loops or so */
/* sandboxing: calls no syscalls */
unsigned int io_debugstring(int64 s,char* buf,unsigned int bufsize);
#ifdef __MINGW32__
// https://github.com/lhmouse/mcfgthread
#include <mcfgthread/c11.h>
#elif defined(__dietlibc__)
#include <threads.h>
#else
#include <pthread.h>
#ifndef __APPLE__
#include <semaphore.h>
#endif
#endif
/* Do not use this yet. The API does not support timeout handling yet.
* When we add it, the API will probably change in an incompatible way. */
enum { SLOTS=128 };
typedef struct iomux {
int ctx;
volatile int working; /* used to synchronize who is filling the queue */
volatile unsigned int h,l; /* high, low */
struct {
int fd, events;
} q[SLOTS];
#if defined(__MINGW32__) || defined(__dietlibc__)
mtx_t mtx;
cnd_t sem;
#elif defined(__APPLE__)
pthread_mutex_t mtx;
pthread_cond_t sem;
#else
sem_t sem;
#endif
} iomux_t;
/* Init master context */
att_nonnull(1) att_write(1)
int iom_init(iomux_t* c);
/* Add socket to iomux */
enum {
IOM_READ=1,
IOM_WRITE=2,
IOM_ERROR=4
};
/* signal interest in events from a socket */
/* return -1 if error, events can be IOM_READ or IOM_WRITE */
att_nonnull(1) att_mangle(1)
int iom_add(iomux_t* c,int64 s,unsigned int events);
/* signal interest in more events from a socket */
att_nonnull(1) att_mangle(1)
int iom_requeue(iomux_t* c,int64 s,unsigned int events);
/* Blocking wait for single event, timeout in milliseconds */
/* return -1 if error, 0 if ok; s set to fd, revents set to known events on that fd */
/* when done with the fd, call iom_requeue on it to receive more events! */
/* This can be called by multiple threads in parallel */
att_write(2) att_write(3) att_mangle(1) att_nonnull(1) att_nonnull(2) att_nonnull(3)
int iom_wait(iomux_t* c,int64* s,unsigned int* revents,unsigned long timeout);
/* Call this to terminate all threads waiting in iom_wait */
/* Returns 0 on success, -1 on failure */
att_nonnull(1)
int iom_abort(iomux_t* c);
#ifdef __cplusplus
}
#endif
#endif