1 /*- 2 * Copyright (c) 2011 Venkatesh Srinivas <vsrinivas@dragonflybsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 */ 15 16 /* 17 * This file contains support for the POSIX 1003.1B AIO/LIO facility. 18 * 19 * This version of AIO is aimed at standards compliance; it is not aimed 20 * at either reasonability or performance. It merely wraps synchronous I/O 21 * routines. 22 * 23 * This version cannot perform asynchronous notification of I/O completion 24 * on DragonFly via SIGEV_THREAD or SIGEV_SIGNAL. 25 * 26 * 1) SIGEV_THREAD is not supported by DFly's sigevent structure or any 27 * other machinery in libthread or librt. 28 * 29 * 2) SIGEV_SIGNAL code is present, but if-ed out under 'notyet'; Dfly 30 * does not support sigqueue(), so we cannot control the payload to 31 * a SIGINFO-signal from userspace. Programs using AIO signals use 32 * the payload field to carry pointers to the completed AIO structure, 33 * which is not yet possible here. 34 * 35 * It would be possible for this version to support SIGEV_KEVENT. 36 */ 37 38 #include <stdlib.h> 39 #include <sys/types.h> 40 #include <sys/time.h> 41 #include <sys/signal.h> 42 #include <sys/queue.h> 43 #include <unistd.h> 44 #include <errno.h> 45 #include <sys/aio.h> 46 47 static void 48 _aio_signal(struct aiocb *ap) 49 { 50 #ifdef notyet 51 int sig; 52 union sigval sv; 53 pid_t pid; 54 55 if (ap->aio_sigevent.sigev_notify == SIGEV_NONE) 56 return; 57 58 sig = ap->aio_sigevent.sigev_signo; 59 sv = ap->aio_sigevent.sigev_value; 60 61 sigqueue(pid, sig, sv); 62 #endif 63 } 64 65 static void 66 _lio_signal(struct sigevent *sigevp) 67 { 68 #ifdef notyet 69 int sig; 70 union sigval sv; 71 pid_t pid; 72 73 pid = getpid(); 74 sig = sigevp->sigev_signo; 75 sv = sigevp->sigev_value; 76 77 sigqueue(pid, sig, sv); 78 #endif 79 } 80 81 /* 82 * aio_read() 83 * 84 * Asynchronously read from a file 85 */ 86 int 87 aio_read(struct aiocb *ap) 88 { 89 #ifndef notyet 90 if (ap->aio_sigevent.sigev_notify != SIGEV_NONE) 91 return (ENOSYS); 92 #endif 93 94 ap->_aio_val = pread(ap->aio_fildes, 95 (void *) ap->aio_buf, 96 ap->aio_nbytes, 97 ap->aio_offset); 98 ap->_aio_err = errno; 99 100 _aio_signal(ap); 101 102 return (0); 103 } 104 105 int 106 aio_write(struct aiocb *ap) 107 { 108 #ifndef notyet 109 if (ap->aio_sigevent.sigev_notify != SIGEV_NONE) 110 return (ENOSYS); 111 #endif 112 113 ap->_aio_val = pwrite(ap->aio_fildes, 114 (void *) ap->aio_buf, 115 ap->aio_nbytes, 116 ap->aio_offset); 117 ap->_aio_err = errno; 118 119 _aio_signal(ap); 120 121 return (0); 122 } 123 124 int 125 aio_fsync(int op, struct aiocb *ap) 126 { 127 #ifndef notyet 128 if (ap->aio_sigevent.sigev_notify != SIGEV_NONE) 129 return (ENOSYS); 130 #endif 131 132 ap->_aio_val = fsync(ap->aio_fildes); 133 ap->_aio_err = errno; 134 135 _aio_signal(ap); 136 137 return(0); 138 } 139 140 int 141 lio_listio(int mode, struct aiocb *const apv[], int nent, 142 struct sigevent *sigevp) 143 { 144 int i; 145 146 #ifndef notyet 147 if (sigevp && sigevp->sigev_notify != SIGEV_NONE) 148 return (ENOSYS); 149 #endif 150 151 for (i = 0; i < nent; i++) 152 switch (apv[i]->aio_lio_opcode) { 153 case LIO_READ: 154 aio_read(apv[i]); 155 break; 156 case LIO_WRITE: 157 aio_write(apv[i]); 158 break; 159 case LIO_NOP: 160 break; 161 } 162 163 if (sigevp && 164 (mode == LIO_NOWAIT) && 165 (sigevp->sigev_notify == SIGEV_SIGNAL) 166 ) { 167 _lio_signal(sigevp); 168 } 169 170 return (0); 171 } 172 173 /* 174 * aio_error() 175 * 176 * Get I/O completion status 177 * 178 * Returns EINPROGRESS until I/O is complete. Returns ECANCELED if 179 * I/O is canceled. Returns I/O status if operation completed. 180 * 181 * This routine does not block. 182 */ 183 int 184 aio_error(const struct aiocb *ap) 185 { 186 return (ap->_aio_err); 187 } 188 189 /* 190 * aio_return() 191 * 192 * Finish up I/O, releasing I/O resources and returns the value 193 * that would have been associated with a synchronous request. 194 */ 195 ssize_t 196 aio_return(struct aiocb *ap) 197 { 198 return (ap->_aio_val); 199 } 200 201 int 202 aio_cancel(int fildes, struct aiocb *aiocbp) 203 { 204 return (AIO_ALLDONE); 205 } 206 207 int 208 aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timo) 209 { 210 return (0); 211 } 212 213