Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 1 | #include <aio.h> |
| 2 | #include <errno.h> |
Rich Felker | 4e8a356 | 2015-02-13 00:27:45 -0500 | [diff] [blame] | 3 | #include <time.h> |
| 4 | #include "atomic.h" |
Szabolcs Nagy | 36c30c4 | 2014-09-04 22:01:36 +0200 | [diff] [blame] | 5 | #include "libc.h" |
Rich Felker | 4e8a356 | 2015-02-13 00:27:45 -0500 | [diff] [blame] | 6 | #include "pthread_impl.h" |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 7 | |
Rich Felker | 4e8a356 | 2015-02-13 00:27:45 -0500 | [diff] [blame] | 8 | extern volatile int __aio_fut; |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 9 | |
Rich Felker | 13cd969 | 2011-09-13 21:09:35 -0400 | [diff] [blame] | 10 | int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec *ts) |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 11 | { |
Rich Felker | 4e8a356 | 2015-02-13 00:27:45 -0500 | [diff] [blame] | 12 | int i, tid = 0, ret, expect = 0; |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 13 | struct timespec at; |
Rich Felker | 4e8a356 | 2015-02-13 00:27:45 -0500 | [diff] [blame] | 14 | volatile int dummy_fut, *pfut; |
| 15 | int nzcnt = 0; |
| 16 | const struct aiocb *cb = 0; |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 17 | |
Rich Felker | 5451d95 | 2015-03-02 18:11:28 -0500 | [diff] [blame] | 18 | pthread_testcancel(); |
| 19 | |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 20 | if (cnt<0) { |
| 21 | errno = EINVAL; |
| 22 | return -1; |
| 23 | } |
| 24 | |
Rich Felker | 4e8a356 | 2015-02-13 00:27:45 -0500 | [diff] [blame] | 25 | for (i=0; i<cnt; i++) if (cbs[i]) { |
| 26 | if (aio_error(cbs[i]) != EINPROGRESS) return 0; |
| 27 | nzcnt++; |
| 28 | cb = cbs[i]; |
| 29 | } |
| 30 | |
| 31 | if (ts) { |
| 32 | clock_gettime(CLOCK_MONOTONIC, &at); |
| 33 | at.tv_sec += ts->tv_sec; |
| 34 | if ((at.tv_nsec += ts->tv_nsec) >= 1000000000) { |
| 35 | at.tv_nsec -= 1000000000; |
| 36 | at.tv_sec++; |
| 37 | } |
| 38 | } |
| 39 | |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 40 | for (;;) { |
Rich Felker | 4e8a356 | 2015-02-13 00:27:45 -0500 | [diff] [blame] | 41 | for (i=0; i<cnt; i++) |
| 42 | if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS) |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 43 | return 0; |
Rich Felker | 4e8a356 | 2015-02-13 00:27:45 -0500 | [diff] [blame] | 44 | |
| 45 | switch (nzcnt) { |
| 46 | case 0: |
| 47 | pfut = &dummy_fut; |
| 48 | break; |
| 49 | case 1: |
| 50 | pfut = (void *)&cb->__err; |
| 51 | expect = EINPROGRESS | 0x80000000; |
| 52 | a_cas(pfut, EINPROGRESS, expect); |
| 53 | break; |
| 54 | default: |
| 55 | pfut = &__aio_fut; |
| 56 | if (!tid) tid = __pthread_self()->tid; |
| 57 | expect = a_cas(pfut, 0, tid); |
| 58 | if (!expect) expect = tid; |
| 59 | /* Need to recheck the predicate before waiting. */ |
| 60 | for (i=0; i<cnt; i++) |
| 61 | if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS) |
| 62 | return 0; |
| 63 | break; |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 64 | } |
| 65 | |
Rich Felker | 5451d95 | 2015-03-02 18:11:28 -0500 | [diff] [blame] | 66 | ret = __timedwait_cp(pfut, expect, CLOCK_MONOTONIC, ts?&at:0, 1); |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 67 | |
Rich Felker | 5451d95 | 2015-03-02 18:11:28 -0500 | [diff] [blame] | 68 | switch (ret) { |
| 69 | case ETIMEDOUT: |
| 70 | ret = EAGAIN; |
| 71 | case ECANCELED: |
| 72 | case EINTR: |
| 73 | errno = ret; |
Rich Felker | b4de6f9 | 2011-09-09 01:07:38 -0400 | [diff] [blame] | 74 | return -1; |
| 75 | } |
| 76 | } |
| 77 | } |
Szabolcs Nagy | 36c30c4 | 2014-09-04 22:01:36 +0200 | [diff] [blame] | 78 | |
| 79 | LFS64(aio_suspend); |