/* tests/cross_module_gil_utils.cpp -- tools for acquiring GIL from a different module Copyright (c) 2019 Google LLC All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #if defined(PYBIND11_INTERNALS_VERSION) # undef PYBIND11_INTERNALS_VERSION #endif #define PYBIND11_INTERNALS_VERSION 21814642 // Ensure this module has its own `internals` instance. #include #include #include #include // This file mimics a DSO that makes pybind11 calls but does not define a // PYBIND11_MODULE. The purpose is to test that such a DSO can create a // py::gil_scoped_acquire when the running thread is in a GIL-released state. // // Note that we define a Python module here for convenience, but in general // this need not be the case. The typical scenario would be a DSO that implements // shared logic used internally by multiple pybind11 modules. namespace { namespace py = pybind11; void gil_acquire() { py::gil_scoped_acquire gil; } std::string gil_multi_acquire_release(unsigned bits) { if ((bits & 0x1u) != 0u) { py::gil_scoped_acquire gil; } if ((bits & 0x2u) != 0u) { py::gil_scoped_release gil; } if ((bits & 0x4u) != 0u) { py::gil_scoped_acquire gil; } if ((bits & 0x8u) != 0u) { py::gil_scoped_release gil; } return PYBIND11_INTERNALS_ID; } struct CustomAutoGIL { CustomAutoGIL() : gstate(PyGILState_Ensure()) {} ~CustomAutoGIL() { PyGILState_Release(gstate); } PyGILState_STATE gstate; }; struct CustomAutoNoGIL { CustomAutoNoGIL() : save(PyEval_SaveThread()) {} ~CustomAutoNoGIL() { PyEval_RestoreThread(save); } PyThreadState *save; }; template void gil_acquire_inner() { Acquire acquire_outer; Acquire acquire_inner; Release release; } template void gil_acquire_nested() { Acquire acquire_outer; Acquire acquire_inner; Release release; auto thread = std::thread(&gil_acquire_inner); thread.join(); } constexpr char kModuleName[] = "cross_module_gil_utils"; struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr}; } // namespace #define ADD_FUNCTION(Name, ...) \ PyModule_AddObject(m, Name, PyLong_FromVoidPtr(reinterpret_cast(&__VA_ARGS__))); extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() { PyObject *m = PyModule_Create(&moduledef); if (m != nullptr) { static_assert(sizeof(&gil_acquire) == sizeof(void *), "Function pointer must have the same size as void*"); ADD_FUNCTION("gil_acquire_funcaddr", gil_acquire) ADD_FUNCTION("gil_multi_acquire_release_funcaddr", gil_multi_acquire_release) ADD_FUNCTION("gil_acquire_inner_custom_funcaddr", gil_acquire_inner) ADD_FUNCTION("gil_acquire_nested_custom_funcaddr", gil_acquire_nested) ADD_FUNCTION("gil_acquire_inner_pybind11_funcaddr", gil_acquire_inner) ADD_FUNCTION("gil_acquire_nested_pybind11_funcaddr", gil_acquire_nested) } return m; }