diff --git a/kernel-src/io/net/arp.c b/kernel-src/io/net/arp.c index fcaa9916..15128b42 100644 --- a/kernel-src/io/net/arp.c +++ b/kernel-src/io/net/arp.c @@ -270,7 +270,7 @@ int arp_lookup(netdev_t *netdev, uint32_t ip, mac_t *mac) { } MUTEX_RELEASE(&cachelock); - int timedout = EVENT_WAIT(&eventlistener, to); + e = EVENT_WAIT(&eventlistener, to); MUTEX_ACQUIRE(&cachelock); time = timekeeper_time(); @@ -279,7 +279,10 @@ int arp_lookup(netdev_t *netdev, uint32_t ip, mac_t *mac) { break; } - if (timedout || time.s > end.s || (end.s == time.s && time.ns >= end.ns)) { + if (e == EINTR) + return e; + + if (e == ETIMEDOUT || time.s > end.s || (end.s == time.s && time.ns >= end.ns)) { e = ENETUNREACH; break; } diff --git a/kernel-src/io/poll.c b/kernel-src/io/poll.c index 4d81c54a..3ea9d1ca 100644 --- a/kernel-src/io/poll.c +++ b/kernel-src/io/poll.c @@ -79,7 +79,7 @@ static void timeout(context_t *, dpcarg_t arg) { spinlock_acquire(&desc->eventlock); if (spinlock_try(&desc->lock)) - sched_wakeup(desc->thread, 1); + sched_wakeup(desc->thread, ETIMEDOUT); spinlock_release(&desc->eventlock); interrupt_set(intstate); @@ -115,15 +115,13 @@ int poll_dowait(polldesc_t *desc, size_t ustimeout) { ret = EINTR; } - if (ustimeout != 0 && ret != 1) { + if (ustimeout != 0 && ret != ETIMEDOUT) { timer_remove(current_cpu()->timer, &sleepentry); sched_target_cpu(NULL); } interrupt_set(intstate); - ret = ret == 1 ? 0 : ret; - return ret; } diff --git a/kernel-src/io/tty.c b/kernel-src/io/tty.c index cdb853da..a13703df 100644 --- a/kernel-src/io/tty.c +++ b/kernel-src/io/tty.c @@ -266,17 +266,16 @@ static int read(int minor, iovec_iterator_t *iovec_iterator, size_t size, uintma error = poll_dowait(&desc, effectivetimeout); - - if (error == 0 && (desc.event == NULL || (desc.event && desc.event->revents == 0))) { - // timed out! - poll_leave(&desc); - poll_destroydesc(&desc); - break; - } - poll_leave(&desc); poll_destroydesc(&desc); + if (error == ETIMEDOUT) { + // this does not return an error on timeout. + // instead, it just returns the number of bytes read. + error = 0; + break; + } + if (error) goto leave; } diff --git a/kernel-src/sys/syscalls/futex.c b/kernel-src/sys/syscalls/futex.c index 1d0dd495..557654df 100644 --- a/kernel-src/sys/syscalls/futex.c +++ b/kernel-src/sys/syscalls/futex.c @@ -5,6 +5,7 @@ #include #include #include +#include static mutex_t futexmutex; static hashtable_t hashtable; @@ -50,7 +51,14 @@ syscallret_t syscall_futex(context_t *, uint32_t *futexp, int op, uint32_t value MUTEX_INIT(&futexmutex); } - timespec_t timespec = tm ? *tm : (timespec_t){0}; + timespec_t timespec = {0}; + if (tm) { + ret.errno = usercopy_fromuser(×pec, tm, sizeof(timespec_t)); + if (ret.errno) + return ret; + } + uintmax_t us = timespec.s * 1000000 + timespec.ns / 1000; + polldesc_t desc = {0}; ret.errno = poll_initdesc(&desc, 1); if (unlikely(ret.errno)) @@ -89,6 +97,12 @@ syscallret_t syscall_futex(context_t *, uint32_t *futexp, int op, uint32_t value break; } + // if timeout is zero, do not sleep + if (tm && us == 0) { + ret.errno = ETIMEDOUT; + break; + } + if (futex == NULL) { futex = alloc(sizeof(futex_t)); if (futex == NULL) { @@ -101,26 +115,21 @@ syscallret_t syscall_futex(context_t *, uint32_t *futexp, int op, uint32_t value break; } - uintmax_t us = timespec.s * 1000000 + timespec.ns / 1000; ++futex->waiting; - + for (;;) { poll_add(&futex->pollheader, &desc.data[0], POLLOUT); MUTEX_RELEASE(&futexmutex); ret.errno = poll_dowait(&desc, us); - int revents = 0; - if (desc.event) - revents = desc.event->revents; MUTEX_ACQUIRE(&futexmutex); - if (revents == 0 || ret.errno == EINTR) { + if (ret.errno) { // timed out or interrupted --futex->waiting; futex->waking = futex->waking > futex->waiting ? futex->waiting : futex->waking; // if it happened during a wakeup, just to make sure nothing bad happens - ret.errno = ret.errno == EINTR ? EINTR : 0; } else if (futex->waking == 0) { // should go back to sleep poll_leave(&desc); diff --git a/kernel-src/sys/syscalls/poll.c b/kernel-src/sys/syscalls/poll.c index 331fc0b9..faa1d3a3 100644 --- a/kernel-src/sys/syscalls/poll.c +++ b/kernel-src/sys/syscalls/poll.c @@ -75,11 +75,15 @@ syscallret_t syscall_poll(context_t *, pollfd_t *fds, size_t nfds, int timeoutms if (eventcount == 0 && timeoutms != 0) { ret.errno = poll_dowait(&desc, (timeoutms == -1 ? 0 : timeoutms) * 1000); - if (ret.errno == 0 && desc.event) { + if (ret.errno == 0) { int fd = ((uintptr_t)desc.event - (uintptr_t)desc.data) / sizeof(polldata_t); fdsbuff[fd].revents = desc.data[fd].revents; eventcount = 1; } + + // timeout is not an error in poll() + if (ret.errno == ETIMEDOUT) + ret.errno = 0; } if (ret.errno == 0)