static DWORD adjust_timeout_win32(DWORD timeout, uint64_t start) { if (timeout == INFINITE) return INFINITE; uint64_t now = ty_millis(); if (now > start + timeout) return 0; return (DWORD)(start + timeout - now); }
int ty_poll(const ty_descriptor_set *set, int timeout) { assert(set); assert(set->count); assert(set->count <= 64); fd_set fds; uint64_t start; struct timeval tv; int r; FD_ZERO(&fds); for (unsigned int i = 0; i < set->count; i++) FD_SET(set->desc[i], &fds); start = ty_millis(); restart: if (timeout >= 0) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; } r = select(FD_SETSIZE, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); if (r < 0) { switch (errno) { case EINTR: timeout = ty_adjust_timeout(timeout, start); goto restart; case ENOMEM: return ty_error(TY_ERROR_MEMORY, NULL); } return ty_error(TY_ERROR_SYSTEM, "poll() failed: %s", strerror(errno)); } if (!r) return 0; for (unsigned int i = 0; i < set->count; i++) { if (FD_ISSET(set->desc[i], &fds)) return set->id[i]; } assert(false); __builtin_unreachable(); }
// Not sure if the fallback code is correct or not, let's hope so for now static BOOL WINAPI SleepConditionVariableCS_fallback(CONDITION_VARIABLE *cv, CRITICAL_SECTION *mutex, DWORD timeout) { ty_cond *cond = (ty_cond *)cv; uint64_t start; bool signaled; DWORD wret; while (true) { EnterCriticalSection((CRITICAL_SECTION *)&cond->xp.mutex); if (!cond->xp.wakeup) break; LeaveCriticalSection((CRITICAL_SECTION *)&cond->xp.mutex); } cond->xp.waiting++; LeaveCriticalSection((CRITICAL_SECTION *)&cond->xp.mutex); LeaveCriticalSection(mutex); start = ty_millis(); restart: wret = WaitForSingleObject(cond->xp.ev, adjust_timeout_win32(timeout, start)); assert(wret == WAIT_OBJECT_0 || wret == WAIT_TIMEOUT); EnterCriticalSection((CRITICAL_SECTION *)&cond->xp.mutex); if (cond->xp.wakeup) { if (!--cond->xp.wakeup) ResetEvent(cond->xp.ev); signaled = true; } else if (wret == WAIT_TIMEOUT) { signaled = false; } else { LeaveCriticalSection((CRITICAL_SECTION *)&cond->xp.mutex); goto restart; } cond->xp.waiting--; LeaveCriticalSection((CRITICAL_SECTION *)&cond->xp.mutex); EnterCriticalSection(mutex); return signaled; }
int ty_poll(const ty_descriptor_set *set, int timeout) { assert(set); assert(set->count); assert(set->count <= 64); struct pollfd pfd[64]; uint64_t start; int r; for (unsigned int i = 0; i < set->count; i++) { pfd[i].events = POLLIN; pfd[i].fd = set->desc[i]; } if (timeout < 0) timeout = -1; start = ty_millis(); restart: r = poll(pfd, (nfds_t)set->count, ty_adjust_timeout(timeout, start)); if (r < 0) { switch (errno) { case EINTR: goto restart; case ENOMEM: return ty_error(TY_ERROR_MEMORY, NULL); } return ty_error(TY_ERROR_SYSTEM, "poll() failed: %s", strerror(errno)); } if (!r) return 0; for (unsigned int i = 0; i < set->count; i++) { if (pfd[i].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL)) return set->id[i]; } assert(false); __builtin_unreachable(); }