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