Loading...
#include <aio.h> #include <errno.h> #include <time.h> #include "atomic.h" #include "libc.h" #include "pthread_impl.h" extern volatile int __aio_fut; int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec *ts) { int i, tid = 0, ret, expect = 0; struct timespec at; volatile int dummy_fut, *pfut; int nzcnt = 0; const struct aiocb *cb = 0; pthread_testcancel(); if (cnt<0) { errno = EINVAL; return -1; } for (i=0; i<cnt; i++) if (cbs[i]) { if (aio_error(cbs[i]) != EINPROGRESS) return 0; nzcnt++; cb = cbs[i]; } if (ts) { clock_gettime(CLOCK_MONOTONIC, &at); at.tv_sec += ts->tv_sec; if ((at.tv_nsec += ts->tv_nsec) >= 1000000000) { at.tv_nsec -= 1000000000; at.tv_sec++; } } for (;;) { for (i=0; i<cnt; i++) if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS) return 0; switch (nzcnt) { case 0: pfut = &dummy_fut; break; case 1: pfut = (void *)&cb->__err; expect = EINPROGRESS | 0x80000000; a_cas(pfut, EINPROGRESS, expect); break; default: pfut = &__aio_fut; if (!tid) tid = __pthread_self()->tid; expect = a_cas(pfut, 0, tid); if (!expect) expect = tid; /* Need to recheck the predicate before waiting. */ for (i=0; i<cnt; i++) if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS) return 0; break; } ret = __timedwait_cp(pfut, expect, CLOCK_MONOTONIC, ts?&at:0, 1); switch (ret) { case ETIMEDOUT: ret = EAGAIN; case ECANCELED: case EINTR: errno = ret; return -1; } } } LFS64(aio_suspend); |