dns query core: detect udp truncation at recv time
[musl] / src / aio / lio_listio.c
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);