Skip to content

Commit

Permalink
sharedlibraries: rework ebpf prog concurrency (DataDog#31745)
Browse files Browse the repository at this point in the history
  • Loading branch information
guyarb authored Dec 4, 2024
1 parent f5222fe commit 03b83e1
Showing 1 changed file with 23 additions and 17 deletions.
40 changes: 23 additions & 17 deletions pkg/network/usm/sharedlibraries/ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import (
"strings"
"sync"

"go.uber.org/atomic"

manager "github.com/DataDog/ebpf-manager"
"golang.org/x/sys/unix"

Expand All @@ -40,10 +38,12 @@ const (
openat2SysCall = "openat2"
)

var traceTypes = []string{"enter", "exit"}
var (
singletonMutex = sync.Mutex{}
progSingleton *EbpfProgram

var progSingletonOnce sync.Once
var progSingleton *EbpfProgram
traceTypes = []string{"enter", "exit"}
)

// LibraryCallback defines the type of the callback function that will be called when a shared library event is detected
type LibraryCallback func(LibPath)
Expand Down Expand Up @@ -93,7 +93,7 @@ type EbpfProgram struct {

// refcount is the number of times the program has been initialized. It is used to
// stop the program only when the refcount reaches 0.
refcount atomic.Int32
refcount uint16

// initMutex is a mutex to protect the initialization variables and the libset map
wg sync.WaitGroup
Expand Down Expand Up @@ -127,7 +127,10 @@ func IsSupported(cfg *ddebpf.Config) bool {

// GetEBPFProgram returns an instance of the shared libraries eBPF program singleton
func GetEBPFProgram(cfg *ddebpf.Config) *EbpfProgram {
progSingletonOnce.Do(func() {
singletonMutex.Lock()
defer singletonMutex.Unlock()

if progSingleton == nil {
progSingleton = &EbpfProgram{
cfg: cfg,
libsets: make(map[Libset]*libsetHandler),
Expand All @@ -140,8 +143,9 @@ func GetEBPFProgram(cfg *ddebpf.Config) *EbpfProgram {
callbacks: make(map[*LibraryCallback]struct{}),
}
}
})
progSingleton.refcount.Inc()
}

progSingleton.refcount++

return progSingleton
}
Expand Down Expand Up @@ -438,21 +442,23 @@ func (e *EbpfProgram) Subscribe(callback LibraryCallback, libsets ...Libset) (fu

// Stop stops the eBPF program if the refcount reaches 0
func (e *EbpfProgram) Stop() {
if e.refcount.Dec() != 0 {
if e.refcount.Load() < 0 {
e.refcount.Swap(0)
}
singletonMutex.Lock()
defer singletonMutex.Unlock()

if e.refcount == 0 {
log.Warn("shared libraries monitor stopping with a refcount of 0")
return
}
e.refcount--
if e.refcount > 0 {
// Still in use
return
}

// At this point any operations are thread safe, as we're using atomics
// so it's guaranteed only one thread can reach this point with refcount == 0
log.Info("shared libraries monitor stopping due to a refcount of 0")

e.stopImpl()

// Reset the program singleton in case it's used again (e.g. in tests)
progSingletonOnce = sync.Once{}
progSingleton = nil
}

Expand Down

0 comments on commit 03b83e1

Please sign in to comment.