Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 09:37:42

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 //  \author Markus Frank
0011 //  \date   2015-11-07
0012 //
0013 //==========================================================================
0014 
0015 // C/C++ include files
0016 #include <fstream>
0017 #include <sstream>
0018 #include <iostream>
0019 #include <stdexcept>
0020 #include <pthread.h>
0021 
0022 // Framework include files
0023 #include <DD4hep/Printout.h>
0024 #include <DDG4/Python/DDPython.h>
0025 
0026 #if !defined(__MAKECINT__) && !defined(__CINT__) && !defined(G__DICTIONARY)
0027 // -----------------------------------------------------------------------------
0028 // Python hacks to avoid warnings if outside dictionaries .....
0029 // -----------------------------------------------------------------------------
0030 // --> /usr/include/python2.7/pyconfig.h:1161:0: warning: "_POSIX_C_SOURCE" redefined [enabled by default]
0031 #ifdef _POSIX_C_SOURCE
0032 #undef _POSIX_C_SOURCE
0033 #endif /* _POSIX_C_SOURCE */
0034 // --> /usr/include/python2.7/pyconfig.h:1183:0: warning: "_XOPEN_SOURCE" redefined [enabled by default]
0035 #ifdef _XOPEN_SOURCE
0036 #undef _XOPEN_SOURCE
0037 #endif /* _XOPEN_SOURCE */
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 /// Standard constructor, initializes variables
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; // Ensure we do not call Py_Finalize()!
0148   }
0149   if ( !_main_dict ) {
0150     // retrieve the main dictionary
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   //if ( !isMainThread() ) context = ::PyEval_SaveThread();
0167   if ( !_save_state )  {
0168     //_save_state = ::PyEval_SaveThread();
0169   }
0170 }
0171 
0172 /// Default Destructor
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 /// Save thread state
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 /// Release python object
0288 void dd4hep::DDPython::releaseObject(PyObject*& obj)   {
0289   if ( obj && ::Py_IsInitialized() )  {
0290     Py_DECREF(obj);
0291   }
0292   obj = 0;
0293 }
0294 
0295 /// Release python object
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 /// Start the interpreter in normal mode without hacks like 'pythopn.exe' does.
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 }