File indexing completed on 2025-02-22 09:37:42
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <fstream>
0017 #include <sstream>
0018 #include <iostream>
0019 #include <stdexcept>
0020 #include <pthread.h>
0021
0022
0023 #include <DD4hep/Printout.h>
0024 #include <DDG4/Python/DDPython.h>
0025
0026 #if !defined(__MAKECINT__) && !defined(__CINT__) && !defined(G__DICTIONARY)
0027
0028
0029
0030
0031 #ifdef _POSIX_C_SOURCE
0032 #undef _POSIX_C_SOURCE
0033 #endif
0034
0035 #ifdef _XOPEN_SOURCE
0036 #undef _XOPEN_SOURCE
0037 #endif
0038 #include <Python.h>
0039 #endif
0040
0041 namespace {
0042 std::string loadScript(const std::string& fname) {
0043 std::ifstream file(fname.c_str());
0044 std::stringstream str;
0045 if( file ) {
0046 char ch;
0047 while( file.get(ch) ) str.put(ch);
0048 file.close();
0049 return str.str();
0050 }
0051 return "";
0052 }
0053
0054 static dd4hep::DDPython* _instance = 0;
0055 static int _blockers = 0;
0056 static pthread_t _mainThread = 0;
0057 static int _refCount = 0;
0058 static PyObject* _main_dict = 0;
0059 static PyThreadState *_save_state = 0;
0060 int _execPy(const char* cmd) {
0061 dd4hep::DDPython::GILState state(0);
0062 PyObject* ret = ::PyRun_String((char*)cmd, Py_file_input,_main_dict,_main_dict);
0063 if ( ::PyErr_Occurred() ) {
0064 ::PyErr_Print();
0065 ::PyErr_Clear();
0066 return 0;
0067 }
0068 if ( ret && ret == Py_None ) {
0069 Py_DECREF( ret );
0070 return 1;
0071 }
0072 else if ( ret ) {
0073 TPyReturn r(ret);
0074 Py_DECREF( ret );
0075 return (int)r;
0076 }
0077 return 0;
0078 }
0079 int _evalPy(const char* cmd) {
0080 dd4hep::DDPython::GILState state(0);
0081 PyObject* ret = ::PyRun_String((char*)cmd, Py_eval_input,_main_dict,_main_dict);
0082 if ( ::PyErr_Occurred() ) {
0083 ::PyErr_Print();
0084 ::PyErr_Clear();
0085 return 0;
0086 }
0087 if ( ret && ret == Py_None ) {
0088 Py_DECREF( ret );
0089 return 1;
0090 }
0091 else if ( ret ) {
0092 TPyReturn r(ret);
0093 Py_DECREF( ret );
0094 return (int)r;
0095 }
0096 return 0;
0097 }
0098 }
0099
0100 dd4hep::DDPython::GILState::GILState(int) : state(0) {
0101 if ( ::Py_IsInitialized() ) {
0102 PyGILState_STATE st = (PyGILState_STATE)::PyGILState_Ensure();
0103 state = (int)st;
0104 }
0105 }
0106
0107 dd4hep::DDPython::GILState::~GILState() {
0108 if ( ::Py_IsInitialized() ) {
0109 PyGILState_STATE st = (PyGILState_STATE)state;
0110 ::PyGILState_Release(st);
0111 }
0112 }
0113
0114 dd4hep::DDPython::BlockThreads::BlockThreads(int) {
0115 if ( _blockers == 0 ) {
0116 DDPython::restoreThread();
0117 }
0118 ++_blockers;
0119 }
0120
0121 dd4hep::DDPython::BlockThreads::~BlockThreads() {
0122 --_blockers;
0123 if ( _blockers == 0 ) {
0124 DDPython::allowThreads();
0125 }
0126 }
0127
0128 dd4hep::DDPython::AllowThreads::AllowThreads(int) {
0129 DDPython::allowThreads();
0130 }
0131
0132 dd4hep::DDPython::AllowThreads::~AllowThreads() {
0133 DDPython::restoreThread();
0134 }
0135
0136
0137 dd4hep::DDPython::DDPython() : context(0) {
0138 ++_refCount;
0139 bool inited = ::Py_IsInitialized();
0140 if ( !inited ) {
0141 ::Py_Initialize();
0142 #if PY_MAJOR_VERSION <=2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7)
0143 ::PyEval_InitThreads();
0144 #endif
0145 }
0146 else {
0147 _refCount += 1000;
0148 }
0149 if ( !_main_dict ) {
0150
0151 PyObject* module = ::PyImport_AddModule("__main__");
0152 if ( !module || ::PyErr_Occurred() ) {
0153 ::PyErr_Print();
0154 ::PyErr_Clear();
0155 dd4hep::printout(WARNING,"DDPython","Main dictionary pointer is NULL. Try to continue like this!");
0156 }
0157 else {
0158 _main_dict = ::PyModule_GetDict(module);
0159 if ( _main_dict ) {
0160 Py_INCREF( _main_dict );
0161 }
0162 dd4hep::printout(DEBUG,"DDPython","Pointer to main dict:%p",(void*)_main_dict);
0163 }
0164 setMainThread();
0165 }
0166
0167 if ( !_save_state ) {
0168
0169 }
0170 }
0171
0172
0173 dd4hep::DDPython::~DDPython() {
0174 --_refCount;
0175 if ( 0 == _refCount && ::Py_IsInitialized() ) {
0176 dd4hep::printout(ALWAYS,"DDPython","+++ Shutdown python interpreter......");
0177 if ( _main_dict ) {
0178 Py_DECREF(_main_dict);
0179 _main_dict = 0;
0180 }
0181 if ( _save_state ) {
0182 ::PyEval_RestoreThread(_save_state);
0183 }
0184 ::Py_Finalize();
0185 _instance = 0;
0186 }
0187 }
0188
0189
0190 dd4hep::DDPython dd4hep::DDPython::instance() {
0191 if ( 0 == _instance ) _instance = new DDPython();
0192 return DDPython();
0193 }
0194
0195
0196 void dd4hep::DDPython::allowThreads() {
0197 if ( !_save_state && ::Py_IsInitialized() ) {
0198 _save_state = ::PyEval_SaveThread();
0199 }
0200 }
0201
0202 void dd4hep::DDPython::restoreThread() {
0203 if ( _save_state ) {
0204 ::PyEval_RestoreThread(_save_state);
0205 _save_state = 0;
0206 }
0207 }
0208
0209 int dd4hep::DDPython::setArgs(int argc, char** argv) const {
0210 std::vector<std::wstring> wargs;
0211 std::vector<const wchar_t*> wargv;
0212 for(int i=0; i<argc;++i) {
0213 std::wstring wstr;
0214 if ( argv[i] ) {
0215 const size_t size = strlen(argv[i]);
0216 if (size > 0) {
0217 wstr.resize(size+1);
0218 std::mbstowcs(&wstr[0], argv[i], size);
0219 wstr[size] = 0;
0220 }
0221 }
0222 wargs.push_back(wstr);
0223 }
0224 for(auto& s : wargs ) wargv.push_back(s.c_str());
0225
0226 PyStatus status;
0227
0228 PyConfig config;
0229 PyConfig_InitPythonConfig( &config );
0230
0231 status = PyConfig_SetString( &config, &config.program_name, wargv[0] );
0232 status = PyConfig_SetArgv( &config, 1, (wchar_t**)&wargv[0] );
0233 status = Py_InitializeFromConfig( &config );
0234 PyConfig_Clear( &config );
0235
0236 return 1;
0237 }
0238
0239 void dd4hep::DDPython::shutdown() {
0240 if ( 0 != _instance ) {
0241 if ( 1 == _refCount ) {
0242 delete _instance;
0243 _instance = 0;
0244 }
0245 }
0246 }
0247
0248 int dd4hep::DDPython::runFile(const std::string& fname) const {
0249 std::string cmd = loadScript(fname);
0250 return execute(cmd);
0251 }
0252
0253 int dd4hep::DDPython::evaluate(const std::string& cmd) const {
0254 return _evalPy(cmd.c_str());
0255 }
0256
0257 int dd4hep::DDPython::execute(const std::string& cmd) const {
0258 return _execPy(cmd.c_str());
0259 }
0260
0261 PyObject* dd4hep::DDPython::call(PyObject* method, PyObject* args) {
0262 dd4hep::DDPython::GILState state(0);
0263 if ( PyCallable_Check(method) ) {
0264 PyObject* ret = ::PyObject_CallObject(method,args==Py_None ? NULL : args);
0265 return ret;
0266 }
0267 ::PyErr_SetString(PyExc_RuntimeError,"DDPython::call: The argument is not a callable object!");
0268 return 0;
0269 }
0270
0271 TPyReturn dd4hep::DDPython::callC(PyObject* method, PyObject* args) {
0272 if ( PyCallable_Check(method) ) {
0273 PyObject* arg = args==Py_None || args==0 ? 0 : args;
0274 PyObject* ret = ::PyObject_CallObject(method,arg);
0275 if ( ::PyErr_Occurred() ) {
0276 ::PyErr_Print();
0277 ::PyErr_Clear();
0278 return TPyReturn();
0279 }
0280 else if ( ret ) {
0281 return TPyReturn(ret);
0282 }
0283 }
0284 throw std::runtime_error("dd4hep::DDPython::callC: Object is not callable!");
0285 }
0286
0287
0288 void dd4hep::DDPython::releaseObject(PyObject*& obj) {
0289 if ( obj && ::Py_IsInitialized() ) {
0290 Py_DECREF(obj);
0291 }
0292 obj = 0;
0293 }
0294
0295
0296 void dd4hep::DDPython::assignObject(PyObject*& obj, PyObject* new_obj) {
0297 if ( ::Py_IsInitialized() ) {
0298 if ( obj ) { Py_DECREF(obj); }
0299 if ( new_obj ){ Py_INCREF(new_obj); }
0300 }
0301 obj = new_obj;
0302 }
0303
0304 void dd4hep::DDPython::prompt() const {
0305 dd4hep::DDPython::GILState state(0);
0306 ::PyRun_InteractiveLoop(stdin,const_cast<char*>("\0"));
0307 }
0308
0309 void dd4hep::DDPython::afterFork() const {
0310 if ( ::Py_IsInitialized() ) {
0311 std::cout << "[INFO] Re-init python after forking....." << std::endl;
0312 #if PY_VERSION_HEX < 0x03070000
0313 ::PyOS_AfterFork();
0314 #else
0315 ::PyOS_AfterFork_Child();
0316 #endif
0317 #if PY_MAJOR_VERSION <=2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7)
0318 ::PyEval_InitThreads();
0319 ::PyEval_ReleaseLock();
0320 #endif
0321 }
0322 }
0323
0324 void dd4hep::DDPython::setMainThread() {
0325 _mainThread = pthread_self();
0326 }
0327
0328 bool dd4hep::DDPython::isMainThread() {
0329 return _mainThread == pthread_self();
0330 }
0331
0332
0333 int dd4hep::DDPython::run_interpreter(int argc, char** argv) {
0334 std::vector<std::wstring> wargs;
0335 std::vector<const wchar_t*> wargv;
0336 for(int i=0; i<argc;++i) {
0337 std::wstring wstr;
0338 if ( argv[i] ) {
0339 const size_t size = strlen(argv[i]);
0340 if (size > 0) {
0341 wstr.resize(size+1);
0342 std::mbstowcs(&wstr[0], argv[i], size);
0343 wstr[size] = 0;
0344 }
0345 }
0346 wargs.push_back(wstr);
0347 }
0348 for( auto& s : wargs ) wargv.push_back(s.c_str());
0349 return ::Py_Main(argc, (wchar_t**)&wargv[0]);
0350 }