| 253 | } |
| 254 | |
| 255 | PyThread::GilStatus |
| 256 | PyThread::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 " |
nothing calls this directly
no test coverage detected