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
|
/* 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)) */
att_read(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)) */
att_read(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)) */
att_read(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)) */
att_read(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) */
att_writen(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) */
att_writen(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) */
att_readn(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) */
att_readn(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) */
att_writen(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) */
att_readn(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
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 */
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 */
int iom_add(iomux_t* c,int64 s,unsigned int events);
/* signal interest in more events from a socket */
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 */
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 */
int iom_abort(iomux_t* c);
#ifdef __cplusplus
}
#endif
#endif
|