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;
 | 
						|
}
 |