|
||||
Warning, file /include/pybind11/gil_safe_call_once.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 // Copyright (c) 2023 The pybind Community. 0002 0003 #pragma once 0004 0005 #include "detail/common.h" 0006 #include "gil.h" 0007 0008 #include <cassert> 0009 #include <mutex> 0010 0011 #ifdef Py_GIL_DISABLED 0012 # include <atomic> 0013 #endif 0014 0015 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 0016 0017 // Use the `gil_safe_call_once_and_store` class below instead of the naive 0018 // 0019 // static auto imported_obj = py::module_::import("module_name"); // BAD, DO NOT USE! 0020 // 0021 // which has two serious issues: 0022 // 0023 // 1. Py_DECREF() calls potentially after the Python interpreter was finalized already, and 0024 // 2. deadlocks in multi-threaded processes (because of missing lock ordering). 0025 // 0026 // The following alternative avoids both problems: 0027 // 0028 // PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> storage; 0029 // auto &imported_obj = storage // Do NOT make this `static`! 0030 // .call_once_and_store_result([]() { 0031 // return py::module_::import("module_name"); 0032 // }) 0033 // .get_stored(); 0034 // 0035 // The parameter of `call_once_and_store_result()` must be callable. It can make 0036 // CPython API calls, and in particular, it can temporarily release the GIL. 0037 // 0038 // `T` can be any C++ type, it does not have to involve CPython API types. 0039 // 0040 // The behavior with regard to signals, e.g. `SIGINT` (`KeyboardInterrupt`), 0041 // is not ideal. If the main thread is the one to actually run the `Callable`, 0042 // then a `KeyboardInterrupt` will interrupt it if it is running normal Python 0043 // code. The situation is different if a non-main thread runs the 0044 // `Callable`, and then the main thread starts waiting for it to complete: 0045 // a `KeyboardInterrupt` will not interrupt the non-main thread, but it will 0046 // get processed only when it is the main thread's turn again and it is running 0047 // normal Python code. However, this will be unnoticeable for quick call-once 0048 // functions, which is usually the case. 0049 template <typename T> 0050 class gil_safe_call_once_and_store { 0051 public: 0052 // PRECONDITION: The GIL must be held when `call_once_and_store_result()` is called. 0053 template <typename Callable> 0054 gil_safe_call_once_and_store &call_once_and_store_result(Callable &&fn) { 0055 if (!is_initialized_) { // This read is guarded by the GIL. 0056 // Multiple threads may enter here, because the GIL is released in the next line and 0057 // CPython API calls in the `fn()` call below may release and reacquire the GIL. 0058 gil_scoped_release gil_rel; // Needed to establish lock ordering. 0059 std::call_once(once_flag_, [&] { 0060 // Only one thread will ever enter here. 0061 gil_scoped_acquire gil_acq; 0062 ::new (storage_) T(fn()); // fn may release, but will reacquire, the GIL. 0063 is_initialized_ = true; // This write is guarded by the GIL. 0064 }); 0065 // All threads will observe `is_initialized_` as true here. 0066 } 0067 // Intentionally not returning `T &` to ensure the calling code is self-documenting. 0068 return *this; 0069 } 0070 0071 // This must only be called after `call_once_and_store_result()` was called. 0072 T &get_stored() { 0073 assert(is_initialized_); 0074 PYBIND11_WARNING_PUSH 0075 #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5 0076 // Needed for gcc 4.8.5 0077 PYBIND11_WARNING_DISABLE_GCC("-Wstrict-aliasing") 0078 #endif 0079 return *reinterpret_cast<T *>(storage_); 0080 PYBIND11_WARNING_POP 0081 } 0082 0083 constexpr gil_safe_call_once_and_store() = default; 0084 PYBIND11_DTOR_CONSTEXPR ~gil_safe_call_once_and_store() = default; 0085 0086 private: 0087 alignas(T) char storage_[sizeof(T)] = {}; 0088 std::once_flag once_flag_ = {}; 0089 #ifdef Py_GIL_DISABLED 0090 std::atomic_bool 0091 #else 0092 bool 0093 #endif 0094 is_initialized_{false}; 0095 // The `is_initialized_`-`storage_` pair is very similar to `std::optional`, 0096 // but the latter does not have the triviality properties of former, 0097 // therefore `std::optional` is not a viable alternative here. 0098 }; 0099 0100 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |