You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Binder: withGIL on a JVM virtual thread can release the GIL from another carrier #161
Read from the source, not observed in a run. withGIL keeps its nesting depth in a Java ThreadLocal (jvmMain GILScope.jvm.kt), which belongs to the virtual thread, while PyGILState binds the thread state to the OS thread (the carrier). A virtual thread that parks inside withGIL (lock, sleep, blocking I/O) unmounts while its carrier holds the GIL; another virtual thread on that carrier sees depth 0 and re-enters PyGILState_Ensure, and the first may later call PyGILState_Release on a different carrier: interpreter corruption, or deadlock under the GIL.
No code runs Python on virtual threads today. pythonx-concurrent SPEC S7.8 to S7.12 (Kotlin mode) needs it; its binder requests 13 and 14.
Request: on a virtual thread, run the outermost withGIL block under a native frame so the virtual thread stays pinned, or refuse to enter it there. Desktop only.
Completion: a test that parks inside withGIL on a virtual thread and records the OS thread id at Ensure and at Release (they must match, or the entry is refused), red before the change.
Option B landed in develop via #337 (withGIL/withPython crossinline; the outermost scope on a JVM virtual thread runs pinned to its carrier through a native frame). Replaces option A's refusal from #303.
Activity
Merge pull request #303 from thisisthepy/feat/pmp-vthread-gil
b-re-w commentedon Oct 25, 2026
Landed in develop via #303 (option A). Option B (pinning, crossinline API change) awaits a user decision; noted on #164.
Merge pull request #337 from thisisthepy/feat/withgil-crossinline-pinned
b-re-w commentedon Oct 25, 2026
Option B landed in develop via #337 (withGIL/withPython crossinline; the outermost scope on a JVM virtual thread runs pinned to its carrier through a native frame). Replaces option A's refusal from #303.