Skip to content

Commit a7ae4d3

Browse files
committed
prog: remove PROG_RUN retry on EINTR and deprecated RunOptions.Reset option
RunOptions.Reset was primarily added to make resetting testing.B possible in case of EINTR. However, ebpf-go now masks SIGPROF during BPF_PROG_LOAD and BPF_PROG_RUN to prevent the Go profiler from endlessely interrupting the verifier when (continuous) profiling is enabled. Of course, the process can still get signaled by other processes, but this would likely be some form of kill or interrupt signal. In the case of PROG_RUN with a significant Repeat value, this signal should probably be respected and Program.Run shouldn't stubbornly continue on. Signed-off-by: Timo Beckers <timo@isovalent.com>
1 parent 5c94717 commit a7ae4d3

File tree

3 files changed

+16
-65
lines changed

3 files changed

+16
-65
lines changed

prog.go

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -745,11 +745,6 @@ type RunOptions struct {
745745
// CPU to run Program on. Optional field.
746746
// Note not all program types support this field.
747747
CPU uint32
748-
// Called whenever the syscall is interrupted, and should be set to testing.B.ResetTimer
749-
// or similar. Typically used during benchmarking. Optional field.
750-
//
751-
// Deprecated: use [testing.B.ReportMetric] with unit "ns/op" instead.
752-
Reset func()
753748
}
754749

755750
// Test runs the Program in the kernel with the given input and returns the
@@ -802,19 +797,17 @@ func (p *Program) Run(opts *RunOptions) (uint32, error) {
802797
// and returns the time taken per iteration.
803798
//
804799
// Returns the result of the last execution of the program and the time per
805-
// run or an error. reset is called whenever the benchmark syscall is
806-
// interrupted, and should be set to testing.B.ResetTimer or similar.
800+
// run or an error.
807801
//
808802
// This function requires at least Linux 4.12.
809-
func (p *Program) Benchmark(in []byte, repeat int, reset func()) (uint32, time.Duration, error) {
803+
func (p *Program) Benchmark(in []byte, repeat int) (uint32, time.Duration, error) {
810804
if uint(repeat) > math.MaxUint32 {
811805
return 0, 0, fmt.Errorf("repeat is too high")
812806
}
813807

814808
opts := RunOptions{
815809
Data: in,
816810
Repeat: uint32(repeat),
817-
Reset: reset,
818811
}
819812

820813
ret, total, err := p.run(&opts)
@@ -923,40 +916,14 @@ func (p *Program) run(opts *RunOptions) (uint32, time.Duration, error) {
923916
ctxOut = ctxIn
924917
}
925918

926-
retry:
927-
for {
928-
err := sys.ProgRun(&attr)
929-
if err == nil {
930-
break retry
931-
}
932-
933-
if errors.Is(err, unix.EINTR) {
934-
if attr.Repeat <= 1 {
935-
// Older kernels check whether enough repetitions have been
936-
// executed only after checking for pending signals.
937-
//
938-
// run signal? done? run ...
939-
//
940-
// As a result we can get EINTR for repeat==1 even though
941-
// the program was run exactly once. Treat this as a
942-
// successful run instead.
943-
//
944-
// Since commit 607b9cc92bd7 ("bpf: Consolidate shared test timing code")
945-
// the conditions are reversed:
946-
// run done? signal? ...
947-
break retry
948-
}
949-
950-
if opts.Reset != nil {
951-
opts.Reset()
952-
}
953-
continue retry
954-
}
955-
956-
if errors.Is(err, sys.ENOTSUPP) {
957-
return 0, 0, fmt.Errorf("kernel doesn't support running %s: %w", p.Type(), ErrNotSupported)
958-
}
959-
919+
err := sys.ProgRun(&attr)
920+
if errors.Is(err, unix.EINTR) {
921+
return 0, 0, fmt.Errorf("program run interrupted: %w", err)
922+
}
923+
if errors.Is(err, sys.ENOTSUPP) {
924+
return 0, 0, fmt.Errorf("kernel doesn't support running %s: %w", p.Type(), ErrNotSupported)
925+
}
926+
if err != nil {
960927
return 0, 0, err
961928
}
962929

prog_linux_test.go

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@ func TestProgramTestRunInterrupt(t *testing.T) {
4848
opts := RunOptions{
4949
Data: internal.EmptyBPFContext,
5050
Repeat: math.MaxInt32,
51-
Reset: func() {
52-
// We don't know how long finishing the
53-
// test run would take, so flag that we've seen
54-
// an interruption and abort the goroutine.
55-
close(errs)
56-
runtime.Goexit()
57-
},
5851
}
5952
_, _, err := prog.run(&opts)
6053

@@ -63,28 +56,19 @@ func TestProgramTestRunInterrupt(t *testing.T) {
6356

6457
tid := <-tidChan
6558
for {
66-
err := unix.Tgkill(tgid, tid, unix.SIGUSR1)
67-
if err != nil {
68-
t.Fatal("Can't send signal to goroutine thread:", err)
69-
}
59+
qt.Assert(t, qt.IsNil(unix.Tgkill(tgid, tid, unix.SIGUSR1)))
7060

7161
select {
72-
case err, ok := <-errs:
73-
if !ok {
74-
return
75-
}
76-
62+
case err := <-errs:
7763
testutils.SkipIfNotSupported(t, err)
78-
if err == nil {
79-
t.Fatal("testRun wasn't interrupted")
80-
}
81-
82-
t.Fatal("testRun returned an error:", err)
64+
qt.Assert(t, qt.ErrorIs(err, unix.EINTR))
65+
return
8366

8467
case <-timeout:
8568
t.Fatal("Timed out trying to interrupt the goroutine")
8669

8770
default:
71+
time.Sleep(time.Millisecond * 100)
8872
}
8973
}
9074
}

prog_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func TestProgramBenchmark(t *testing.T) {
158158

159159
prog := createBasicProgram(t)
160160

161-
ret, duration, err := prog.Benchmark(internal.EmptyBPFContext, 1, nil)
161+
ret, duration, err := prog.Benchmark(internal.EmptyBPFContext, 1)
162162
testutils.SkipIfNotSupported(t, err)
163163
if err != nil {
164164
t.Fatal("Error from Benchmark:", err)

0 commit comments

Comments
 (0)