1#include <aio.h>
2#include <errno.h>
3#include <time.h>
4#include "atomic.h"
5#include "libc.h"
6#include "pthread_impl.h"
7
8extern volatile int __aio_fut;
9
10int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec *ts)
11{
12	int i, tid = 0, ret, expect = 0;
13	struct timespec at;
14	volatile int dummy_fut, *pfut;
15	int nzcnt = 0;
16	const struct aiocb *cb = 0;
17
18	pthread_testcancel();
19
20	if (cnt<0) {
21		errno = EINVAL;
22		return -1;
23	}
24
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
40	for (;;) {
41		for (i=0; i<cnt; i++)
42			if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS)
43				return 0;
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;
64		}
65
66		ret = __timedwait_cp(pfut, expect, CLOCK_MONOTONIC, ts?&at:0, 1);
67
68		switch (ret) {
69		case ETIMEDOUT:
70			ret = EAGAIN;
71		case ECANCELED:
72		case EINTR:
73			errno = ret;
74			return -1;
75		}
76	}
77}
78
79LFS64(aio_suspend);
80