Skip to content

Commit 401409d

Browse files
committed
don't dealloc PyMethodDef object until cleaning
1 parent 3dcb02e commit 401409d

File tree

3 files changed

+41
-26
lines changed

3 files changed

+41
-26
lines changed

extension.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ type slotMeta struct {
5050
hasRecv bool // whether it has a receiver
5151
index int // used for member type
5252
typ reflect.Type // member/method type
53+
def *C.PyMethodDef
5354
}
5455

5556
type typeMeta struct {
@@ -627,25 +628,27 @@ func (m Module) AddMethod(name string, fn any, doc string) Func {
627628
}
628629

629630
methodId := uint(len(meta.methods))
630-
meta.methods[methodId] = &slotMeta{
631+
632+
methodPtr := C.wrapperMethods[methodId]
633+
cName := C.CString(name)
634+
cDoc := C.CString(doc)
635+
636+
def := (*C.PyMethodDef)(C.malloc(C.size_t(unsafe.Sizeof(C.PyMethodDef{}))))
637+
def.ml_name = cName
638+
def.ml_meth = C.PyCFunction(methodPtr)
639+
def.ml_flags = C.METH_VARARGS
640+
def.ml_doc = cDoc
641+
642+
methodMeta := &slotMeta{
631643
name: name,
632644
methodName: name,
633645
fn: fn,
634646
typ: t,
635647
doc: doc,
636648
hasRecv: false,
649+
def: def,
637650
}
638-
639-
methodPtr := C.wrapperMethods[methodId]
640-
cName := C.CString(name)
641-
cDoc := C.CString(doc)
642-
643-
def := &C.PyMethodDef{
644-
ml_name: cName,
645-
ml_meth: C.PyCFunction(methodPtr),
646-
ml_flags: C.METH_VARARGS,
647-
ml_doc: cDoc,
648-
}
651+
meta.methods[methodId] = methodMeta
649652

650653
pyFunc := C.PyCFunction_NewEx(def, m.obj, m.obj)
651654
if pyFunc == nil {

global_data.go

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"reflect"
1010
"sync"
1111
"sync/atomic"
12+
"unsafe"
1213
)
1314

1415
// ----------------------------------------------------------------------------
@@ -51,11 +52,15 @@ func (l *decRefList) add(obj *C.PyObject) {
5152
l.mu.Unlock()
5253
}
5354

54-
func (l *decRefList) decRefAll() {
55-
var list []*C.PyObject
55+
func (l *decRefList) len() int {
56+
l.mu.Lock()
57+
defer l.mu.Unlock()
58+
return len(l.objects)
59+
}
5660

61+
func (l *decRefList) decRefAll() {
5762
l.mu.Lock()
58-
list = l.objects
63+
list := l.objects
5964
l.objects = make([]*C.PyObject, 0, maxPyObjects*2)
6065
l.mu.Unlock()
6166

@@ -67,12 +72,11 @@ func (l *decRefList) decRefAll() {
6772
// ----------------------------------------------------------------------------
6873

6974
type globalData struct {
70-
typeMetas map[*C.PyObject]*typeMeta
71-
pyTypes map[reflect.Type]*C.PyObject
72-
holders holderList
73-
decRefList decRefList
74-
disableDecRef bool
75-
finished int32
75+
typeMetas map[*C.PyObject]*typeMeta
76+
pyTypes map[reflect.Type]*C.PyObject
77+
holders holderList
78+
decRefList decRefList
79+
finished int32
7680
}
7781

7882
var (
@@ -84,17 +88,16 @@ func getGlobalData() *globalData {
8488
}
8589

8690
func (gd *globalData) addDecRef(obj *C.PyObject) {
87-
if gd.disableDecRef {
88-
return
89-
}
9091
if atomic.LoadInt32(&gd.finished) != 0 {
9192
return
9293
}
9394
gd.decRefList.add(obj)
9495
}
9596

9697
func (gd *globalData) decRefObjectsIfNeeded() {
97-
gd.decRefList.decRefAll()
98+
if gd.decRefList.len() >= maxPyObjects {
99+
gd.decRefList.decRefAll()
100+
}
98101
}
99102

100103
// ----------------------------------------------------------------------------
@@ -111,5 +114,15 @@ func markFinished() {
111114
}
112115

113116
func cleanupGlobal() {
117+
for _, meta := range global.typeMetas {
118+
for _, method := range meta.methods {
119+
def := method.def
120+
if def != nil {
121+
C.free(unsafe.Pointer(def.ml_name))
122+
C.free(unsafe.Pointer(def.ml_doc))
123+
C.free(unsafe.Pointer(def))
124+
}
125+
}
126+
}
114127
global = nil
115128
}

python_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ func setupTest(t *testing.T) {
1414
testMutex.Lock()
1515
Initialize()
1616
// TODO: Remove this once we solve random segfaults
17-
getGlobalData().disableDecRef = true
1817
t.Cleanup(func() {
1918
runtime.GC()
2019
Finalize()

0 commit comments

Comments
 (0)