diff --git a/perf/reader.go b/perf/reader.go index 05ad5ef22..0b46f8fc2 100644 --- a/perf/reader.go +++ b/perf/reader.go @@ -357,7 +357,7 @@ func (pr *Reader) ReadInto(rec *Record) error { pr.pauseMu.Unlock() _, err := pr.poller.Wait(events, pr.deadline) pr.pauseMu.Lock() - if err != nil { + if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) { return err } @@ -374,6 +374,11 @@ func (pr *Reader) ReadInto(rec *Record) error { pr.epollRings = append(pr.epollRings, ring) } } + + if len(pr.epollRings) == 0 { + // Woken up but no data, deadline exceeded. + return fmt.Errorf("read: %w", os.ErrDeadlineExceeded) + } } // Start at the last available event. The order in which we diff --git a/perf/reader_test.go b/perf/reader_test.go index bb2988ac4..f2421fd55 100644 --- a/perf/reader_test.go +++ b/perf/reader_test.go @@ -531,6 +531,27 @@ func TestPerfReaderWakeupEvents(t *testing.T) { } } +func TestReadWithoutWakeup(t *testing.T) { + t.Parallel() + + events := perfEventArray(t) + + rd, err := NewReaderWithOptions(events, 1, ReaderOptions{WakeupEvents: 2}) + if err != nil { + t.Fatal(err) + } + defer rd.Close() + + prog := outputSamplesProg(t, events, 5) + ret, _, err := prog.Test(internal.EmptyBPFContext) + testutils.SkipIfNotSupported(t, err) + qt.Assert(t, qt.IsNil(err)) + qt.Assert(t, qt.Equals(ret, 0)) + + rd.SetDeadline(time.Now()) + checkRecord(t, rd) +} + func BenchmarkReader(b *testing.B) { events := perfEventArray(b) prog := outputSamplesProg(b, events, 80)