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_SIGNAL. 25 * 26 * 2) SIGEV_SIGNAL code is present, but if-ed out under 'notyet'; Dfly 27 * does not support sigqueue(), so we cannot control the payload to 28 * a SIGINFO-signal from userspace. Programs using AIO signals use 29 * the payload field to carry pointers to the completed AIO structure, 30 * which is not yet possible here. 31 * 32 * It would be possible for this version to support SIGEV_KEVENT. 33 */ 34 35 #include <stdlib.h> 36 #include <sys/types.h> 37 #include <sys/time.h> 38 #include <sys/signal.h> 39 #include <sys/queue.h> 40 #include <unistd.h> 41 #include <errno.h> 42 #include <sys/aio.h> 43 #include <pthread.h> 44 45 static void *_aio_thr_start(void *); 46 47 static void 48 _aio_notify(struct sigevent *sigevp) 49 { 50 #if 0 /* not yet */ 51 int sig; 52 union sigval sv; 53 pid_t pid; 54 #endif 55 pthread_t thr; 56 57 switch (sigevp->sigev_notify) { 58 case SIGEV_NONE: 59 return; 60 61 case SIGEV_THREAD: 62 pthread_create(&thr, 63 sigevp->sigev_notify_attributes, 64 _aio_thr_start, 65 sigevp); 66 break; 67 68 case SIGEV_SIGNAL: 69 #if 0 /* not yet */ 70 pid = getpid(); 71 sig = sigevp->sigev_signo; 72 sv = sigevp->sigev_value; 73 sigqueue(pid, sig, sv); 74 #endif 75 break; 76 77 case SIGEV_KEVENT: 78 /* not yet */ 79 break; 80 } 81 } 82 83 static void * 84 _aio_thr_start(void *vsigevp) 85 { 86 struct sigevent *sigevp = vsigevp; 87 sigevp->sigev_notify_function(sigevp->sigev_value); 88 return (NULL); 89 } 90 91 /* 92 * aio_read() 93 * 94 * Asynchronously read from a file 95 */ 96 int 97 aio_read(struct aiocb *ap) 98 { 99 #ifndef notyet 100 if ((ap->aio_sigevent.sigev_notify != SIGEV_NONE) && 101 (ap->aio_sigevent.sigev_notify != SIGEV_THREAD)) 102 return (ENOSYS); 103 #endif 104 105 ap->_aio_val = pread(ap->aio_fildes, 106 (void *) ap->aio_buf, 107 ap->aio_nbytes, 108 ap->aio_offset); 109 ap->_aio_err = errno; 110 111 _aio_notify(&ap->aio_sigevent); 112 113 return (0); 114 } 115 116 int 117 aio_write(struct aiocb *ap) 118 { 119 #ifndef notyet 120 if ((ap->aio_sigevent.sigev_notify != SIGEV_NONE) && 121 (ap->aio_sigevent.sigev_notify != SIGEV_THREAD)) 122 return (ENOSYS); 123 #endif 124 125 ap->_aio_val = pwrite(ap->aio_fildes, 126 (void *) ap->aio_buf, 127 ap->aio_nbytes, 128 ap->aio_offset); 129 ap->_aio_err = errno; 130 131 _aio_notify(&ap->aio_sigevent); 132 133 return (0); 134 } 135 136 int 137 aio_fsync(int op, struct aiocb *ap) 138 { 139 #ifndef notyet 140 if ((ap->aio_sigevent.sigev_notify != SIGEV_NONE) && 141 (ap->aio_sigevent.sigev_notify != SIGEV_THREAD)) 142 return (ENOSYS); 143 #endif 144 145 ap->_aio_val = fsync(ap->aio_fildes); 146 ap->_aio_err = errno; 147 148 _aio_notify(&ap->aio_sigevent); 149 150 return(0); 151 } 152 153 int 154 lio_listio(int mode, struct aiocb *const apv[], int nent, 155 struct sigevent *sigevp) 156 { 157 int i; 158 159 #ifndef notyet 160 if (sigevp && 161 (sigevp->sigev_notify != SIGEV_NONE) && 162 (sigevp->sigev_notify != SIGEV_THREAD)) 163 return (ENOSYS); 164 #endif 165 166 for (i = 0; i < nent; i++) 167 switch (apv[i]->aio_lio_opcode) { 168 case LIO_READ: 169 aio_read(apv[i]); 170 break; 171 case LIO_WRITE: 172 aio_write(apv[i]); 173 break; 174 case LIO_NOP: 175 break; 176 } 177 178 if (sigevp && 179 (mode == LIO_NOWAIT) 180 ) { 181 _aio_notify(sigevp); 182 } 183 184 return (0); 185 } 186 187 /* 188 * aio_error() 189 * 190 * Get I/O completion status 191 * 192 * Returns EINPROGRESS until I/O is complete. Returns ECANCELED if 193 * I/O is canceled. Returns I/O status if operation completed. 194 * 195 * This routine does not block. 196 */ 197 int 198 aio_error(const struct aiocb *ap) 199 { 200 return (ap->_aio_err); 201 } 202 203 /* 204 * aio_return() 205 * 206 * Finish up I/O, releasing I/O resources and returns the value 207 * that would have been associated with a synchronous request. 208 */ 209 ssize_t 210 aio_return(struct aiocb *ap) 211 { 212 return (ap->_aio_val); 213 } 214 215 int 216 aio_cancel(int fildes, struct aiocb *aiocbp) 217 { 218 return (AIO_ALLDONE); 219 } 220 221 int 222 aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timo) 223 { 224 return (0); 225 } 226 227