@@ -1749,42 +1749,53 @@ void print(Args &&...args) {
1749
1749
* example which uses features 2 and 3 to migrate the Python thread of
1750
1750
* execution to another thread (to run the event loop on the original thread,
1751
1751
* in this case).
1752
+ *
1753
+ * Due to the fact that gil_scoped_acquire creates its own internal thread
1754
+ * state, this can get out of sync with the PyGILState_* API's thread state,
1755
+ * causing GIL deadlocks in complicated setups with third party code that
1756
+ * calls the PyGILState_* functions. To force gil_scoped_acquire to use the
1757
+ * PyGILState_* API, create a pybind11::options object and call
1758
+ * options::enable_use_gilstate().
1752
1759
*/
1753
1760
1754
1761
class gil_scoped_acquire {
1755
1762
public:
1756
1763
PYBIND11_NOINLINE gil_scoped_acquire () {
1757
- auto const &internals = detail::get_internals ();
1758
- tstate = (PyThreadState *) PyThread_get_key_value (internals.tstate );
1759
-
1760
- if (!tstate) {
1761
- tstate = PyThreadState_New (internals.istate );
1762
- #if !defined(NDEBUG)
1763
- if (!tstate)
1764
- pybind11_fail (" scoped_acquire: could not create thread state!" );
1765
- #endif
1766
- tstate->gilstate_counter = 0 ;
1767
- #if PY_MAJOR_VERSION < 3
1768
- PyThread_delete_key_value (internals.tstate );
1769
- #endif
1770
- PyThread_set_key_value (internals.tstate , tstate);
1764
+ if (options::use_gilstate ()) {
1765
+ state = PyGILState_Ensure ();
1771
1766
} else {
1772
- release = detail::get_thread_state_unchecked () != tstate ;
1773
- }
1767
+ auto const &internals = detail::get_internals () ;
1768
+ tstate = (PyThreadState *) PyThread_get_key_value (internals. tstate );
1774
1769
1775
- if (release) {
1776
- /* Work around an annoying assertion in PyThreadState_Swap */
1777
- #if defined(Py_DEBUG)
1778
- PyInterpreterState *interp = tstate->interp ;
1779
- tstate->interp = nullptr ;
1780
- #endif
1781
- PyEval_AcquireThread (tstate);
1782
- #if defined(Py_DEBUG)
1783
- tstate->interp = interp;
1784
- #endif
1785
- }
1770
+ if (!tstate) {
1771
+ tstate = PyThreadState_New (internals.istate );
1772
+ #if !defined(NDEBUG)
1773
+ if (!tstate)
1774
+ pybind11_fail (" scoped_acquire: could not create thread state!" );
1775
+ #endif
1776
+ tstate->gilstate_counter = 0 ;
1777
+ #if PY_MAJOR_VERSION < 3
1778
+ PyThread_delete_key_value (internals.tstate );
1779
+ #endif
1780
+ PyThread_set_key_value (internals.tstate , tstate);
1781
+ } else {
1782
+ release = detail::get_thread_state_unchecked () != tstate;
1783
+ }
1786
1784
1787
- inc_ref ();
1785
+ if (release) {
1786
+ /* Work around an annoying assertion in PyThreadState_Swap */
1787
+ #if defined(Py_DEBUG)
1788
+ PyInterpreterState *interp = tstate->interp ;
1789
+ tstate->interp = nullptr ;
1790
+ #endif
1791
+ PyEval_AcquireThread (tstate);
1792
+ #if defined(Py_DEBUG)
1793
+ tstate->interp = interp;
1794
+ #endif
1795
+ }
1796
+
1797
+ inc_ref ();
1798
+ }
1788
1799
}
1789
1800
1790
1801
void inc_ref () {
@@ -1812,12 +1823,17 @@ class gil_scoped_acquire {
1812
1823
}
1813
1824
1814
1825
PYBIND11_NOINLINE ~gil_scoped_acquire () {
1815
- dec_ref ();
1816
- if (release)
1817
- PyEval_SaveThread ();
1826
+ if (options::use_gilstate ()) {
1827
+ PyGILState_Release (state);
1828
+ } else {
1829
+ dec_ref ();
1830
+ if (release)
1831
+ PyEval_SaveThread ();
1832
+ }
1818
1833
}
1819
1834
private:
1820
1835
PyThreadState *tstate = nullptr ;
1836
+ PyGILState_STATE state;
1821
1837
bool release = true ;
1822
1838
};
1823
1839
0 commit comments