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 
aio_suspend(const struct aiocb * const cbs[],int cnt,const struct timespec * ts)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 }
76 
77 #if !_REDIR_TIME64
78 weak_alias(aio_suspend, aio_suspend64);
79 #endif
80