remove LFS64 symbol aliases; replace with dynamic linker remapping
[musl] / src / aio / aio_suspend.c
1 #include <aio.h>
2 #include <errno.h>
3 #include <time.h>
4 #include "atomic.h"
5 #include "pthread_impl.h"
6 #include "aio_impl.h"
7
8 int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec *ts)
9 {
10         int i, tid = 0, ret, expect = 0;
11         struct timespec at;
12         volatile int dummy_fut, *pfut;
13         int nzcnt = 0;
14         const struct aiocb *cb = 0;
15
16         pthread_testcancel();
17
18         if (cnt<0) {
19                 errno = EINVAL;
20                 return -1;
21         }
22
23         for (i=0; i<cnt; i++) if (cbs[i]) {
24                 if (aio_error(cbs[i]) != EINPROGRESS) return 0;
25                 nzcnt++;
26                 cb = cbs[i];
27         }
28
29         if (ts) {
30                 clock_gettime(CLOCK_MONOTONIC, &at);
31                 at.tv_sec += ts->tv_sec;
32                 if ((at.tv_nsec += ts->tv_nsec) >= 1000000000) {
33                         at.tv_nsec -= 1000000000;
34                         at.tv_sec++;
35                 }
36         }
37
38         for (;;) {
39                 for (i=0; i<cnt; i++)
40                         if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS)
41                                 return 0;
42
43                 switch (nzcnt) {
44                 case 0:
45                         pfut = &dummy_fut;
46                         break;
47                 case 1:
48                         pfut = (void *)&cb->__err;
49                         expect = EINPROGRESS | 0x80000000;
50                         a_cas(pfut, EINPROGRESS, expect);
51                         break;
52                 default:
53                         pfut = &__aio_fut;
54                         if (!tid) tid = __pthread_self()->tid;
55                         expect = a_cas(pfut, 0, tid);
56                         if (!expect) expect = tid;
57                         /* Need to recheck the predicate before waiting. */
58                         for (i=0; i<cnt; i++)
59                                 if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS)
60                                         return 0;
61                         break;
62                 }
63
64                 ret = __timedwait_cp(pfut, expect, CLOCK_MONOTONIC, ts?&at:0, 1);
65
66                 switch (ret) {
67                 case ETIMEDOUT:
68                         ret = EAGAIN;
69                 case ECANCELED:
70                 case EINTR:
71                         errno = ret;
72                         return -1;
73                 }
74         }
75 }