MCPcopy Create free account
hub / github.com/bloomberg/pystack / calculateGilStatus

Method calculateGilStatus

src/pystack/_pystack/pythread.cpp:255–325  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

253}
254
255PyThread::GilStatus
256PyThread::calculateGilStatus(
257 Structure<py_thread_v>& ts,
258 const std::shared_ptr<const AbstractProcessManager>& manager) const
259{
260 LOG(DEBUG) << "Attempting to determine GIL Status";
261 remote_addr_t thread_addr;
262 remote_addr_t pyruntime = manager->findSymbol("_PyRuntime");
263 if (pyruntime) {
264 assert(manager->versionIsAtLeast(3, 0));
265 LOG(DEBUG) << "_PyRuntime symbol detected. Searching for GIL status within _PyRuntime structure";
266
267 if (manager->versionIsAtLeast(3, 12)) {
268 // Fast, exact method supporting per-interpreter GILs:
269 // The thread state points to an interpreter state, which contains
270 // a ceval state, which points to a GIL runtime state.
271 // If that GIL state has `locked` set and `last_holder` is d_addr,
272 // then the thread represented by this PyThread holds the GIL.
273 auto is_addr = ts.getField(&py_thread_v::o_interp);
274 Structure<py_is_v> interp(manager, is_addr);
275
276 auto gil_addr = interp.getField(&py_is_v::o_gil_runtime_state);
277 Structure<py_gilruntimestate_v> gil(manager, gil_addr);
278
279 auto locked = gil.getField(&py_gilruntimestate_v::o_locked);
280 auto holder = gil.getField(&py_gilruntimestate_v::o_last_holder);
281 return (locked && holder == d_addr ? GilStatus::HELD : GilStatus::NOT_HELD);
282 } else if (manager->versionIsAtLeast(3, 8)) {
283 // Fast, exact method by checking the gilstate structure in _PyRuntime
284 LOG(DEBUG) << "Searching for the GIL by checking the value of 'tstate_current'";
285 Structure<py_runtime_v> runtime(manager, pyruntime);
286 uintptr_t tstate_current = runtime.getField(&py_runtime_v::o_tstate_current);
287 return (tstate_current == d_addr ? GilStatus::HELD : GilStatus::NOT_HELD);
288 } else {
289 LOG(DEBUG) << "Searching for the GIL by scanning the _PyRuntime structure";
290 // Slow, potentially unreliable method for older versions.
291 // The thread object that has the GIL is stored twice at some unknown
292 // offsets in the _PyRuntime structure. In order to determine if a given
293 // thread has the GIL, we scan the _PyRuntime struct and check if the
294 // address of the given thread object is present twice in the _PyRuntime
295 // struct.
296 int hits = 0;
297 static const size_t MAX_RUNTIME_OFFSET = 2048;
298 for (void** raddr = (void**)pyruntime;
299 (void*)raddr < (void*)(pyruntime + MAX_RUNTIME_OFFSET);
300 raddr++)
301 {
302 manager->copyObjectFromProcess((remote_addr_t)raddr, &thread_addr);
303 if (thread_addr == d_addr && ++hits == 2) {
304 LOG(DEBUG) << "GIL status correctly determined: HELD";
305 return GilStatus::HELD;
306 }
307 }
308 LOG(DEBUG) << "GIL status correctly determined: NOT HELD";
309 return GilStatus::NOT_HELD;
310 }
311 } else {
312 LOG(DEBUG) << "_PyRuntime symbol not detected. Searching for GIL status using "

Callers

nothing calls this directly

Calls 4

LOGClass · 0.85
findSymbolMethod · 0.80
versionIsAtLeastMethod · 0.80
copyObjectFromProcessMethod · 0.80

Tested by

no test coverage detected