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