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->sigev_notify != SIGEV_NONE) && 161 (sigevp->sigev_notify != SIGEV_THREAD)) 162 return (ENOSYS); 163 #endif 164 165 for (i = 0; i < nent; i++) 166 switch (apv[i]->aio_lio_opcode) { 167 case LIO_READ: 168 aio_read(apv[i]); 169 break; 170 case LIO_WRITE: 171 aio_write(apv[i]); 172 break; 173 case LIO_NOP: 174 break; 175 } 176 177 if (sigevp && 178 (mode == LIO_NOWAIT) 179 ) { 180 _aio_notify(sigevp); 181 } 182 183 return (0); 184 } 185 186 /* 187 * aio_error() 188 * 189 * Get I/O completion status 190 * 191 * Returns EINPROGRESS until I/O is complete. Returns ECANCELED if 192 * I/O is canceled. Returns I/O status if operation completed. 193 * 194 * This routine does not block. 195 */ 196 int 197 aio_error(const struct aiocb *ap) 198 { 199 return (ap->_aio_err); 200 } 201 202 /* 203 * aio_return() 204 * 205 * Finish up I/O, releasing I/O resources and returns the value 206 * that would have been associated with a synchronous request. 207 */ 208 ssize_t 209 aio_return(struct aiocb *ap) 210 { 211 return (ap->_aio_val); 212 } 213 214 int 215 aio_cancel(int fildes, struct aiocb *aiocbp) 216 { 217 return (AIO_ALLDONE); 218 } 219 220 int 221 aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timo) 222 { 223 return (0); 224 } 225 226