1 | /* |
2 | pybind11/gil.h: RAII helpers for managing the GIL |
3 | |
4 | Copyright (c) 2016 Wenzel Jakob <[email protected]> |
5 | |
6 | All rights reserved. Use of this source code is governed by a |
7 | BSD-style license that can be found in the LICENSE file. |
8 | */ |
9 | |
10 | #pragma once |
11 | |
12 | #include "detail/common.h" |
13 | |
14 | #if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) |
15 | # include "detail/internals.h" |
16 | #endif |
17 | |
18 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) |
19 | |
20 | PYBIND11_NAMESPACE_BEGIN(detail) |
21 | |
22 | // forward declarations |
23 | PyThreadState *get_thread_state_unchecked(); |
24 | |
25 | PYBIND11_NAMESPACE_END(detail) |
26 | |
27 | #if defined(WITH_THREAD) |
28 | |
29 | # if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) |
30 | |
31 | /* The functions below essentially reproduce the PyGILState_* API using a RAII |
32 | * pattern, but there are a few important differences: |
33 | * |
34 | * 1. When acquiring the GIL from an non-main thread during the finalization |
35 | * phase, the GILState API blindly terminates the calling thread, which |
36 | * is often not what is wanted. This API does not do this. |
37 | * |
38 | * 2. The gil_scoped_release function can optionally cut the relationship |
39 | * of a PyThreadState and its associated thread, which allows moving it to |
40 | * another thread (this is a fairly rare/advanced use case). |
41 | * |
42 | * 3. The reference count of an acquired thread state can be controlled. This |
43 | * can be handy to prevent cases where callbacks issued from an external |
44 | * thread would otherwise constantly construct and destroy thread state data |
45 | * structures. |
46 | * |
47 | * See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an |
48 | * example which uses features 2 and 3 to migrate the Python thread of |
49 | * execution to another thread (to run the event loop on the original thread, |
50 | * in this case). |
51 | */ |
52 | |
53 | class gil_scoped_acquire { |
54 | public: |
55 | PYBIND11_NOINLINE gil_scoped_acquire() { |
56 | auto &internals = detail::get_internals(); |
57 | tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate); |
58 | |
59 | if (!tstate) { |
60 | /* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if |
61 | calling from a Python thread). Since we use a different key, this ensures |
62 | we don't create a new thread state and deadlock in PyEval_AcquireThread |
63 | below. Note we don't save this state with internals.tstate, since we don't |
64 | create it we would fail to clear it (its reference count should be > 0). */ |
65 | tstate = PyGILState_GetThisThreadState(); |
66 | } |
67 | |
68 | if (!tstate) { |
69 | tstate = PyThreadState_New(internals.istate); |
70 | # if defined(PYBIND11_DETAILED_ERROR_MESSAGES) |
71 | if (!tstate) { |
72 | pybind11_fail("scoped_acquire: could not create thread state!" ); |
73 | } |
74 | # endif |
75 | tstate->gilstate_counter = 0; |
76 | PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate); |
77 | } else { |
78 | release = detail::get_thread_state_unchecked() != tstate; |
79 | } |
80 | |
81 | if (release) { |
82 | PyEval_AcquireThread(tstate); |
83 | } |
84 | |
85 | inc_ref(); |
86 | } |
87 | |
88 | gil_scoped_acquire(const gil_scoped_acquire &) = delete; |
89 | gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; |
90 | |
91 | void inc_ref() { ++tstate->gilstate_counter; } |
92 | |
93 | PYBIND11_NOINLINE void dec_ref() { |
94 | --tstate->gilstate_counter; |
95 | # if defined(PYBIND11_DETAILED_ERROR_MESSAGES) |
96 | if (detail::get_thread_state_unchecked() != tstate) { |
97 | pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!" ); |
98 | } |
99 | if (tstate->gilstate_counter < 0) { |
100 | pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!" ); |
101 | } |
102 | # endif |
103 | if (tstate->gilstate_counter == 0) { |
104 | # if defined(PYBIND11_DETAILED_ERROR_MESSAGES) |
105 | if (!release) { |
106 | pybind11_fail("scoped_acquire::dec_ref(): internal error!" ); |
107 | } |
108 | # endif |
109 | PyThreadState_Clear(tstate); |
110 | if (active) { |
111 | PyThreadState_DeleteCurrent(); |
112 | } |
113 | PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate); |
114 | release = false; |
115 | } |
116 | } |
117 | |
118 | /// This method will disable the PyThreadState_DeleteCurrent call and the |
119 | /// GIL won't be acquired. This method should be used if the interpreter |
120 | /// could be shutting down when this is called, as thread deletion is not |
121 | /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and |
122 | /// protect subsequent code. |
123 | PYBIND11_NOINLINE void disarm() { active = false; } |
124 | |
125 | PYBIND11_NOINLINE ~gil_scoped_acquire() { |
126 | dec_ref(); |
127 | if (release) { |
128 | PyEval_SaveThread(); |
129 | } |
130 | } |
131 | |
132 | private: |
133 | PyThreadState *tstate = nullptr; |
134 | bool release = true; |
135 | bool active = true; |
136 | }; |
137 | |
138 | class gil_scoped_release { |
139 | public: |
140 | explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) { |
141 | // `get_internals()` must be called here unconditionally in order to initialize |
142 | // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an |
143 | // initialization race could occur as multiple threads try `gil_scoped_acquire`. |
144 | auto &internals = detail::get_internals(); |
145 | // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) |
146 | tstate = PyEval_SaveThread(); |
147 | if (disassoc) { |
148 | // Python >= 3.7 can remove this, it's an int before 3.7 |
149 | // NOLINTNEXTLINE(readability-qualified-auto) |
150 | auto key = internals.tstate; |
151 | PYBIND11_TLS_DELETE_VALUE(key); |
152 | } |
153 | } |
154 | |
155 | gil_scoped_release(const gil_scoped_acquire &) = delete; |
156 | gil_scoped_release &operator=(const gil_scoped_acquire &) = delete; |
157 | |
158 | /// This method will disable the PyThreadState_DeleteCurrent call and the |
159 | /// GIL won't be acquired. This method should be used if the interpreter |
160 | /// could be shutting down when this is called, as thread deletion is not |
161 | /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and |
162 | /// protect subsequent code. |
163 | PYBIND11_NOINLINE void disarm() { active = false; } |
164 | |
165 | ~gil_scoped_release() { |
166 | if (!tstate) { |
167 | return; |
168 | } |
169 | // `PyEval_RestoreThread()` should not be called if runtime is finalizing |
170 | if (active) { |
171 | PyEval_RestoreThread(tstate); |
172 | } |
173 | if (disassoc) { |
174 | // Python >= 3.7 can remove this, it's an int before 3.7 |
175 | // NOLINTNEXTLINE(readability-qualified-auto) |
176 | auto key = detail::get_internals().tstate; |
177 | PYBIND11_TLS_REPLACE_VALUE(key, tstate); |
178 | } |
179 | } |
180 | |
181 | private: |
182 | PyThreadState *tstate; |
183 | bool disassoc; |
184 | bool active = true; |
185 | }; |
186 | |
187 | # else // PYBIND11_SIMPLE_GIL_MANAGEMENT |
188 | |
189 | class gil_scoped_acquire { |
190 | PyGILState_STATE state; |
191 | |
192 | public: |
193 | gil_scoped_acquire() : state{PyGILState_Ensure()} {} |
194 | gil_scoped_acquire(const gil_scoped_acquire &) = delete; |
195 | gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; |
196 | ~gil_scoped_acquire() { PyGILState_Release(state); } |
197 | void disarm() {} |
198 | }; |
199 | |
200 | class gil_scoped_release { |
201 | PyThreadState *state; |
202 | |
203 | public: |
204 | gil_scoped_release() : state{PyEval_SaveThread()} {} |
205 | gil_scoped_release(const gil_scoped_release &) = delete; |
206 | gil_scoped_release &operator=(const gil_scoped_acquire &) = delete; |
207 | ~gil_scoped_release() { PyEval_RestoreThread(state); } |
208 | void disarm() {} |
209 | }; |
210 | |
211 | # endif // PYBIND11_SIMPLE_GIL_MANAGEMENT |
212 | |
213 | #else // WITH_THREAD |
214 | |
215 | class gil_scoped_acquire { |
216 | public: |
217 | gil_scoped_acquire() { |
218 | // Trick to suppress `unused variable` error messages (at call sites). |
219 | (void) (this != (this + 1)); |
220 | } |
221 | gil_scoped_acquire(const gil_scoped_acquire &) = delete; |
222 | gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; |
223 | void disarm() {} |
224 | }; |
225 | |
226 | class gil_scoped_release { |
227 | public: |
228 | gil_scoped_release() { |
229 | // Trick to suppress `unused variable` error messages (at call sites). |
230 | (void) (this != (this + 1)); |
231 | } |
232 | gil_scoped_release(const gil_scoped_release &) = delete; |
233 | gil_scoped_release &operator=(const gil_scoped_acquire &) = delete; |
234 | void disarm() {} |
235 | }; |
236 | |
237 | #endif // WITH_THREAD |
238 | |
239 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) |
240 | |