/* * ProcessStandard.cc * * Created on: Oct 31, 2012 * Author: f.casimir */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DicError.hh" #include "Helper.hh" #include "Parameter.hh" #include "Operation.hh" #include "ParamData.hh" #include "DataTypeMath.hh" #include "ServicesServer.hh" #include "DataWriter.hh" #include "ParameterManager.hh" #include "ProcessStandard.hh" using namespace std; using namespace boost; using namespace log4cxx; namespace AMDA { namespace Parameters { ProcessStandard::ProcessStandard(Parameter & parameter) : MultiParamProcess_CRTP(parameter), _fct(""), _symboleName("processFct"), _handle(NULL), _processInit(NULL), _compilVersion(NULL), _accesDirect(false), _alreadyParsed(false), _propertiesList("app.properties"), _timeOfSoFile(0) { _servicesServer = ServicesServer::getInstance(); } ProcessStandard::ProcessStandard(const ProcessStandard & pProcess, Parameter ¶meter) : MultiParamProcess_CRTP(pProcess,parameter), _fct(pProcess._fct), _symboleName(pProcess._symboleName), _handle(pProcess._handle), _processInit(pProcess._processInit), _compilVersion(pProcess._compilVersion), _accesDirect(pProcess._accesDirect), _alreadyParsed(pProcess._alreadyParsed), _propertiesList(pProcess._propertiesList), _timeOfSoFile(pProcess._timeOfSoFile) { _servicesServer = ServicesServer::getInstance(); establishConnection(); } ProcessStandard::~ProcessStandard() { this->_paramData.reset(); delete _operation; _operation = NULL; closeDynamicLib(); //Attention au mémoire allouer par cette lib } void ProcessStandard::establishConnection() { if ( ! _expression.empty()) { parse(); MultiParamProcess::establishConnection(); } } TimeStamp ProcessStandard::init() { _fileNameRoot = _parameter.getId(); size_t index = _fileNameRoot.find('/'); if(index != string::npos) { _fileNameRoot.at(index) = '_'; } std::string soDir; if (isUserProcess() && !_propertiesList["app.process.userlib"].empty()) { soDir = _propertiesList["app.process.userlib"]; } else { soDir = _propertiesList["app.process.lib"]; } if (soDir.empty() || (AMDA::Helpers::Helper::mkdir(soDir.c_str()) != 0)) { BOOST_THROW_EXCEPTION(Process_exception() << AMDA::errno_code(AMDA_PROCESS_ERR) << AMDA::ex_msg(std::string("ProcessStandard::init - Cannot create detination lib dir"))); } _fileNameSO = soDir + "/" + _fileNameRoot + ".so"; TimeStamp time = MultiParamProcess::init(); if(mustGenerated(time)) { generateCppfile(); time = generateSoFile(); } loadDynamicLib(); if ((_compilVersion == NULL) || ((*_compilVersion)() != PROCESS_STANDARD_COMPIL_VERSION)) { closeDynamicLib(); generateCppfile(); time = generateSoFile(); loadDynamicLib(); } // Create Operation && ParamData (*_processInit)(this); _paramData->setMinSampling(_minSampling); ParameterManager& lParameterManager = _parameter.getParameterManager(); double minGapSize = NAN; for (auto param : _paramNameList) { ParameterSPtr& parameter = param.second.first; double crtGapSize = lParameterManager.getComputedGapSize(parameter->getGapThreshold(),parameter->getDataWriterTemplate()->getMinSampling()); if (isNAN(minGapSize) || (crtGapSize < minGapSize)) minGapSize = crtGapSize; } if (!isNAN(minGapSize)) { double computedGapThreshold = minGapSize / _minSampling; _parameter.setGapThreshold(computedGapThreshold); } return time; } double ProcessStandard::getMinSampling() { if ( ! _expression.empty()) parse(); return MultiParamProcess_CRTP::getMinSampling(); } #define MIN(a,b) (((a) < (b)) ? (a) :(b) ) void ProcessStandard::parse() { if (_alreadyParsed) return; ParameterManager& lParameterManager = _parameter.getParameterManager(); _parser.process(_expression); const Parser::ListParameterName& lParameterNameList = _parser.getListParameterName(); // Temporary Parameter creation const Parser::ListProcessName& processNameList = _parser.getListProcessName(); Parser::ListProcessName::const_iterator lProcessIt = processNameList.begin(); for (;lProcessIt!=processNameList.end();++lProcessIt) { ParameterSPtr lParameter; if ( lParameterManager.addParameter(&_parameter,lProcessIt->first,lParameter)) { Process* lProcess = _servicesServer->getProcess(lProcessIt->second.name,*lParameter.get()); if ( lProcess) { lProcess->setExpression(lProcessIt->second.expression); lProcess->setAttributList(lProcessIt->second.attribut); lProcess->setIsUserProcess(isUserProcess()); boost::shared_ptr dataWriter = boost::shared_ptr(static_cast(lProcess)); lParameter->setDataWriter(dataWriter); _paramNameList[lProcessIt->first].first = lParameterManager.getParameter(lProcessIt->first); } else { stringstream lError; lError << "Process: '" << lProcessIt->second.name << "' not found"; LOG4CXX_ERROR(_logger, lError.str()); BOOST_THROW_EXCEPTION(Process_exception() << AMDA::errno_code(AMDA_PROCESS_ERR) << AMDA::ex_msg(lError.str())); } } else { _paramNameList[lProcessIt->first].first = lParameterManager.getParameter(lProcessIt->first); } } for (Parser::ListParameterName::const_iterator it = lParameterNameList.begin(); it != lParameterNameList.end(); ++it) { ParameterSPtr lParameter = lParameterManager.getParameter(*it); if (lParameter.get()) { _paramNameList[*it].first = lParameter; // Here we have a broken link in parameter chaining so create link. // Child is already creating before linking it to its parent parameter. _parameter.addParameter(lParameter); } else { LOG4CXX_ERROR(_logger, "parse of expression: \""<<_expression << "\" are impossible!"); BOOST_THROW_EXCEPTION(Process_exception() << AMDA::errno_code(AMDA_PROCESS_ERR) << AMDA::ex_msg(std::string("Error to parse expression: ")+_expression)); } } _alreadyParsed = true; } bool ProcessStandard::findInclude(std::string name, std::string &path, std::vector &listSo) { path = this->_propertiesList["app.plugin"] + "/" + name; bool find = false; if (AMDA::Helpers::Helper::getMatchFiles(path.c_str(), listSo, ".*.(so|a)$") == 0) { find = true; } return find; } bool ProcessStandard::mustGenerated(TimeStamp timeDepend) { bool recompile = false; if(_timeOfSoFile == 0) { if(_signatureTrigger != "") { // _signatureTrigger must be a name of xml parameter file timeDepend = std::max(TimeStamp(AMDA::Helpers::Helper::dateOfFile(_signatureTrigger.c_str())), timeDepend) ; } for(Parser::ListFctName::iterator it = _parser.getListFctName().begin(); it != _parser.getListFctName().end(); ++it) { std::string path; SoList listLib; if(findInclude(*it, path, listLib)) { string includePath = path +"/" + *it; timeDepend = std::max(timeDepend, TimeStamp(AMDA::Helpers::Helper::dateOfFile((includePath + ".hh").c_str()))); _streamIncludeFile << "#include \""<< *it <<".hh\" "; _streamIncludeFile << endl; _PluginList[path] = listLib; } } //return 0 if file not exist _timeOfSoFile = AMDA::Helpers::Helper::dateOfFile(_fileNameSO.c_str()); recompile = (_timeOfSoFile <= timeDepend); } return recompile; } void ProcessStandard::generateCppfile() { LOG4CXX_INFO(_logger, "generation of compilation expression: " << _parser.getFormulaCc()) size_t bufSize = _propertiesList["app.process.src"].size() + _fileNameRoot.size() + 8; char *buf = new char[bufSize]; strcpy(buf, (_propertiesList["app.process.src"] + "/" + _fileNameRoot).c_str()); strcat(buf, "XXXXXX"); _workingDiretory = mkdtemp(buf); delete[] buf; _fileNameC =_workingDiretory + "/" + _fileNameRoot + ".cc"; fstream fileC(_fileNameC.c_str(), ios_base::out); fileC << " /* File generated by AMDA */ " << endl; // Include fileC << "#include \"Operation.hh\" " << endl; fileC << "#include \"ServicesServer.hh\" " << endl; fileC << "#include \"Parameter.hh\"" << endl; fileC << "#include \"ParamData.hh\"" << endl; fileC << "#include \"DataTypeMath.hh\"" << endl; fileC << "#include \"ProcessStandard.hh\"" << endl; fileC << endl; fileC << "#include \"TimeInterval.hh\"" << endl; fileC << endl; fileC << "#include \"AMDA_constants.hh\"" << endl; fileC << endl; fileC << endl; fileC.flush(); fileC << _streamIncludeFile.str(); fileC << endl; fileC << endl; fileC << "#define PROCESS_STANDARD_COMPIL_VERSION " << PROCESS_STANDARD_COMPIL_VERSION << endl; fileC << endl; fileC << endl; for (ParameterList::iterator it = _paramNameList.begin(); it != _paramNameList.end(); ++it) { ParamDataSPtr p = it->second.first->getParamData(this); string lParamTypeName = " _T_" + boost::to_upper_copy(it->first) ; string lElementTypeName = lParamTypeName + "_Element_Type"; fileC << "typedef "<< p->getElementType() << " " << lElementTypeName <<";"; fileC << endl; fileC << "typedef "<< p->getParamDataType() << " " << lParamTypeName <<";"; fileC << endl; } fileC.flush(); // Process Init Signature stringstream lProcessInit; lProcessInit << "void processInit(AMDA::Parameters::ProcessStandard *pProcess)"; fileC << "extern \"C\" " << lProcessInit.str() << ";" ; fileC << endl; fileC << "extern \"C\" int compilVersion();" << endl; fileC << endl; fileC << endl; //Declaration Calss fileC << "template " << endl; ParameterManager& lParameterManager = this->_parameter.getParameterManager(); std::string fixedParamId = this->_parameter.getId(); lParameterManager.applyParamIdCorrection(fixedParamId); string lClassName = "_Operation" + fixedParamId; fileC << "class " <first << " = dynamic_cast<_T_"<< boost::to_upper_copy(it->first)<< "*>( pProcess.getParameterList()[\""<< it->first << "\"].first->getParamData(&pProcess).get());"; fileC << endl; } fileC << "}" << endl; fileC << endl; fileC.flush(); //Destructor fileC << "virtual ~" <pushTime(_processStandard.getParameterList().begin()->second.first->getParamData(&_process)->getTime(index));" << endl; fileC << " _paramOutput->push("<< _parser.getFormulaCc() <<");"; fileC << endl; fileC << " }" << endl; fileC << "}" << endl; fileC << endl; //attributs fileC << "AMDA::Parameters::ProcessStandard& _processStandard;" << endl; fileC << "TParamData *_paramOutput;" << endl; fileC << "AMDA::Parameters::ParamDataIndexInfo _paramDataIndexInfo;" << endl; fileC.flush(); for (ParameterList::iterator it = _paramNameList.begin(); it != _paramNameList.end(); ++it) { ParamDataSPtr p = it->second.first->getParamData(this); fileC << " _T_" + boost::to_upper_copy(it->first) <<" *" << it->first <<";" << endl; } fileC << endl; //fin class fileC << "};" << endl; fileC << lProcessInit.str() << "{"<< endl; fileC << " typedef decltype(AMDA::Parameters::generate(" << _parser.getContructorCc() <<")) _Generated_Type;" << endl; fileC << " pProcess->setOperation(new " << lClassName<<"<_Generated_Type>(*pProcess));" ; fileC << endl; fileC << " pProcess->getParamData().reset( pProcess->getOperation()->getParamOutput());" << endl; fileC << "}" << endl; fileC << endl; fileC << "int compilVersion() {"<< endl; fileC << " return PROCESS_STANDARD_COMPIL_VERSION;"<< endl; fileC << "}" << endl; fileC << endl; fileC.close(); } TimeStamp ProcessStandard::generateSoFile() { string pathInclude; string pathlib; string fileNameSOTmp = _workingDiretory + "/" + _fileNameRoot + ".so"; for(PluginList::iterator it =_PluginList.begin() ; it != _PluginList.end(); ++it) { pathInclude += " -I" +it->first; pathlib += " -L"+it->first; pathlib += " -Wl,-rpath,"+it->first; for(SoList::iterator itlib =it->second.begin() ; itlib != it->second.end(); ++itlib) { //pathlib = string(pwd) + "/" + it->first + "/" + *itlib; string name = *itlib; unsigned int posLastPoint = name.rfind('.'); string rootLib = itlib->substr(3, posLastPoint - 3); pathlib += " -l"+rootLib; } } string command = _propertiesList["app.process.CXX_COMPILER"] //+ "-DParameters_EXPORTS" + + " " + _propertiesList["app.process.CMAKE_CXX_FLAGS"] + " " + _propertiesList["app.process.INCLUDE"] + " " + pathInclude + " " + _propertiesList["app.process.LIB"] + " " + pathlib + " -shared -Wl,-soname," + fileNameSOTmp + " -o " + fileNameSOTmp + " " + _fileNameC; if(AMDA::Helpers::Helper::SystemCommand(command, _logger)) { BOOST_THROW_EXCEPTION(Process_exception() << AMDA::errno_code(AMDA_PROCESS_ERR) << AMDA::ex_msg(std::string("Error to parse expression: ")+_expression)); } //move file int status = rename(fileNameSOTmp.c_str(), _fileNameSO.c_str()); if(status != 0) { LOG4CXX_ERROR(_logger, "rename of : " << fileNameSOTmp << " in " << _fileNameSO <<" End with an error " << WTERMSIG(status)); BOOST_THROW_EXCEPTION(Process_exception() << AMDA::errno_code(AMDA_PROCESS_ERR) << AMDA::ex_msg("rename of : " + fileNameSOTmp + " in " + _fileNameSO + " End with an error ")); } //if not Debug environment const char* lBuildType=getenv("BUILD_TYPE"); if(lBuildType && strcmp(lBuildType, "Debug")) { status = unlink(_fileNameC.c_str()); if(_workingDiretory != ".") { status += rmdir(_workingDiretory.c_str()); } if(status != 0) { LOG4CXX_WARN(_logger, "Suppression of temporary files: " << _fileNameC <<" End with an error " << WTERMSIG(status)); } } return AMDA::Helpers::Helper::dateOfFile(_fileNameSO.c_str()); } //std::string ProcessStandard::_env(getenv("LD_LIBRARY_PATH")); void ProcessStandard::loadDynamicLib() { std::string lLib = _fileNameSO; // /*set LD_LIBRARY_PATH */ // string lLD_LIBRARY_PATH = "LD_LIBRARY_PATH="; // for(PluginList::iterator it =_PluginList.begin() ; it != _PluginList.end(); ++it) { // lLD_LIBRARY_PATH += it->first + ":"; // } // lLD_LIBRARY_PATH += _env; // LOG4CXX_INFO(_logger, "add in environment: " << lLD_LIBRARY_PATH); // putenv(const_cast( lLD_LIBRARY_PATH.c_str())); _handle = dlopen(lLib.c_str(), RTLD_LAZY); if (!_handle) { LOG4CXX_ERROR(_logger,dlerror()); BOOST_THROW_EXCEPTION(Process_exception() << AMDA::errno_code(AMDA_PROCESS_ERR) << AMDA::ex_msg(std::string("Error to parse expression: ")+_expression)); } dlerror(); /* Clear any existing error */ *(void **) (&_processInit) = dlsym(_handle, "processInit"); char *error = dlerror(); if (error != NULL) { LOG4CXX_ERROR(_logger,error); BOOST_THROW_EXCEPTION(Process_exception() << AMDA::errno_code(AMDA_PROCESS_ERR) << AMDA::ex_msg(std::string("Error to parse expression: ")+_expression)); } dlerror(); /* Clear any existing error */ *(void **) (&_compilVersion) = dlsym(_handle, "compilVersion"); error = dlerror(); if (error != NULL) { LOG4CXX_WARN(_logger,error); } } void ProcessStandard::closeDynamicLib() { if(_handle) dlclose(_handle); } } /* namespace Parameters */ } /* namespace AMDA */