mirror of
https://github.com/thelsing/knx.git
synced 2024-12-23 19:09:41 +01:00
112 lines
3.6 KiB
C++
112 lines
3.6 KiB
C++
/*
|
|
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 <pybind11/pybind11.h>
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <thread>
|
|
|
|
// 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 <typename Acquire, typename Release>
|
|
void gil_acquire_inner() {
|
|
Acquire acquire_outer;
|
|
Acquire acquire_inner;
|
|
Release release;
|
|
}
|
|
|
|
template <typename Acquire, typename Release>
|
|
void gil_acquire_nested() {
|
|
Acquire acquire_outer;
|
|
Acquire acquire_inner;
|
|
Release release;
|
|
auto thread = std::thread(&gil_acquire_inner<Acquire, Release>);
|
|
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<void *>(&__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*");
|
|
#ifdef Py_GIL_DISABLED
|
|
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
|
|
#endif
|
|
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<CustomAutoGIL, CustomAutoNoGIL>)
|
|
ADD_FUNCTION("gil_acquire_nested_custom_funcaddr",
|
|
gil_acquire_nested<CustomAutoGIL, CustomAutoNoGIL>)
|
|
ADD_FUNCTION("gil_acquire_inner_pybind11_funcaddr",
|
|
gil_acquire_inner<py::gil_scoped_acquire, py::gil_scoped_release>)
|
|
ADD_FUNCTION("gil_acquire_nested_pybind11_funcaddr",
|
|
gil_acquire_nested<py::gil_scoped_acquire, py::gil_scoped_release>)
|
|
}
|
|
|
|
return m;
|
|
}
|