DD4hep  1.30.0
Detector Description Toolkit for High Energy Physics
DDPython.cpp
Go to the documentation of this file.
1 //==========================================================================
2 // AIDA Detector description implementation
3 //--------------------------------------------------------------------------
4 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
5 // All rights reserved.
6 //
7 // For the licensing terms see $DD4hepINSTALL/LICENSE.
8 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
9 //
10 // \author Markus Frank
11 // \date 2015-11-07
12 //
13 //==========================================================================
14 
15 // C/C++ include files
16 #include <fstream>
17 #include <sstream>
18 #include <iostream>
19 #include <stdexcept>
20 #include <pthread.h>
21 
22 // Framework include files
23 #include <DD4hep/Printout.h>
24 #include <DDG4/Python/DDPython.h>
25 
26 #if !defined(__MAKECINT__) && !defined(__CINT__) && !defined(G__DICTIONARY)
27 // -----------------------------------------------------------------------------
28 // Python hacks to avoid warnings if outside dictionaries .....
29 // -----------------------------------------------------------------------------
30 // --> /usr/include/python2.7/pyconfig.h:1161:0: warning: "_POSIX_C_SOURCE" redefined [enabled by default]
31 #ifdef _POSIX_C_SOURCE
32 #undef _POSIX_C_SOURCE
33 #endif /* _POSIX_C_SOURCE */
34 // --> /usr/include/python2.7/pyconfig.h:1183:0: warning: "_XOPEN_SOURCE" redefined [enabled by default]
35 #ifdef _XOPEN_SOURCE
36 #undef _XOPEN_SOURCE
37 #endif /* _XOPEN_SOURCE */
38 #include <Python.h>
39 #endif
40 
41 namespace {
42  std::string loadScript(const std::string& fname) {
43  std::ifstream file(fname.c_str());
44  std::stringstream str;
45  if( file ) {
46  char ch;
47  while( file.get(ch) ) str.put(ch);
48  file.close();
49  return str.str();
50  }
51  return "";
52  }
53 
54  static dd4hep::DDPython* _instance = 0;
55  static int _blockers = 0;
56  static pthread_t _mainThread = 0;
57  static int _refCount = 0;
58  static PyObject* _main_dict = 0;
59  static PyThreadState *_save_state = 0;
60  int _execPy(const char* cmd) {
62  PyObject* ret = ::PyRun_String((char*)cmd, Py_file_input,_main_dict,_main_dict);
63  if ( ::PyErr_Occurred() ) {
64  ::PyErr_Print();
65  ::PyErr_Clear();
66  return 0;
67  }
68  if ( ret && ret == Py_None ) {
69  Py_DECREF( ret );
70  return 1;
71  }
72  else if ( ret ) {
73  TPyReturn r(ret);
74  Py_DECREF( ret );
75  return (int)r;
76  }
77  return 0;
78  }
79  int _evalPy(const char* cmd) {
81  PyObject* ret = ::PyRun_String((char*)cmd, Py_eval_input,_main_dict,_main_dict);
82  if ( ::PyErr_Occurred() ) {
83  ::PyErr_Print();
84  ::PyErr_Clear();
85  return 0;
86  }
87  if ( ret && ret == Py_None ) {
88  Py_DECREF( ret );
89  return 1;
90  }
91  else if ( ret ) {
92  TPyReturn r(ret);
93  Py_DECREF( ret );
94  return (int)r;
95  }
96  return 0;
97  }
98 }
99 
101  if ( ::Py_IsInitialized() ) {
102  PyGILState_STATE st = (PyGILState_STATE)::PyGILState_Ensure();
103  state = (int)st;
104  }
105 }
106 
108  if ( ::Py_IsInitialized() ) {
109  PyGILState_STATE st = (PyGILState_STATE)state;
110  ::PyGILState_Release(st);
111  }
112 }
113 
115  if ( _blockers == 0 ) {
117  }
118  ++_blockers;
119 }
120 
122  --_blockers;
123  if ( _blockers == 0 ) {
125  }
126 }
127 
130 }
131 
134 }
135 
138  ++_refCount;
139  bool inited = ::Py_IsInitialized();
140  if ( !inited ) {
141  ::Py_Initialize();
142 #if PY_MAJOR_VERSION <=2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7)
143  ::PyEval_InitThreads();
144 #endif
145  }
146  else {
147  _refCount += 1000; // Ensure we do not call Py_Finalize()!
148  }
149  if ( !_main_dict ) {
150  // retrieve the main dictionary
151  PyObject* module = ::PyImport_AddModule("__main__");
152  if ( !module || ::PyErr_Occurred() ) {
153  ::PyErr_Print();
154  ::PyErr_Clear();
155  dd4hep::printout(WARNING,"DDPython","Main dictionary pointer is NULL. Try to continue like this!");
156  }
157  else {
158  _main_dict = ::PyModule_GetDict(module);
159  if ( _main_dict ) {
160  Py_INCREF( _main_dict );
161  }
162  dd4hep::printout(DEBUG,"DDPython","Pointer to main dict:%p",(void*)_main_dict);
163  }
164  setMainThread();
165  }
166  //if ( !isMainThread() ) context = ::PyEval_SaveThread();
167  if ( !_save_state ) {
168  //_save_state = ::PyEval_SaveThread();
169  }
170 }
171 
174  --_refCount;
175  if ( 0 == _refCount && ::Py_IsInitialized() ) {
176  dd4hep::printout(ALWAYS,"DDPython","+++ Shutdown python interpreter......");
177  if ( _main_dict ) {
178  Py_DECREF(_main_dict);
179  _main_dict = 0;
180  }
181  if ( _save_state ) {
182  ::PyEval_RestoreThread(_save_state);
183  }
184  ::Py_Finalize();
185  _instance = 0;
186  }
187 }
188 
189 
191  if ( 0 == _instance ) _instance = new DDPython();
192  return DDPython();
193 }
194 
197  if ( !_save_state && ::Py_IsInitialized() ) {
198  _save_state = ::PyEval_SaveThread();
199  }
200 }
201 
203  if ( _save_state ) {
204  ::PyEval_RestoreThread(_save_state);
205  _save_state = 0;
206  }
207 }
208 
209 int dd4hep::DDPython::setArgs(int argc, char** argv) const {
210  std::vector<std::wstring> wargs;
211  std::vector<const wchar_t*> wargv;
212  for(int i=0; i<argc;++i) {
213  std::wstring wstr;
214  if ( argv[i] ) {
215  const size_t size = strlen(argv[i]);
216  if (size > 0) {
217  wstr.resize(size+1);
218  std::mbstowcs(&wstr[0], argv[i], size);
219  wstr[size] = 0;
220  }
221  }
222  wargs.push_back(wstr);
223  }
224  for(auto& s : wargs ) wargv.push_back(s.c_str());
225 
226  PyStatus status;
227 
228  PyConfig config;
229  PyConfig_InitPythonConfig( &config );
230 
231  status = PyConfig_SetString( &config, &config.program_name, wargv[0] );
232  status = PyConfig_SetArgv( &config, 1, (wchar_t**)&wargv[0] );
233  status = Py_InitializeFromConfig( &config );
234  PyConfig_Clear( &config );
235 
236  return 1;
237 }
238 
240  if ( 0 != _instance ) {
241  if ( 1 == _refCount ) {
242  delete _instance;
243  _instance = 0;
244  }
245  }
246 }
247 
248 int dd4hep::DDPython::runFile(const std::string& fname) const {
249  std::string cmd = loadScript(fname);
250  return execute(cmd);
251 }
252 
253 int dd4hep::DDPython::evaluate(const std::string& cmd) const {
254  return _evalPy(cmd.c_str());
255 }
256 
257 int dd4hep::DDPython::execute(const std::string& cmd) const {
258  return _execPy(cmd.c_str());
259 }
260 
261 PyObject* dd4hep::DDPython::call(PyObject* method, PyObject* args) {
263  if ( PyCallable_Check(method) ) {
264  PyObject* ret = ::PyObject_CallObject(method,args==Py_None ? NULL : args);
265  return ret;
266  }
267  ::PyErr_SetString(PyExc_RuntimeError,"DDPython::call: The argument is not a callable object!");
268  return 0;
269 }
270 
271 TPyReturn dd4hep::DDPython::callC(PyObject* method, PyObject* args) {
272  if ( PyCallable_Check(method) ) {
273  PyObject* arg = args==Py_None || args==0 ? 0 : args;
274  PyObject* ret = ::PyObject_CallObject(method,arg);
275  if ( ::PyErr_Occurred() ) {
276  ::PyErr_Print();
277  ::PyErr_Clear();
278  return TPyReturn();
279  }
280  else if ( ret ) {
281  return TPyReturn(ret);
282  }
283  }
284  throw std::runtime_error("dd4hep::DDPython::callC: Object is not callable!");
285 }
286 
288 void dd4hep::DDPython::releaseObject(PyObject*& obj) {
289  if ( obj && ::Py_IsInitialized() ) {
290  Py_DECREF(obj);
291  }
292  obj = 0;
293 }
294 
296 void dd4hep::DDPython::assignObject(PyObject*& obj, PyObject* new_obj) {
297  if ( ::Py_IsInitialized() ) {
298  if ( obj ) { Py_DECREF(obj); }
299  if ( new_obj ){ Py_INCREF(new_obj); }
300  }
301  obj = new_obj;
302 }
303 
306  ::PyRun_InteractiveLoop(stdin,const_cast<char*>("\0"));
307 }
308 
310  if ( ::Py_IsInitialized() ) {
311  std::cout << "[INFO] Re-init python after forking....." << std::endl;
312 #if PY_VERSION_HEX < 0x03070000
313  ::PyOS_AfterFork();
314 #else
315  ::PyOS_AfterFork_Child();
316 #endif
317 #if PY_MAJOR_VERSION <=2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7)
318  ::PyEval_InitThreads();
319  ::PyEval_ReleaseLock();
320 #endif
321  }
322 }
323 
325  _mainThread = pthread_self();
326 }
327 
329  return _mainThread == pthread_self();
330 }
331 
333 int dd4hep::DDPython::run_interpreter(int argc, char** argv) {
334  std::vector<std::wstring> wargs;
335  std::vector<const wchar_t*> wargv;
336  for(int i=0; i<argc;++i) {
337  std::wstring wstr;
338  if ( argv[i] ) {
339  const size_t size = strlen(argv[i]);
340  if (size > 0) {
341  wstr.resize(size+1);
342  std::mbstowcs(&wstr[0], argv[i], size);
343  wstr[size] = 0;
344  }
345  }
346  wargs.push_back(wstr);
347  }
348  for( auto& s : wargs ) wargv.push_back(s.c_str());
349  return ::Py_Main(argc, (wchar_t**)&wargv[0]);
350 }
dd4hep::DDPython::DDPython
DDPython()
Standard constructor.
Definition: DDPython.cpp:137
dd4hep::DDPython::AllowThreads::~AllowThreads
~AllowThreads()
Definition: DDPython.cpp:132
dd4hep::DDPython::isMainThread
static bool isMainThread()
Definition: DDPython.cpp:328
dd4hep::DDPython::callC
TPyReturn callC(PyObject *method, PyObject *args)
Call a python object with argument (typically a dictionary).
Definition: DDPython.cpp:271
dd4hep::DDPython::setMainThread
static void setMainThread()
Definition: DDPython.cpp:324
dd4hep::DDPython::GILState::state
int state
Definition: DDPython.h:43
dd4hep::DDPython::GILState::GILState
GILState(int)
Definition: DDPython.cpp:100
dd4hep::DDPython::shutdown
static void shutdown()
Definition: DDPython.cpp:239
dd4hep::DDPython
Python interface class for callbacks and GIL.
Definition: DDPython.h:34
dd4hep::DDPython::evaluate
int evaluate(const std::string &cmd) const
Definition: DDPython.cpp:253
dd4hep::DDPython::allowThreads
static void allowThreads()
Save thread state.
Definition: DDPython.cpp:196
dd4hep::DDPython::run_interpreter
static int run_interpreter(int argc, char **argv)
Start the interpreter in normal mode without hacks like 'python.exe' does.
Definition: DDPython.cpp:333
dd4hep::DDPython::afterFork
void afterFork() const
Callback after forking.
Definition: DDPython.cpp:309
dd4hep::DDPython::BlockThreads::BlockThreads
BlockThreads(int)
Definition: DDPython.cpp:114
dd4hep::DDPython::BlockThreads::~BlockThreads
~BlockThreads()
Definition: DDPython.cpp:121
dd4hep::DDPython::assignObject
static void assignObject(PyObject *&obj, PyObject *new_obj)
Release python object.
Definition: DDPython.cpp:296
dd4hep::DDPython::AllowThreads::AllowThreads
AllowThreads(int)
Definition: DDPython.cpp:128
dd4hep::DDPython::releaseObject
static void releaseObject(PyObject *&obj)
Release python object.
Definition: DDPython.cpp:288
dd4hep::DDPython::setArgs
int setArgs(int argc, char **argv) const
Definition: DDPython.cpp:209
dd4hep::DDPython::restoreThread
static void restoreThread()
Definition: DDPython.cpp:202
dd4hep::DDPython::execute
int execute(const std::string &cmd) const
Definition: DDPython.cpp:257
dd4hep::DDPython::context
void * context
Definition: DDPython.h:36
DDPython.h
dd4hep::DDPython::GILState
Definition: DDPython.h:42
dd4hep::DDPython::instance
static DDPython instance()
Object instantiator.
Definition: DDPython.cpp:190
dd4hep::DDPython::GILState::~GILState
~GILState()
Definition: DDPython.cpp:107
dd4hep::DDPython::runFile
int runFile(const std::string &fname) const
Definition: DDPython.cpp:248
dd4hep::DDPython::~DDPython
~DDPython()
Destructor.
Definition: DDPython.cpp:173
dd4hep::DDPython::prompt
void prompt() const
Invoke command prompt.
Definition: DDPython.cpp:304
Printout.h
dd4hep::DDPython::call
PyObject * call(PyObject *method, PyObject *args)
Call a python object with argument (typically a dictionary)
Definition: DDPython.cpp:261