diff --git a/internal/sysfs/poll_test.go b/internal/sysfs/poll_test.go index 192b7b0e29..6f6b35595e 100644 --- a/internal/sysfs/poll_test.go +++ b/internal/sysfs/poll_test.go @@ -8,40 +8,56 @@ import ( "testing" "time" + "github.com/tetratelabs/wazero/experimental/sys" "github.com/tetratelabs/wazero/internal/testing/require" ) func Test_poll(t *testing.T) { t.Run("should return immediately with no fds and duration 0", func(t *testing.T) { - n, err := _poll([]pollFd{}, 0) - require.EqualErrno(t, 0, err) - require.Equal(t, 0, n) + for { + n, err := _poll([]pollFd{}, 0) + if err == sys.EINTR { + t.Logf("Select interrupted") + continue + } + require.EqualErrno(t, 0, err) + require.Equal(t, 0, n) + return + } }) t.Run("should wait for the given duration", func(t *testing.T) { dur := int32(250) var took time.Duration - // On some platforms (e.g. Linux), the passed-in timeval is - // updated by select(2). We are not accounting for this - // in our implementation. - start := time.Now() - n, err := _poll([]pollFd{}, dur) - took = time.Since(start) - require.EqualErrno(t, 0, err) - require.Equal(t, 0, n) - - // On some platforms the actual timeout might be arbitrarily - // less than requested. - if took < time.Duration(dur)*time.Millisecond { - if runtime.GOOS == "linux" { - // Linux promises to only return early if a file descriptor - // becomes ready (not applicable here), or the call - // is interrupted by a signal handler (explicitly retried in the loop above), - // or the timeout expires. - t.Errorf("Select: slept for %v, expected %v", took, dur) - } else { - t.Logf("Select: slept for %v, requested %v", took, dur) + for { + + // On some platforms (e.g. Linux), the passed-in timeval is + // updated by select(2). We are not accounting for this + // in our implementation. + start := time.Now() + n, err := _poll([]pollFd{}, dur) + took = time.Since(start) + if err == sys.EINTR { + t.Logf("Select interrupted after %v", took) + continue } + require.EqualErrno(t, 0, err) + require.Equal(t, 0, n) + + // On some platforms the actual timeout might be arbitrarily + // less than requested. + if took < time.Duration(dur)*time.Millisecond { + if runtime.GOOS == "linux" { + // Linux promises to only return early if a file descriptor + // becomes ready (not applicable here), or the call + // is interrupted by a signal handler (explicitly retried in the loop above), + // or the timeout expires. + t.Errorf("Select: slept for %v, expected %v", took, dur) + } else { + t.Logf("Select: slept for %v, requested %v", took, dur) + } + } + return } }) @@ -54,9 +70,16 @@ func Test_poll(t *testing.T) { _, err = ww.Write([]byte("TEST")) require.NoError(t, err) - fds := []pollFd{newPollFd(rr.Fd(), _POLLIN, 0)} - n, err := _poll(fds, 0) - require.EqualErrno(t, 0, err) - require.Equal(t, 1, n) + for { + fds := []pollFd{newPollFd(rr.Fd(), _POLLIN, 0)} + if err == sys.EINTR { + t.Log("Select interrupted") + continue + } + n, err := _poll(fds, 0) + require.EqualErrno(t, 0, err) + require.Equal(t, 1, n) + return + } }) } diff --git a/internal/sysfs/poll_windows_test.go b/internal/sysfs/poll_windows_test.go index d137d6f8b7..46e3e9a224 100644 --- a/internal/sysfs/poll_windows_test.go +++ b/internal/sysfs/poll_windows_test.go @@ -233,10 +233,6 @@ func TestPoll_Windows(t *testing.T) { ch := make(chan result, 1) go pollToChannel(r.Fd(), 200, ch) - // Wait a little, then ensure a message has been written to the channel. - <-time.After(300 * time.Millisecond) - require.Equal(t, 1, len(ch)) - // Ensure that the timer has expired. res := <-ch require.Zero(t, res.err) @@ -249,7 +245,7 @@ func TestPoll_Windows(t *testing.T) { wh := syscall.Handle(w.Fd()) ch := make(chan result, 1) - go pollToChannel(r.Fd(), 600, ch) + go pollToChannel(r.Fd(), 800, ch) <-time.After(300 * time.Millisecond) require.Equal(t, 0, len(ch))