@@ -9,27 +9,26 @@ import "C"
99import (
1010 "fmt"
1111 "sync"
12- "sync/atomic"
1312 "syscall"
14- "unsafe"
1513)
1614
1715//
1816// RingBuffer
1917//
2018
2119type RingBuffer struct {
22- rb * C.struct_ring_buffer
23- bpfMap * BPFMap
24- slots []uint
25- closed bool
26- wg sync. WaitGroup
27- stopFlag uint32 // use with atomic operations
20+ rb * C.struct_ring_buffer
21+ bpfMap * BPFMap
22+ slots []uint
23+ stop chan struct {}
24+ closed bool
25+ wg sync. WaitGroup
2826}
2927
3028// Poll will wait until timeout in milliseconds to gather
3129// data from the ring buffer.
3230func (rb * RingBuffer ) Poll (timeout int ) {
31+ rb .stop = make (chan struct {})
3332 rb .wg .Add (1 )
3433 go rb .poll (timeout )
3534}
@@ -40,12 +39,12 @@ func (rb *RingBuffer) Start() {
4039}
4140
4241func (rb * RingBuffer ) Stop () {
43- if atomic . LoadUint32 ( & rb .stopFlag ) == 1 {
42+ if rb .stop == nil {
4443 return
4544 }
4645
4746 // Signal the poll goroutine to exit
48- atomic . StoreUint32 ( & rb .stopFlag , 1 )
47+ close ( rb .stop )
4948
5049 // The event channel should be drained here since the consumer
5150 // may have stopped at this point. Failure to drain it will
@@ -70,6 +69,9 @@ func (rb *RingBuffer) Stop() {
7069 eventChan := eventChannels .get (slot ).(chan []byte )
7170 close (eventChan )
7271 }
72+
73+ // Reset pb.stop to allow multiple safe calls to Stop()
74+ rb .stop = nil
7375}
7476
7577func (rb * RingBuffer ) Close () {
@@ -85,13 +87,32 @@ func (rb *RingBuffer) Close() {
8587 rb .closed = true
8688}
8789
90+ func (rb * RingBuffer ) isStopped () bool {
91+ select {
92+ case <- rb .stop :
93+ return true
94+ default :
95+ return false
96+ }
97+ }
98+
8899func (rb * RingBuffer ) poll (timeout int ) error {
89100 defer rb .wg .Done ()
90101
91- stopFlag := (* C .uint32_t )(unsafe .Pointer (& rb .stopFlag ))
92- ret := C .cgo_ring_buffer__poll (rb .rb , C .int (timeout ), stopFlag )
93- if ret < 0 {
94- return fmt .Errorf ("error polling perf buffer: %w" , syscall .Errno (- ret ))
102+ for {
103+ retC := C .ring_buffer__poll (rb .rb , C .int (timeout ))
104+ if rb .isStopped () {
105+ break
106+ }
107+
108+ if retC < 0 {
109+ errno := syscall .Errno (- retC )
110+ if errno == syscall .EINTR {
111+ continue
112+ }
113+
114+ return fmt .Errorf ("error polling ring buffer: %w" , errno )
115+ }
95116 }
96117
97118 return nil
0 commit comments