// SPDX-License-Identifier: ISC #define _GNU_SOURCE /* for ppoll */ #include #include #include #include #include struct dl dl_now = DL_NOW; int init_dl(struct dl *dl, clockid_t clock, unsigned long ms) { dl->clock = clock; if (clock_gettime(clock, &dl->time) < 0) return -1; timespec_add_msec(&dl->time, &dl->time, ms); return 0; } bool passed_dl(const struct dl *dl) { struct timespec now; if (!dl) return false; /* shortcut for dl_now, so we do not need dl->clock */ if (!dl->time.tv_sec && !dl->time.tv_nsec) return true; if (clock_gettime(dl->clock, &now) < 0) return true; if (timespec_is_less(&dl->time, &now)) { errno = ETIMEDOUT; return true; } return false; } int sleep_dl(const struct dl *dl) { struct timespec now, diff; int r; if (!dl) return 0; /* shortcut for dl_now, so we do not need dl->clock */ if (!dl->time.tv_sec && !dl->time.tv_nsec) return 0; if (clock_gettime(dl->clock, &now) < 0) return -1; if (!timespec_sub(&diff, &dl->time, &now)) return 0; while ((r = nanosleep(&diff, &diff)) < 0 && errno == EINTR) ; if (r < 0) return -1; return 1; } static int poll_timeout_fixup(int ret) { if (!ret) { errno = ETIMEDOUT; return -1; } return ret; } int poll_dl(struct pollfd *fds, nfds_t nfds, const struct dl *dl) { struct timespec now, diff; /* should never return timeout, so poll_timeout_fixup is not needed */ if (!dl) return poll(fds, nfds, -1); /* shortcut for dl_now, so we do not need dl->clock */ if (!dl->time.tv_sec && !dl->time.tv_nsec) return poll_timeout_fixup(poll(fds, nfds, 0)); if (clock_gettime(dl->clock, &now) < 0) return -1; /* return timeout if we already passed the deadline */ if (!timespec_sub(&diff, &dl->time, &now)) { errno = ETIMEDOUT; return -1; } return poll_timeout_fixup(ppoll(fds, nfds, &diff, NULL)); } const struct dl *next_dl(const struct dl *lhs, const struct dl *rhs) { if (!lhs) return rhs; if (!rhs) return lhs; if (timespec_is_less(&lhs->time, &rhs->time)) return lhs; return rhs; }