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