// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2016 John Spray * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ // Python.h comes first because otherwise it clobbers ceph's assert #include #include "PyModule.h" #include "common/debug.h" #include "mgr/Gil.h" #include "PyModuleRunner.h" #define dout_context g_ceph_context #define dout_subsys ceph_subsys_mgr PyModuleRunner::~PyModuleRunner() { Gil gil(py_module->pMyThreadState, true); if (pClassInstance) { Py_XDECREF(pClassInstance); pClassInstance = nullptr; } } int PyModuleRunner::serve() { ceph_assert(pClassInstance != nullptr); // This method is called from a separate OS thread (i.e. a thread not // created by Python), so tell Gil to wrap this in a new thread state. Gil gil(py_module->pMyThreadState, true); auto pValue = PyObject_CallMethod(pClassInstance, const_cast("serve"), nullptr); int r = 0; if (pValue != NULL) { Py_DECREF(pValue); } else { // This is not a very informative log message because it's an // unknown/unexpected exception that we can't say much about. // Get short exception message for the cluster log, before // dumping the full backtrace to the local log. std::string exc_msg = peek_pyerror(); clog->error() << "Unhandled exception from module '" << get_name() << "' while running on mgr." << g_conf()->name.get_id() << ": " << exc_msg; derr << get_name() << ".serve:" << dendl; derr << handle_pyerror(true, get_name(), "PyModuleRunner::serve") << dendl; py_module->fail(exc_msg); return -EINVAL; } return r; } void PyModuleRunner::shutdown() { ceph_assert(pClassInstance != nullptr); Gil gil(py_module->pMyThreadState, true); auto pValue = PyObject_CallMethod(pClassInstance, const_cast("shutdown"), nullptr); if (pValue != NULL) { Py_DECREF(pValue); } else { derr << "Failed to invoke shutdown() on " << get_name() << dendl; derr << handle_pyerror(true, get_name(), "PyModuleRunner::shutdown") << dendl; } dead = true; } void PyModuleRunner::log(const std::string &record) { #undef dout_prefix #define dout_prefix *_dout dout(0) << record << dendl; #undef dout_prefix #define dout_prefix *_dout << "mgr " << __func__ << " " } void* PyModuleRunner::PyModuleRunnerThread::entry() { // No need to acquire the GIL here; the module does it. dout(4) << "Entering thread for " << mod->get_name() << dendl; mod->serve(); return nullptr; }