fix: proper gil handling, increase testing for symbols & complex numbers - #401
fix: proper gil handling, increase testing for symbols & complex numbers#401b-long wants to merge 2 commits into
Conversation
|
Had a look. The argument side looks right to me, the tuple side I would drop, and there is a third window neither PR touches that I think is the better target. Everything below is against #399 head ( The argument side is right. Hoisting the And to confirm what you found: reverting d41db33 on top of this cannot work. One nit. The premarshal variable is declared in a new loop over The tuple side: I would drop it. _gstate := C.PyGILState_Ensure() // 1086
...
<buildTuple output spliced here> // 1110
C.PyObject_CallObject(_fun_arg, _fcargs) // 1111
C.gopy_decref(_fcargs) // 1112
C.gopy_err_handle() // 1117
C.PyGILState_Release(_gstate) // 1118So the new inner As future-proofing it also does not do what the comment says. The tuple is created inside the new bracket and used outside it:
If you want that contract enforced rather than conventional, the way to get it is to emit the whole Minor, separate from the GIL question: wrapping the body in Where the live GIL-less window actually isStill in C.PyGILState_Release(_gstate) // 1118
...
return C.GoString(C.PyBytes_AsString(_fcret)) // via pyObjectToGo, 1120-1124so While in there: The stress testWell aimed. The churn thread can only run while the main thread has released the GIL, which is exactly gopy's |
Convert Python-side arguments whose marshalling touches a raw *C.PyObject (complex64/complex128, via needsGILForArgMarshal) before releasing the GIL for the wrapped Go call, instead of inline afterward once it has already been released. Self-bracket buildTuple's PyTuple_New/PyTuple_SetItem output with PyGILState_Ensure/Release so it does not rely on its caller already holding the GIL. Adds a complex64/128 round-trip stress test that hammers the fix from a churn thread, and TestBuildTupleHoldsGIL.
addSignatureType released the GIL before converting the *C.PyObject return value from an invoked Python callback back to Go (e.g. via PyLong_AsLongLong/PyBytes_AsString) and never decref'd it. Both now happen before PyGILState_Release, closing a live GIL-less window (hit by any callback with a return value, e.g. _examples/funcs' CallBackRval) and a one-object-per-call leak. Drop buildTuple's self-bracketing GIL, added in the previous commit: its only caller (addSignatureType) already holds the GIL across the whole build/call/decref region, so the extra Ensure/Release was redundant. Replace TestBuildTupleHoldsGIL, which only checked the tuple-build fragment and could pass in the broken case, with a test on addSignatureType's full output. Extract argCallExpr as the single function deciding both an argument's call-site expression and whether it needs GIL premarshalling, so a premarshalled variable can no longer be declared without also being the expression consumed at the call site. Trim the complex stress test from 20000 to 500 iterations; the pre-fix crash is deterministic on the first call.
f8d6795 to
e24deba
Compare
|
Thank you again for the review and collaboration, @satarsa! 🙇 Good catch on the tuple side — you were totally right. That GIL-less window you flagged in For the gen_func.go nit, instead of just reordering the switch, I moved the logic for picking the expression (and whether it needs the GIL) into Also trimmed the stress test down from 20,000 iterations to 500 — good point that the crash is deterministic on the first call anyway. Everything's updated in e24deba. I squashed the branch down to two commits: ec3b50c is the state from your original review, and e24deba includes all the updates above (so the old comment thread will show as outdated against the new diff). |
This PR stacks on top of: #399
Specifically, this PR was motivated by feedback from @satarsa (see PR 399 feedback).