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