OpenWalnut
1.4.0
|
00001 //--------------------------------------------------------------------------- 00002 // 00003 // Project: OpenWalnut ( http://www.openwalnut.org ) 00004 // 00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS 00006 // For more information see http://www.openwalnut.org/copying 00007 // 00008 // This file is part of OpenWalnut. 00009 // 00010 // OpenWalnut is free software: you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as published by 00012 // the Free Software Foundation, either version 3 of the License, or 00013 // (at your option) any later version. 00014 // 00015 // OpenWalnut is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 // GNU Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public License 00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>. 00022 // 00023 //--------------------------------------------------------------------------- 00024 00025 #include <fstream> 00026 #include <string> 00027 #include <vector> 00028 00029 #include "core/kernel/WKernel.h" 00030 00031 #include "../wrappers/WLoggerWrapper.h" 00032 #include "../wrappers/WModuleWrapper.h" 00033 #include "../wrappers/WPropertyGroupWrapper.h" 00034 #include "../wrappers/WPropertyWrapper.h" 00035 00036 #include "WScriptInterpreterPython.h" 00037 00038 #ifdef PYTHON_FOUND 00039 00040 WScriptInterpreterPython::WScriptInterpreterPython( boost::shared_ptr< WModuleContainer > const& rootContainer ) 00041 : WScriptInterpreter(), 00042 m_rootContainer( rootContainer ), 00043 m_argc( 0 ), 00044 m_argv( 0 ), 00045 m_scriptThread( *this ) 00046 { 00047 try 00048 { 00049 Py_Initialize(); 00050 m_pyModule = pb::import( "__main__" ); 00051 m_pyMainNamespace = m_pyModule.attr( "__dict__" ); 00052 } 00053 catch( pb::error_already_set const& ) 00054 { 00055 PyErr_Print(); 00056 } 00057 // Make ctrl+c key available for killing interpeter 00058 execute( "import signal" ); 00059 execute( "signal.signal( signal.SIGINT, signal.SIG_DFL )" ); 00060 00061 m_scriptThread.run(); 00062 } 00063 00064 WScriptInterpreterPython::~WScriptInterpreterPython() 00065 { 00066 m_scriptThread.requestStop(); 00067 m_scriptThread.wait(); 00068 00069 Py_Finalize(); 00070 00071 if( m_argv ) 00072 { 00073 for( int k = 0; k < m_argc; ++k ) 00074 { 00075 delete[] m_argv[ k ]; 00076 } 00077 delete[] m_argv; 00078 } 00079 } 00080 00081 void WScriptInterpreterPython::initBindings() 00082 { 00083 boost::unique_lock< boost::mutex > lock( m_mutex ); 00084 00085 // bind WPropertyWrapper class to "WProperty" in the python namespace 00086 // no constructor in python for now 00087 m_pyMainNamespace[ "WProperty" ] = pb::class_< WPropertyWrapper >( "WProperty", pb::no_init ) 00088 .def( "getBool", &WPropertyWrapper::getBool ) 00089 .def( "getInt", &WPropertyWrapper::getInt ) 00090 .def( "getString", &WPropertyWrapper::getString ) 00091 .def( "getDouble", &WPropertyWrapper::getDouble ) 00092 .def( "getFilename", &WPropertyWrapper::getFilename ) 00093 .def( "getSelection", &WPropertyWrapper::getSelection ) 00094 .def( "setBool", &WPropertyWrapper::setBool ) 00095 .def( "setInt", &WPropertyWrapper::setInt ) 00096 .def( "setString", &WPropertyWrapper::setString ) 00097 .def( "setDouble", &WPropertyWrapper::setDouble ) 00098 .def( "setFilename", &WPropertyWrapper::setFilename ) 00099 .def( "setSelection", &WPropertyWrapper::setSelection ) 00100 .def( "click", &WPropertyWrapper::click ) 00101 .def( "getName", &WPropertyWrapper::getName ) 00102 .def( "getDescription", &WPropertyWrapper::getDescription ) 00103 .def( "waitForUpdate", &WPropertyWrapper::waitForUpdate ); 00104 00105 m_pyMainNamespace[ "WPropertyGroup" ] = pb::class_< WPropertyGroupWrapper >( "WPropertyGroup", pb::no_init ) 00106 .def( "getProperty", &WPropertyGroupWrapper::getProperty ) 00107 .def( "getGroup", &WPropertyGroupWrapper::getGroup ) 00108 .def( "getName", &WPropertyGroupWrapper::getName ) 00109 .def( "getDescription", &WPropertyGroupWrapper::getDescription ); 00110 00111 m_pyMainNamespace[ "WModuleContainer" ] = pb::class_< WModuleContainerWrapper >( "WModuleContainer", pb::no_init ) 00112 .def( "create", &WModuleContainerWrapper::create ) 00113 .def( "remove", &WModuleContainerWrapper::remove ) 00114 .def( "createDataModule", &WModuleContainerWrapper::createDataModule ); 00115 00116 m_pyMainNamespace[ "WOutputConnector" ] = pb::class_< WOutputConnectorWrapper >( "WOutputConnectorWrapper", pb::no_init ) 00117 .def( "disconnect", &WOutputConnectorWrapper::disconnect ); 00118 00119 m_pyMainNamespace[ "WInputConnector" ] = pb::class_< WInputConnectorWrapper >( "WInputConnectorWrapper", pb::no_init ) 00120 .def( "connect", &WInputConnectorWrapper::connect ) 00121 .def( "disconnect", &WInputConnectorWrapper::disconnect ) 00122 .def( "waitForInput", &WInputConnectorWrapper::waitForInput ); 00123 00124 m_pyMainNamespace[ "WModule" ] = pb::class_< WModuleWrapper >( "WModule", pb::no_init ) 00125 .def( "getName", &WModuleWrapper::getName ) 00126 .def( "getDescription", &WModuleWrapper::getDescription ) 00127 .def( "getProperties", &WModuleWrapper::getProperties ) 00128 .def( "getInformationProperties", &WModuleWrapper::getInformationProperties ) 00129 .def( "getInputConnector", &WModuleWrapper::getInputConnector ) 00130 .def( "getOutputConnector", &WModuleWrapper::getOutputConnector ); 00131 00132 // bind the kernel's root container to the "rootContainer" variable in the python namespace 00133 // this allows access to the modules via this variable 00134 m_pyMainNamespace[ "rootContainer" ] = &m_rootContainer; 00135 00136 m_pyMainNamespace[ "WLogger" ] = pb::class_< WLoggerWrapper >( "WLogger", pb::no_init ) 00137 .def( "addFileStream", &WLoggerWrapper::addFileStream ) 00138 .def( "removeFileStream", &WLoggerWrapper::removeFileStream ) 00139 .def( "removeAllFileStreams", &WLoggerWrapper::removeAllFileStreams ); 00140 00141 m_logger = WLoggerWrapper( WLogger::getLogger() ); 00142 m_pyMainNamespace[ "logger" ] = &m_logger; 00143 } 00144 00145 void WScriptInterpreterPython::setParameters( std::vector< std::string > const& params ) 00146 { 00147 boost::unique_lock< boost::mutex > lock( m_mutex ); 00148 00149 if( params.size() == 0 ) 00150 { 00151 return; 00152 } 00153 00154 m_argc = params.size(); 00155 m_argv = new char*[ params.size() ]; 00156 00157 for( std::size_t k = 0; k < params.size(); ++k ) 00158 { 00159 m_argv[ k ] = new char[ params[ k ].length() + 1 ]; 00160 std::snprintf( m_argv[ k ], params[ k ].length() + 1, "%s", params[ k ].c_str() ); 00161 m_argv[ k ][ params[ k ].length() ] = '\0'; 00162 } 00163 00164 PySys_SetArgv( m_argc, m_argv ); 00165 } 00166 00167 void WScriptInterpreterPython::execute( std::string const& line ) 00168 { 00169 boost::unique_lock< boost::mutex > lock( m_mutex ); 00170 00171 try 00172 { 00173 pb::exec( line.c_str(), m_pyMainNamespace ); 00174 } 00175 catch( pb::error_already_set const& ) 00176 { 00177 PyErr_Print(); 00178 } 00179 } 00180 00181 void WScriptInterpreterPython::executeAsync( std::string const& script ) 00182 { 00183 m_scriptThread.addToExecuteQueue( script ); 00184 } 00185 00186 void WScriptInterpreterPython::executeFile( std::string const& filename ) 00187 { 00188 // load file content into string 00189 std::ifstream in( filename.c_str() ); 00190 std::string script; 00191 std::string line; 00192 while( std::getline( in, line ) ) 00193 { 00194 script += line + "\n"; 00195 } 00196 in.close(); 00197 00198 // execute 00199 try 00200 { 00201 execute( script ); 00202 } 00203 catch( WException const& e ) 00204 { 00205 wlog::error( "Walnut" ) << "Error while executing script: " << e.what(); 00206 } 00207 } 00208 00209 void WScriptInterpreterPython::executeFileAsync( std::string const& filename ) 00210 { 00211 // load file content into string 00212 std::ifstream in( filename.c_str() ); 00213 std::string script; 00214 std::string line; 00215 while( std::getline( in, line ) ) 00216 { 00217 script += line + "\n"; 00218 } 00219 in.close(); 00220 00221 // execute 00222 executeAsync( script ); 00223 } 00224 00225 std::string const WScriptInterpreterPython::getName() const 00226 { 00227 return "python"; 00228 } 00229 00230 std::string const WScriptInterpreterPython::getExtension() const 00231 { 00232 return ".py"; 00233 } 00234 00235 WScriptInterpreterPython::ScriptThread::ScriptThread( WScriptInterpreterPython& interpreter ) // NOLINT reference 00236 : WThreadedRunner(), 00237 m_scriptQueue(), 00238 m_queueMutex(), 00239 m_condition( new WCondition() ), 00240 m_conditionSet(), 00241 m_interpreter( interpreter ) 00242 { 00243 m_conditionSet.setResetable( true, true ); 00244 m_conditionSet.add( m_condition ); 00245 } 00246 00247 WScriptInterpreterPython::ScriptThread::~ScriptThread() 00248 { 00249 } 00250 00251 void WScriptInterpreterPython::ScriptThread::requestStop() 00252 { 00253 WThreadedRunner::requestStop(); 00254 m_condition->notify(); 00255 } 00256 00257 void WScriptInterpreterPython::ScriptThread::threadMain() 00258 { 00259 while( !m_shutdownFlag ) 00260 { 00261 m_conditionSet.wait(); 00262 00263 if( m_shutdownFlag ) 00264 break; 00265 00266 std::size_t numScripts = 0; 00267 { 00268 boost::unique_lock< boost::mutex > lock( m_queueMutex ); 00269 numScripts = m_scriptQueue.size(); 00270 } 00271 00272 while( numScripts > 0 ) 00273 { 00274 std::string script; 00275 00276 // only getting the script content must be locked 00277 { 00278 boost::unique_lock< boost::mutex > lock( m_queueMutex ); 00279 script = m_scriptQueue.front(); 00280 m_scriptQueue.pop(); 00281 } 00282 00283 if( script.length() != 0 ) 00284 { 00285 wlog::info( "WScriptInterpreterPython::ScriptThread" ) << "Executing script asyncronously."; 00286 // note that this may block if the interpreter is currently executing another script 00287 m_interpreter.execute( script ); 00288 wlog::info( "WScriptInterpreterPython::ScriptThread" ) << "Done executing script."; 00289 } 00290 { 00291 boost::unique_lock< boost::mutex > lock( m_queueMutex ); 00292 numScripts = m_scriptQueue.size(); 00293 } 00294 } 00295 } 00296 } 00297 00298 void WScriptInterpreterPython::ScriptThread::addToExecuteQueue( std::string const& script ) 00299 { 00300 wlog::info( "WScriptInterpreterPython::ScriptThread" ) << "Queueing script for asyncronous execution."; 00301 00302 boost::unique_lock< boost::mutex > lock( m_queueMutex ); 00303 m_scriptQueue.push( script ); 00304 m_condition->notify(); 00305 } 00306 00307 #endif // PYTHON_FOUND