OLD | NEW |
(Empty) | |
| 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 |
| 8 struct lio_state { |
| 9 struct sigevent *sev; |
| 10 int cnt; |
| 11 struct aiocb *cbs[]; |
| 12 }; |
| 13 |
| 14 static 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 |
| 41 static 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 |
| 53 static 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 |
| 70 int lio_listio(int mode, struct aiocb *restrict const *restrict cbs, int cnt, st
ruct 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; |
| 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); |
| 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, 0); |
| 139 } |
| 140 |
| 141 return 0; |
| 142 } |
| 143 |
| 144 LFS64(lio_listio); |
OLD | NEW |