implement POSIX asynchronous io
[musl] / src / aio / aio_suspend.c
1 #include <aio.h>
2 #include <errno.h>
3 #include "pthread_impl.h"
4
5 /* Due to the requirement that aio_suspend be async-signal-safe, we cannot
6  * use any locks, wait queues, etc. that would make it more efficient. The
7  * only obviously-correct algorithm is to generate a wakeup every time any
8  * aio operation finishes and have aio_suspend re-evaluate the completion
9  * status of each aiocb it was waiting on. */
10
11 static volatile int seq;
12
13 void __aio_wake(void)
14 {
15         a_inc(&seq);
16         __wake(&seq, -1, 1);
17 }
18
19 int aio_suspend(struct aiocb *const cbs[], int cnt, const struct timespec *ts)
20 {
21         int i, last, first=1, ret=0;
22         struct timespec at;
23
24         if (cnt<0) {
25                 errno = EINVAL;
26                 return -1;
27         }
28
29         for (;;) {
30                 last = seq;
31
32                 for (i=0; i<cnt; i++) {
33                         if (cbs[i] && cbs[i]->__err != EINPROGRESS)
34                                 return 0;
35                 }
36
37                 if (first && ts) {
38                         clock_gettime(CLOCK_MONOTONIC, &at);
39                         at.tv_sec += ts->tv_sec;
40                         if ((at.tv_nsec += ts->tv_nsec) >= 1000000000) {
41                                 at.tv_nsec -= 1000000000;
42                                 at.tv_sec++;
43                         }
44                         first = 0;
45                 }
46
47                 ret = __timedwait(&seq, last, CLOCK_MONOTONIC,
48                         ts ? &at : 0, 0, 0, 1);
49
50                 if (ret == ETIMEDOUT) ret = EAGAIN;
51
52                 if (ret) {
53                         errno = ret;
54                         return -1;
55                 }
56         }
57 }