A new API for ensuring/releasing thread states

Cython uses PyGILState_Ensure all the time to implement with gil: blocks. Because they’re user-written functions we don’t know where they’ll be called from - it’s possible that a “nogil” function may be called:

  • on a thread where no thread state has ever been set up,
  • on a thread that currently holds the GIL (because a “nogil” function only says that it doesn’t need the GIL - it doesn’t require you not to have it),
  • on a thread where the GIL has been held, but has been released by a with nogil: block.

2 and 3 are most common, but all can happen. That’s just a consequence of the fact that we’re generating code in isolation without seeing the full context that it’s used in.

While it’d be possible for us to track some of this internally, Cython functions are generic Python and/or C callables so it’s not possible for Cython alone to track this. It might also have been possible to require the user to pass an existing thread-state down through their call-stack to give to with gil blocks, but adding that now would be a big change.

Where this currently falls down is with sub-interpreters, which hasn’t been a major concern but which we’re just starting to support. We’ll probably have to be slightly less flexible there and require the user to at pass the interpreter state for us though.

We do also treat PyGILState_Ensure and PyGILState_Release as a pair that are always generated together, so I don’t think there are any specific clean-up issues compared to any other API.

1 Like