1 /* 2 Copyright 2020 Boris-Barboris 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 6 Permission is hereby granted, free of charge, to any person or organization 7 obtaining a copy of the software and accompanying documentation covered by 8 this license (the "Software") to use, reproduce, display, distribute, 9 execute, and transmit the Software, and to prepare derivative works of the 10 Software, and to permit third-parties to whom the Software is furnished to 11 do so, all subject to the following: 12 13 The copyright notices in the Software and this entire statement, including 14 the above license grant, this restriction and the following disclaimer, 15 must be included in all copies of the Software, in whole or in part, and 16 all derivative works of the Software, unless such copies or derivative 17 works are solely in the form of machine-executable object code generated by 18 a source language processor. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 */ 28 module libaio; 29 30 import core.stdc.config; 31 import core.sys.posix.time: timespec; 32 import core.sys.posix.signal: sigset_t; 33 import core.sys.posix.sys.uio: iovec; 34 import core.sys.linux.sys.socket: sockaddr; 35 36 37 // Online examples: 38 // https://www.fsl.cs.sunysb.edu/~vass/linux-aio.txt 39 // https://manpages.ubuntu.com/manpages/precise/man3/io.3.html 40 // https://pagure.io/libaio/blob/master/f/man/io.3 41 42 43 @nogc nothrow: 44 45 alias io_context_t = void*; 46 47 enum io_iocb_cmd: short 48 { 49 IO_CMD_PREAD = 0, 50 IO_CMD_PWRITE = 1, 51 52 IO_CMD_FSYNC = 2, 53 IO_CMD_FDSYNC = 3, 54 55 IO_CMD_POLL = 5, 56 IO_CMD_NOOP = 6, 57 IO_CMD_PREADV = 7, 58 IO_CMD_PWRITEV = 8, 59 }; 60 61 // from /usr/include/linux/aio_abi.h 62 enum io_iocb_flags: uint 63 { 64 IOCB_FLAG_RESFD = (1 << 0), 65 IOCB_FLAG_IOPRIO = (1 << 1) 66 } 67 68 align(8) struct io_iocb_poll 69 { 70 int events; 71 }; 72 73 static assert (io_iocb_poll.sizeof == 8); 74 75 struct io_iocb_sockaddr 76 { 77 sockaddr* addr; 78 int len; 79 }; 80 81 struct io_iocb_common 82 { 83 align(8): 84 void* buf; 85 c_ulong nbytes; 86 long offset; 87 long __pad3; 88 align(4): 89 uint flags; 90 uint resfd; 91 }; 92 93 static assert (io_iocb_common.sizeof == 40); 94 95 struct io_iocb_vector 96 { 97 iovec* vec; 98 int nr; 99 long offset; 100 }; 101 102 static assert (io_iocb_vector.sizeof == 8 + 4 + 8 + 4); 103 104 struct iocb 105 { 106 align(8): 107 void *data; 108 private uint key; // used by kernel 109 align(4): 110 uint aio_rw_flags; // RWF_ flags from /usr/include/linux/fs 111 align: 112 io_iocb_cmd aio_lio_opcode; 113 short aio_reqprio; 114 int aio_fildes; 115 116 union { 117 io_iocb_common c; 118 io_iocb_vector v; 119 io_iocb_poll poll; 120 io_iocb_sockaddr saddr; 121 }; 122 }; 123 124 static assert (iocb.sizeof == 8 + 4 + 4 + 2 * 2 + 4 + io_iocb_common.sizeof); 125 126 struct io_event 127 { 128 align(8): 129 void* data; 130 iocb* obj; 131 c_ulong res; 132 c_ulong res2; 133 } 134 135 static assert (io_event.sizeof == 32); 136 137 138 139 alias io_callback_t = extern(C) nothrow @nogc void function( 140 io_context_t ctx, iocb* iocb, c_long res, c_long res2); 141 142 alias da_io_queue_init = extern(C) nothrow @nogc int function( 143 int maxevents, io_context_t* ctxp); 144 145 alias da_io_queue_release = extern(C) nothrow @nogc int function( 146 io_context_t ctx); 147 148 alias da_io_queue_run = extern(C) nothrow @nogc int function( 149 io_context_t ctx); 150 151 alias da_io_setup = extern(C) nothrow @nogc int function( 152 int maxevents, io_context_t* ctxp); 153 154 alias da_io_destroy = extern(C) nothrow @nogc int function( 155 io_context_t ctx); 156 157 alias da_io_submit = extern(C) nothrow @nogc int function( 158 io_context_t ctx, c_long nr, iocb** ios); 159 160 alias da_io_cancel = extern(C) nothrow @nogc int function( 161 io_context_t ctx, iocb *iocb, io_event* evt); 162 163 alias da_io_getevents = extern(C) nothrow @nogc int function( 164 io_context_t ctx_id, c_long min_nr, c_long nr, io_event* events, 165 timespec* timeout); 166 167 alias da_io_pgetevents = extern(C) nothrow @nogc int function( 168 io_context_t ctx_id, c_long min_nr, c_long nr, 169 io_event* events, timespec* timeout, sigset_t* sigmask); 170 171 172 __gshared 173 { 174 da_io_queue_init io_queue_init; 175 da_io_queue_release io_queue_release; 176 da_io_queue_run io_queue_run; 177 da_io_setup io_setup; 178 da_io_destroy io_destroy; 179 da_io_submit io_submit; 180 da_io_cancel io_cancel; 181 da_io_getevents io_getevents; 182 da_io_pgetevents io_pgetevents; 183 } 184 185 186 // UFCS-optimized functions from libaio.h 187 188 pragma(inline) void io_set_callback(ref iocb iocb, io_callback_t cb) 189 { 190 iocb.data = cast(void*) cb; 191 } 192 193 pragma(inline) void io_prep_pread( 194 ref iocb iocb, int fd, void* buf, size_t count, long offset) 195 { 196 iocb = iocb.init; 197 iocb.aio_fildes = fd; 198 iocb.aio_lio_opcode = io_iocb_cmd.IO_CMD_PREAD; 199 iocb.aio_reqprio = 0; 200 iocb.c.buf = buf; 201 iocb.c.nbytes = count; 202 iocb.c.offset = offset; 203 } 204 205 pragma(inline) void io_prep_pwrite( 206 ref iocb iocb, int fd, void* buf, size_t count, long offset) 207 { 208 iocb = iocb.init; 209 iocb.aio_fildes = fd; 210 iocb.aio_lio_opcode = io_iocb_cmd.IO_CMD_PWRITE; 211 iocb.aio_reqprio = 0; 212 iocb.c.buf = buf; 213 iocb.c.nbytes = count; 214 iocb.c.offset = offset; 215 } 216 217 pragma(inline) void io_prep_preadv( 218 ref iocb iocb, int fd, iovec* iov, int iovcnt, long offset) 219 { 220 iocb = iocb.init; 221 iocb.aio_fildes = fd; 222 iocb.aio_lio_opcode = io_iocb_cmd.IO_CMD_PREADV; 223 iocb.aio_reqprio = 0; 224 iocb.c.buf = cast(void*) iov; 225 iocb.c.nbytes = iovcnt; 226 iocb.c.offset = offset; 227 } 228 229 pragma(inline) void io_prep_pwritev( 230 ref iocb iocb, int fd, iovec* iov, int iovcnt, long offset) 231 { 232 iocb = iocb.init; 233 iocb.aio_fildes = fd; 234 iocb.aio_lio_opcode = io_iocb_cmd.IO_CMD_PWRITEV; 235 iocb.aio_reqprio = 0; 236 iocb.c.buf = cast(void*) iov; 237 iocb.c.nbytes = iovcnt; 238 iocb.c.offset = offset; 239 } 240 241 pragma(inline) void io_prep_preadv2( 242 ref iocb iocb, int fd, iovec* iov, int iovcnt, long offset, int flags) 243 { 244 iocb = iocb.init; 245 iocb.aio_fildes = fd; 246 iocb.aio_lio_opcode = io_iocb_cmd.IO_CMD_PREADV; 247 iocb.aio_reqprio = 0; 248 iocb.aio_rw_flags = flags; 249 iocb.c.buf = cast(void*) iov; 250 iocb.c.nbytes = iovcnt; 251 iocb.c.offset = offset; 252 } 253 254 pragma(inline) void io_prep_pwritev2( 255 ref iocb iocb, int fd, iovec* iov, int iovcnt, long offset, int flags) 256 { 257 iocb = iocb.init; 258 iocb.aio_fildes = fd; 259 iocb.aio_lio_opcode = io_iocb_cmd.IO_CMD_PWRITEV; 260 iocb.aio_reqprio = 0; 261 iocb.aio_rw_flags = flags; 262 iocb.c.buf = cast(void*) iov; 263 iocb.c.nbytes = iovcnt; 264 iocb.c.offset = offset; 265 } 266 267 pragma(inline) void io_prep_poll(ref iocb iocb, int fd, int events) 268 { 269 iocb = iocb.init; 270 iocb.aio_fildes = fd; 271 iocb.aio_lio_opcode = io_iocb_cmd.IO_CMD_POLL; 272 iocb.aio_reqprio = 0; 273 iocb.poll.events = events; 274 } 275 276 pragma(inline) int io_poll( 277 io_context_t ctx, iocb* iocb, io_callback_t cb, int fd, int events) 278 { 279 io_prep_poll(*iocb, fd, events); 280 io_set_callback(*iocb, cb); 281 return io_submit(ctx, 1, &iocb); 282 } 283 284 pragma(inline) void io_prep_fsync(ref iocb iocb, int fd) 285 { 286 iocb = iocb.init; 287 iocb.aio_fildes = fd; 288 iocb.aio_lio_opcode = io_iocb_cmd.IO_CMD_FSYNC; 289 iocb.aio_reqprio = 0; 290 } 291 292 pragma(inline) int io_fsync( 293 io_context_t ctx, iocb* iocb, io_callback_t cb, int fd) 294 { 295 io_prep_fsync(*iocb, fd); 296 io_set_callback(*iocb, cb); 297 return io_submit(ctx, 1, &iocb); 298 } 299 300 pragma(inline) void io_prep_fdsync(ref iocb iocb, int fd) 301 { 302 iocb = iocb.init; 303 iocb.aio_fildes = fd; 304 iocb.aio_lio_opcode = io_iocb_cmd.IO_CMD_FDSYNC; 305 iocb.aio_reqprio = 0; 306 } 307 308 pragma(inline) int io_fdsync( 309 io_context_t ctx, iocb* iocb, io_callback_t cb, int fd) 310 { 311 io_prep_fdsync(*iocb, fd); 312 io_set_callback(*iocb, cb); 313 return io_submit(ctx, 1, &iocb); 314 } 315 316 pragma(inline) void io_set_eventfd(ref iocb iocb, int eventfd) 317 { 318 iocb.c.flags |= io_iocb_flags.IOCB_FLAG_RESFD; 319 iocb.c.resfd = eventfd; 320 }