diff --git a/kernel-src/include/kernel/poll.h b/kernel-src/include/kernel/poll.h index 4314efab..fa279588 100644 --- a/kernel-src/include/kernel/poll.h +++ b/kernel-src/include/kernel/poll.h @@ -10,6 +10,7 @@ typedef struct { thread_t *thread; spinlock_t lock; spinlock_t eventlock; + spinlock_t wakeuplock; struct polldata *data; struct polldata *event; size_t size; diff --git a/kernel-src/io/poll.c b/kernel-src/io/poll.c index 401eb37a..f8a8c462 100644 --- a/kernel-src/io/poll.c +++ b/kernel-src/io/poll.c @@ -40,6 +40,7 @@ int poll_initdesc(polldesc_t *desc, size_t size) { desc->size = size; SPINLOCK_INIT(desc->lock); SPINLOCK_INIT(desc->eventlock); + SPINLOCK_INIT(desc->wakeuplock); for (uintmax_t i = 0; i < size; ++i) desc->data[i].desc = desc; __assert(spinlock_try(&desc->lock)); @@ -106,8 +107,11 @@ int poll_dowait(polldesc_t *desc, size_t ustimeout) { spinlock_release(&desc->eventlock); int ret = sched_yield(); // on return, the desc lock is REQUIRED to be left locked by the poll_event function. - // XXX interruptible wait breaks this - __assert(spinlock_try(&desc->lock) == false); + // in the case of sleep being interrupted, wait until poll_event has done everything (if anything) + __assert(ret || spinlock_try(&desc->lock) == false); + + if (ret) + spinlock_acquire(&desc->wakeuplock); if (ustimeout != 0 && ret != 1) { timer_remove(_cpu()->timer, &sleepentry); @@ -134,7 +138,7 @@ void poll_event(pollheader_t *header, int events) { spinlock_acquire(&desc->eventlock); int revents = iterator->events & events; - if (spinlock_try(&desc->lock) == false) { + if (spinlock_try(&desc->lock) == false || spinlock_try(&desc->wakeuplock) == false) { removefromlist(&pending, iterator); insertinheader(header, iterator); } @@ -154,6 +158,7 @@ void poll_event(pollheader_t *header, int events) { polldata_t *next = iterator->next; sched_wakeup(iterator->desc->thread, 0); insertinheader(header, iterator); + spinlock_release(&iterator->desc->wakeuplock); iterator = next; } diff --git a/kernel-src/sys/syscalls/sleep.c b/kernel-src/sys/syscalls/sleep.c index 6fa94c10..9f688f0d 100644 --- a/kernel-src/sys/syscalls/sleep.c +++ b/kernel-src/sys/syscalls/sleep.c @@ -34,10 +34,8 @@ syscallret_t syscall_nanosleep(context_t *, timespec_t *utime, timespec_t *remai ret.errno = sched_yield(); - if (ret.errno) { - // XXX interruptible wait might break things + if (ret.errno) timer_remove(_cpu()->timer, &sleepentry); - } sched_targetcpu(NULL);