fix(core): take over agent, reuse callbacks
- Kill running agents before replace - Retry copy with backoff while locked - Reuse syscall callbacks at package scope - Add callback regression test
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Go never frees syscall.NewCallback (hard cap ~2000). Creating one per
|
||||
// screenshot frame is a fatal "too many callback functions".
|
||||
func TestNewCallbackOnlyAtPackageScope(t *testing.T) {
|
||||
root := filepath.Join("..", "..")
|
||||
fset := token.NewFileSet()
|
||||
err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
name := d.Name()
|
||||
if name == ".git" || name == "vendor" || name == "testdata" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !strings.HasSuffix(path, ".go") {
|
||||
return nil
|
||||
}
|
||||
file, err := parser.ParseFile(fset, path, nil, 0)
|
||||
if err != nil {
|
||||
t.Errorf("parse %s: %v", path, err)
|
||||
return nil
|
||||
}
|
||||
for _, decl := range file.Decls {
|
||||
fn, ok := decl.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
ast.Inspect(fn, func(n ast.Node) bool {
|
||||
if !isNewCallbackCall(n) {
|
||||
return true
|
||||
}
|
||||
name := fn.Name.Name
|
||||
if fn.Recv != nil {
|
||||
name = "method " + name
|
||||
}
|
||||
t.Errorf("%s: syscall.NewCallback inside %s; Go never frees these (cap ~2000)", fset.Position(n.Pos()), name)
|
||||
return true
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func isNewCallbackCall(n ast.Node) bool {
|
||||
call, ok := n.(*ast.CallExpr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
sel, ok := call.Fun.(*ast.SelectorExpr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
switch sel.Sel.Name {
|
||||
case "NewCallback", "NewCallbackCDecl":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user