// Copyright (c) 2016-2025 The Pybind Development Team. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #pragma once #include "pytypes.h" PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) /// This does not do anything if there's a GIL. On free-threaded Python, /// it locks an object. This uses the CPython API, which has limits class scoped_critical_section { public: #ifdef Py_GIL_DISABLED explicit scoped_critical_section(handle obj1, handle obj2 = handle{}) { if (obj1) { if (obj2) { PyCriticalSection2_Begin(§ion2, obj1.ptr(), obj2.ptr()); rank = 2; } else { PyCriticalSection_Begin(§ion, obj1.ptr()); rank = 1; } } else if (obj2) { PyCriticalSection_Begin(§ion, obj2.ptr()); rank = 1; } } ~scoped_critical_section() { if (rank == 1) { PyCriticalSection_End(§ion); } else if (rank == 2) { PyCriticalSection2_End(§ion2); } } #else explicit scoped_critical_section(handle, handle = handle{}) {}; ~scoped_critical_section() = default; #endif scoped_critical_section(const scoped_critical_section &) = delete; scoped_critical_section &operator=(const scoped_critical_section &) = delete; private: #ifdef Py_GIL_DISABLED int rank{0}; union { PyCriticalSection section; PyCriticalSection2 section2; }; #endif }; PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)