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