diff --git a/pkg/fdnotifier/fdnotifier.go b/pkg/fdnotifier/fdnotifier.go index 152557143..0858e0866 100644 --- a/pkg/fdnotifier/fdnotifier.go +++ b/pkg/fdnotifier/fdnotifier.go @@ -155,13 +155,20 @@ func (n *notifier) waitAndNotify() error { return err } + notified := false n.mu.Lock() for i := 0; i < v; i++ { if fi, ok := n.fdMap[e[i].Fd]; ok { fi.queue.Notify(waiter.EventMaskFromLinux(e[i].Events)) + notified = true } } n.mu.Unlock() + if notified { + // Let goroutines woken by Notify get a chance to run before we + // epoll_wait again. + sync.Goyield() + } } } diff --git a/pkg/sync/runtime_unsafe.go b/pkg/sync/runtime_unsafe.go index cd17f7368..cd7b9025b 100644 --- a/pkg/sync/runtime_unsafe.go +++ b/pkg/sync/runtime_unsafe.go @@ -22,6 +22,15 @@ import ( "unsafe" ) +// Goyield is runtime.goyield, which is similar to runtime.Gosched but only +// yields the processor to other goroutines already on the processor's +// runqueue. +// +//go:nosplit +func Goyield() { + goyield() +} + // Gopark is runtime.gopark. Gopark calls unlockf(pointer to runtime.g, lock); // if unlockf returns true, Gopark blocks until Goready(pointer to runtime.g) // is called. unlockf and its callees must be nosplit and norace, since stack