1#include <aio.h> 2#include <errno.h> 3#include <unistd.h> 4#include <string.h> 5#include "pthread_impl.h" 6#include "libc.h" 7 8struct lio_state { 9 struct sigevent *sev; 10 int cnt; 11 struct aiocb *cbs[]; 12}; 13 14static int lio_wait(struct lio_state *st) 15{ 16 int i, err, got_err = 0; 17 int cnt = st->cnt; 18 struct aiocb **cbs = st->cbs; 19 20 for (;;) { 21 for (i=0; i<cnt; i++) { 22 if (!cbs[i]) continue; 23 err = aio_error(cbs[i]); 24 if (err==EINPROGRESS) 25 break; 26 if (err) got_err=1; 27 cbs[i] = 0; 28 } 29 if (i==cnt) { 30 if (got_err) { 31 errno = EIO; 32 return -1; 33 } 34 return 0; 35 } 36 if (aio_suspend((void *)cbs, cnt, 0)) 37 return -1; 38 } 39} 40 41static void notify_signal(struct sigevent *sev) 42{ 43 siginfo_t si = { 44 .si_signo = sev->sigev_signo, 45 .si_value = sev->sigev_value, 46 .si_code = SI_ASYNCIO, 47 .si_pid = getpid(), 48 .si_uid = getuid() 49 }; 50 __syscall(SYS_rt_sigqueueinfo, si.si_pid, si.si_signo, &si); 51} 52 53static void *wait_thread(void *p) 54{ 55 struct lio_state *st = p; 56 struct sigevent *sev = st->sev; 57 lio_wait(st); 58 free(st); 59 switch (sev->sigev_notify) { 60 case SIGEV_SIGNAL: 61 notify_signal(sev); 62 break; 63 case SIGEV_THREAD: 64 sev->sigev_notify_function(sev->sigev_value); 65 break; 66 } 67 return 0; 68} 69 70int lio_listio(int mode, struct aiocb *restrict const *restrict cbs, int cnt, struct sigevent *restrict sev) 71{ 72 int i, ret; 73 struct lio_state *st=0; 74 75 if (cnt < 0) { 76 errno = EINVAL; 77 return -1; 78 } 79 80 if (mode == LIO_WAIT || (sev && sev->sigev_notify != SIGEV_NONE)) { 81 if (!(st = malloc(sizeof *st + cnt*sizeof *cbs))) { 82 errno = EAGAIN; 83 return -1; 84 } 85 st->cnt = cnt; 86 st->sev = sev; 87 memcpy(st->cbs, (void*) cbs, cnt*sizeof *cbs); 88 } 89 90 for (i=0; i<cnt; i++) { 91 if (!cbs[i]) continue; 92 switch (cbs[i]->aio_lio_opcode) { 93 case LIO_READ: 94 ret = aio_read(cbs[i]); 95 break; 96 case LIO_WRITE: 97 ret = aio_write(cbs[i]); 98 break; 99 default: 100 continue; 101 } 102 if (ret) { 103 free(st); 104 errno = EAGAIN; 105 return -1; 106 } 107 } 108 109 if (mode == LIO_WAIT) { 110 ret = lio_wait(st); 111 free(st); 112 return ret; 113 } 114 115 if (st) { 116 pthread_attr_t a; 117 sigset_t set, set_old; 118 pthread_t td; 119 120 if (sev->sigev_notify == SIGEV_THREAD) { 121 if (sev->sigev_notify_attributes) 122 a = *sev->sigev_notify_attributes; 123 else 124 pthread_attr_init(&a); 125 } else { 126 pthread_attr_init(&a); 127 pthread_attr_setstacksize(&a, PAGE_SIZE); 128 pthread_attr_setguardsize(&a, 0); 129 } 130 pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); 131 sigfillset(&set); 132 pthread_sigmask(SIG_BLOCK, &set, &set_old); 133 if (pthread_create(&td, &a, wait_thread, st)) { 134 free(st); 135 errno = EAGAIN; 136 return -1; 137 } 138 pthread_sigmask(SIG_SETMASK, &set_old, 0); 139 } 140 141 return 0; 142} 143 144LFS64(lio_listio); 145