Back to index

salome-gui  6.5.0
PyInterp_Interp.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 //  File   : PyInterp_Interp.cxx
00024 //  Author : Christian CAREMOLI, Paul RASCLE, EDF
00025 //  Module : SALOME
00026 //
00027 #include "PyInterp_Interp.h"  // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
00028 #include <pythread.h>
00029 
00030 #include <cStringIO.h>
00031 #include <structmember.h>
00032 
00033 #include <string>
00034 #include <vector>
00035 #include <map>
00036 #include <iostream>
00037 
00038 #define TOP_HISTORY_PY   "--- top of history ---"
00039 #define BEGIN_HISTORY_PY "--- begin of history ---"
00040 
00041 // a map to store python thread states that have been created for a given system thread (key=thread id,value=thread state)
00042 std::map<long,PyThreadState*> currentThreadMap;
00043 
00053 PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState): 
00054   myThreadState(theThreadState),
00055   mySaveThreadState(0)
00056 {
00057   if (myThreadState->interp == PyInterp_Interp::_interp)
00058     _savestate = PyGILState_Ensure();
00059   else
00060     PyEval_AcquireThread(myThreadState);
00061 }
00062 
00066 PyLockWrapper::~PyLockWrapper()
00067 {
00068   if (myThreadState->interp == PyInterp_Interp::_interp)
00069     PyGILState_Release(_savestate);
00070   else
00071     PyEval_ReleaseThread(myThreadState);
00072 }
00073 
00078 PyLockWrapper PyInterp_Interp::GetLockWrapper()
00079 {
00080   if (_tstate->interp == PyInterp_Interp::_interp)
00081     return _tstate;
00082 
00083   // If we are here, we have a secondary python interpreter. Try to get a thread state synchronized with the system thread
00084   long currentThreadid=PyThread_get_thread_ident(); // the system thread id
00085   PyThreadState* theThreadState;
00086   if(currentThreadMap.count(currentThreadid) != 0)
00087     {
00088       //a thread state exists for this thread id
00089       PyThreadState* oldThreadState=currentThreadMap[currentThreadid];
00090       if(_tstate->interp ==oldThreadState->interp)
00091         {
00092           //The old thread state has the same python interpreter as this one : reuse the threadstate
00093           theThreadState=oldThreadState;
00094         }
00095       else
00096         {
00097           //The old thread state has not the same python interpreter as this one : delete the old threadstate and create a new one
00098           PyEval_AcquireLock();
00099           PyThreadState_Clear(oldThreadState);
00100           PyThreadState_Delete(oldThreadState);
00101           PyEval_ReleaseLock();
00102           theThreadState=PyThreadState_New(_tstate->interp);
00103           currentThreadMap[currentThreadid]=theThreadState;
00104         }
00105     }
00106   else
00107     {
00108       // no old thread state for this thread id : create a new one
00109       theThreadState=PyThreadState_New(_tstate->interp);
00110       currentThreadMap[currentThreadid]=theThreadState;
00111     }
00112   return theThreadState;
00113 }
00114 
00115 /*
00116   The following functions are used to hook the Python 
00117   interpreter output.
00118 */
00119 
00120 static void
00121 PyStdOut_dealloc(PyStdOut *self)
00122 {
00123   PyObject_Del(self);
00124 }
00125 
00126 static PyObject*
00127 PyStdOut_write(PyStdOut *self, PyObject *args)
00128 {
00129   char *c;
00130   int l;
00131   if (!PyArg_ParseTuple(args, "t#:write",&c, &l))
00132     return NULL;
00133   if(self->_cb==NULL) {
00134     if ( self->_iscerr )
00135       std::cerr << c ;
00136     else
00137       std::cout << c ;
00138   }
00139   else {
00140     self->_cb(self->_data,c);
00141   }
00142   Py_INCREF(Py_None);
00143   return Py_None;
00144 }
00145 
00146 static PyObject*
00147 PyStdOut_flush(PyStdOut *self)
00148 {
00149   Py_INCREF(Py_None);
00150   return Py_None;
00151 }
00152 
00153 static PyMethodDef PyStdOut_methods[] = {
00154   {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS, PyDoc_STR("write(string) -> None")},
00155   {"flush",  (PyCFunction)PyStdOut_flush,  METH_NOARGS,  PyDoc_STR("flush() -> None")},
00156   {NULL,    NULL}   /* sentinel */
00157 };
00158 
00159 static PyMemberDef PyStdOut_memberlist[] = {
00160   {(char*)"softspace", T_INT,  offsetof(PyStdOut, softspace), 0,
00161    (char*)"flag indicating that a space needs to be printed; used by print"},
00162   {NULL} /* Sentinel */
00163 };
00164 
00165 static PyTypeObject PyStdOut_Type = {
00166   /* The ob_type field must be initialized in the module init function
00167    * to be portable to Windows without using C++. */
00168   PyObject_HEAD_INIT(NULL)
00169   0,                            /*ob_size*/
00170   "PyOut",                      /*tp_name*/
00171   sizeof(PyStdOut),             /*tp_basicsize*/
00172   0,                            /*tp_itemsize*/
00173   /* methods */
00174   (destructor)PyStdOut_dealloc, /*tp_dealloc*/
00175   0,                            /*tp_print*/
00176   0,                            /*tp_getattr*/
00177   0,                            /*tp_setattr*/
00178   0,                            /*tp_compare*/
00179   0,                            /*tp_repr*/
00180   0,                            /*tp_as_number*/
00181   0,                            /*tp_as_sequence*/
00182   0,                            /*tp_as_mapping*/
00183   0,                            /*tp_hash*/
00184   0,                            /*tp_call*/
00185   0,                            /*tp_str*/
00186   PyObject_GenericGetAttr,      /*tp_getattro*/
00187   /* softspace is writable:  we must supply tp_setattro */
00188   PyObject_GenericSetAttr,      /* tp_setattro */
00189   0,                            /*tp_as_buffer*/
00190   Py_TPFLAGS_DEFAULT,           /*tp_flags*/
00191   0,                            /*tp_doc*/
00192   0,                            /*tp_traverse*/
00193   0,                            /*tp_clear*/
00194   0,                            /*tp_richcompare*/
00195   0,                            /*tp_weaklistoffset*/
00196   0,                            /*tp_iter*/
00197   0,                            /*tp_iternext*/
00198   PyStdOut_methods,             /*tp_methods*/
00199   PyStdOut_memberlist,          /*tp_members*/
00200   0,                            /*tp_getset*/
00201   0,                            /*tp_base*/
00202   0,                            /*tp_dict*/
00203   0,                            /*tp_descr_get*/
00204   0,                            /*tp_descr_set*/
00205   0,                            /*tp_dictoffset*/
00206   0,                            /*tp_init*/
00207   0,                            /*tp_alloc*/
00208   0,                            /*tp_new*/
00209   0,                            /*tp_free*/
00210   0,                            /*tp_is_gc*/
00211 };
00212 
00213 #define PyStdOut_Check(v)  ((v)->ob_type == &PyStdOut_Type)
00214 
00215 static PyStdOut* newPyStdOut( bool iscerr )
00216 {
00217   PyStdOut *self;
00218   self = PyObject_New(PyStdOut, &PyStdOut_Type);
00219   if (self == NULL)
00220     return NULL;
00221   self->softspace = 0;
00222   self->_cb = NULL;
00223   self->_iscerr = iscerr;
00224   return self;
00225 }
00226 
00232 int   PyInterp_Interp::_argc   = 1;
00233 char* PyInterp_Interp::_argv[] = {(char*)""};
00234 PyObject*           PyInterp_Interp::builtinmodule = NULL;
00235 PyThreadState*      PyInterp_Interp::_gtstate      = NULL;
00236 PyInterpreterState* PyInterp_Interp::_interp       = NULL;
00237 
00244 PyInterp_Interp::PyInterp_Interp(): 
00245   _tstate(0), _vout(0), _verr(0), _g(0)
00246 {
00247 }
00248 
00252 PyInterp_Interp::~PyInterp_Interp()
00253 {
00254 }
00255 
00268 void PyInterp_Interp::initialize()
00269 {
00270   _history.clear();       // start a new list of user's commands 
00271   _ith = _history.begin();
00272 
00273   initPython();
00274   // Here the global lock is released
00275 
00276   initState();
00277 
00278   PyEval_AcquireThread(_tstate);
00279 
00280   initContext();
00281 
00282   // used to interpret & compile commands
00283   PyObjWrapper m(PyImport_ImportModule("codeop"));
00284   if(!m) {
00285     PyErr_Print();
00286     PyEval_ReleaseThread(_tstate);
00287     return;
00288   }
00289 
00290   // Create python objects to capture stdout and stderr
00291   _vout=(PyObject*)newPyStdOut( false ); // stdout 
00292   _verr=(PyObject*)newPyStdOut( true );  // stderr
00293 
00294   // All the initRun outputs are redirected to the standard output (console)
00295   initRun();
00296   PyEval_ReleaseThread(_tstate);
00297 }
00298 
00308 void PyInterp_Interp::initPython()
00309 {
00310   if (!Py_IsInitialized()){
00311     // Python is not initialized
00312     Py_SetProgramName(_argv[0]);
00313     Py_Initialize(); // Initialize the interpreter
00314     PySys_SetArgv(_argc, _argv);
00315     PyEval_InitThreads(); // Create (and acquire) the interpreter lock
00316   }
00317 
00318   if ( _interp == NULL )
00319     _interp = PyThreadState_Get()->interp;
00320   if (PyType_Ready(&PyStdOut_Type) < 0) {
00321     PyErr_Print();
00322   }
00323   if ( _gtstate == NULL )
00324     _gtstate = PyEval_SaveThread(); // Release global thread state
00325 }
00326 
00331 std::string PyInterp_Interp::getbanner()
00332 {
00333  // Should we take the lock ?
00334  // PyEval_RestoreThread(_tstate);
00335   std::string aBanner("Python ");
00336   aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
00337   aBanner = aBanner + "\ntype help to get general information on environment\n";
00338   //PyEval_SaveThread();
00339   return aBanner;
00340 }
00341 
00350 bool PyInterp_Interp::initRun()
00351 {
00352   // 
00353   // probably all below code isn't required
00354   //
00355   /*
00356   PySys_SetObject("stderr",_verr);
00357   PySys_SetObject("stdout",_vout);
00358 
00359   //PyObject *m = PyImport_GetModuleDict();
00360   
00361   PySys_SetObject("stdout",PySys_GetObject("__stdout__"));
00362   PySys_SetObject("stderr",PySys_GetObject("__stderr__"));
00363   */
00364   return true;
00365 }
00366 
00376 static int compile_command(const char *command,PyObject *context)
00377 {
00378   PyObject *m = PyImport_AddModule("codeop");
00379   if(!m) { // Fatal error. No way to go on.
00380     PyErr_Print();
00381     return -1;
00382   }
00383   PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"s",command));
00384   if(!v) {
00385     // Error encountered. It should be SyntaxError,
00386     //so we don't write out traceback
00387     PyObjWrapper exception, value, tb;
00388     PyErr_Fetch(&exception, &value, &tb);
00389     PyErr_NormalizeException(&exception, &value, &tb);
00390     PyErr_Display(exception, value, NULL);
00391     return -1;
00392   }
00393   else if (v == Py_None) {
00394     // Incomplete text we return 1 : we need a complete text to execute
00395     return 1;
00396   }
00397   else {
00398     // Complete and correct text. We evaluate it.
00399     //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0
00400     //    PyObjWrapper r(PyEval_EvalCode(v,context,context));
00401     //#else
00402     PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context));
00403     //#endif
00404     if(!r) {
00405       // Execution error. We return -1
00406       PyErr_Print();
00407       return -1;
00408     }
00409     // The command has been successfully executed. Return 0
00410     return 0;
00411   }
00412 }
00413 
00419 int PyInterp_Interp::run(const char *command)
00420 {
00421   beforeRun();
00422   return simpleRun(command);
00423 }
00424 
00431 int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory)
00432 {
00433   if( addToHistory && strcmp(command,"") != 0 ) {
00434     _history.push_back(command);
00435     _ith = _history.end();
00436   }
00437 
00438   // We come from C++ to enter Python world
00439   // We need to acquire the Python global lock
00440   //PyLockWrapper aLock(_tstate); // san - lock is centralized now
00441 
00442   // Reset redirected outputs before treatment
00443   PySys_SetObject((char*)"stderr",_verr);
00444   PySys_SetObject((char*)"stdout",_vout);
00445 
00446   int ier = compile_command(command,_g);
00447 
00448   // Outputs are redirected on standards outputs (console)
00449   PySys_SetObject((char*)"stdout",PySys_GetObject((char*)"__stdout__"));
00450   PySys_SetObject((char*)"stderr",PySys_GetObject((char*)"__stderr__"));
00451 
00452   return ier;
00453 }
00454 
00459 const char * PyInterp_Interp::getPrevious()
00460 {
00461   if(_ith != _history.begin()){
00462     _ith--;
00463     return (*_ith).c_str();
00464   }
00465   else
00466     return BEGIN_HISTORY_PY;
00467 }
00468 
00473 const char * PyInterp_Interp::getNext()
00474 {
00475   if(_ith != _history.end()){
00476     _ith++;
00477   }
00478   if (_ith == _history.end())
00479     return TOP_HISTORY_PY;
00480   else
00481     return (*_ith).c_str();
00482 }
00483 
00489 void PyInterp_Interp::setvoutcb(PyOutChanged* cb, void* data)
00490 {  
00491   ((PyStdOut*)_vout)->_cb=cb;
00492   ((PyStdOut*)_vout)->_data=data;
00493 }
00494 
00500 void PyInterp_Interp::setverrcb(PyOutChanged* cb, void* data)
00501 {  
00502   ((PyStdOut*)_verr)->_cb=cb;
00503   ((PyStdOut*)_verr)->_data=data;
00504 }