#include "Gil.h"
-Gil::Gil(PyThreadState *ts, bool new_thread) : pThreadState(ts)
+SafeThreadState::SafeThreadState(PyThreadState *ts_)
+ : ts(ts_)
{
- assert(pThreadState != nullptr);
+ assert(ts != nullptr);
+ thread = pthread_self();
+}
+Gil::Gil(SafeThreadState &ts, bool new_thread) : pThreadState(ts)
+{
// Acquire the GIL, set the current thread state
- PyEval_RestoreThread(pThreadState);
- dout(25) << "GIL acquired for thread state " << pThreadState << dendl;
+ PyEval_RestoreThread(pThreadState.ts);
+ dout(25) << "GIL acquired for thread state " << pThreadState.ts << dendl;
//
// If called from a separate OS thread (i.e. a thread not created
// something that's meant to be a black box.
//
if (new_thread) {
- pNewThreadState = PyThreadState_New(pThreadState->interp);
+ pNewThreadState = PyThreadState_New(pThreadState.ts->interp);
PyThreadState_Swap(pNewThreadState);
dout(20) << "Switched to new thread state " << pNewThreadState << dendl;
+ } else {
+ assert(pthread_self() == pThreadState.thread);
}
}
{
if (pNewThreadState != nullptr) {
dout(20) << "Destroying new thread state " << pNewThreadState << dendl;
- PyThreadState_Swap(pThreadState);
+ PyThreadState_Swap(pThreadState.ts);
PyThreadState_Clear(pNewThreadState);
PyThreadState_Delete(pNewThreadState);
}
// Release the GIL, reset the thread state to NULL
PyEval_SaveThread();
- dout(25) << "GIL released for thread state " << pThreadState << dendl;
+ dout(25) << "GIL released for thread state " << pThreadState.ts << dendl;
}
struct _ts;
typedef struct _ts PyThreadState;
+#include <pthread.h>
+
+
+/**
+ * Wrap PyThreadState to carry a record of which POSIX thread
+ * the thread state relates to. This allows the Gil class to
+ * validate that we're being used from the right thread.
+ */
+class SafeThreadState
+{
+ public:
+ SafeThreadState(PyThreadState *ts_);
+
+ SafeThreadState()
+ : ts(nullptr), thread(0)
+ {
+ }
+
+ PyThreadState *ts;
+ pthread_t thread;
+
+ void set(PyThreadState *ts_)
+ {
+ ts = ts_;
+ thread = pthread_self();
+ }
+};
+
+//
// Use one of these in any scope in which you need to hold Python's
// Global Interpreter Lock.
//
Gil(const Gil&) = delete;
Gil& operator=(const Gil&) = delete;
- Gil(PyThreadState *ts, bool new_thread = false);
+ Gil(SafeThreadState &ts, bool new_thread = false);
~Gil();
private:
- PyThreadState *pThreadState;
+ SafeThreadState &pThreadState;
PyThreadState *pNewThreadState = nullptr;
};
#include "PyState.h"
#include "PyOSDMap.h"
-#include "Gil.h"
#include "PyFormatter.h"
pClassInstance(nullptr),
pMainThreadState(main_ts_)
{
- assert(pMainThreadState != nullptr);
-
Gil gil(pMainThreadState);
- pMyThreadState = Py_NewInterpreter();
- if (pMyThreadState == nullptr) {
+ auto thread_state = Py_NewInterpreter();
+ if (thread_state == nullptr) {
derr << "Failed to create python sub-interpreter for '" << module_name << '"' << dendl;
} else {
+ pMyThreadState.set(thread_state);
+
// Some python modules do not cope with an unpopulated argv, so lets
// fake one. This step also picks up site-packages into sys.path.
const char *argv[] = {"ceph-mgr"};
MgrPyModule::~MgrPyModule()
{
- if (pMyThreadState != nullptr) {
+ if (pMyThreadState.ts != nullptr) {
Gil gil(pMyThreadState);
Py_XDECREF(pClassInstance);
int MgrPyModule::load()
{
- if (pMyThreadState == nullptr) {
+ if (pMyThreadState.ts == nullptr) {
derr << "No python sub-interpreter exists for module '" << module_name << "'" << dendl;
return -EINVAL;
}
#include "common/LogEntry.h"
#include "common/Mutex.h"
#include "mon/health_check.h"
+#include "mgr/Gil.h"
#include <vector>
#include <string>
private:
const std::string module_name;
PyObject *pClassInstance;
- PyThreadState *pMainThreadState;
- PyThreadState *pMyThreadState = nullptr;
+ SafeThreadState pMainThreadState;
+ SafeThreadState pMyThreadState;
health_check_map_t health_checks;
// Drop the GIL and remember the main thread state (current
// thread state becomes NULL)
pMainThreadState = PyEval_SaveThread();
+ assert(pMainThreadState != nullptr);
std::list<std::string> failed_modules;
{
PyObject *python_completion;
const std::string tag;
- PyThreadState *pThreadState;
+ SafeThreadState pThreadState;
public:
std::string outs;