| // 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) |