int main(int argc, char* argv[]) { int returnCode = 0; std::string context; bool alwaysAddContext = true; boost::shared_ptr<edm::Presence> theMessageServicePresence; std::auto_ptr<std::ofstream> jobReportStreamPtr; boost::shared_ptr<edm::serviceregistry::ServiceWrapper<edm::JobReport> > jobRep; EventProcessorWithSentry proc; try { try { // NOTE: MacOs X has a lower rlimit for opened file descriptor than Linux (256 // in Snow Leopard vs 512 in SLC5). This is a problem for some of the workflows // that open many small root datafiles. Notice that this is safe to do also // for Linux, but we agreed not to change the behavior there for the moment. // Also the limits imposed by ulimit are not affected and still apply, if // there. #ifdef __APPLE__ context = "Setting file descriptor limit"; struct rlimit limits; getrlimit(RLIMIT_NOFILE, &limits); limits.rlim_cur = (OPEN_MAX < limits.rlim_max) ? OPEN_MAX : limits.rlim_max; setrlimit(RLIMIT_NOFILE, &limits); #endif context = "Initializing plug-in manager"; edmplugin::PluginManager::configure(edmplugin::standard::config()); // Decide whether to use the multi-thread or single-thread message logger // (Just walk the command-line arguments, since the boost parser will // be run below and can lead to error messages which should be sent via // the message logger) context = "Initializing either multi-threaded or single-threaded message logger"; bool multiThreadML = false; for(int i = 0; i < argc; ++i) { if((std::strncmp (argv[i], "-t", 20) == 0) || (std::strncmp (argv[i], "--multithreadML", 20) == 0)) { multiThreadML = true; break; } } // Load the message service plug-in if(multiThreadML) { theMessageServicePresence = boost::shared_ptr<edm::Presence>(edm::PresenceFactory::get()-> makePresence("MessageServicePresence").release()); } else { theMessageServicePresence = boost::shared_ptr<edm::Presence>(edm::PresenceFactory::get()-> makePresence("SingleThreadMSPresence").release()); } context = "Processing command line arguments"; std::string descString(argv[0]); descString += " [options] [--"; descString += kParameterSetOpt; descString += "] config_file \nAllowed options"; boost::program_options::options_description desc(descString); desc.add_options() (kHelpCommandOpt, "produce help message") (kParameterSetCommandOpt, boost::program_options::value<std::string>(), "configuration file") (kJobreportCommandOpt, boost::program_options::value<std::string>(), "file name to use for a job report file: default extension is .xml") (kEnableJobreportCommandOpt, "enable job report files (if any) specified in configuration file") (kJobModeCommandOpt, boost::program_options::value<std::string>(), "Job Mode for MessageLogger defaults - default mode is grid") (kMultiThreadMessageLoggerOpt, "MessageLogger handles multiple threads - default is single-thread") (kStrictOpt, "strict parsing"); // anything at the end will be ignored, and sent to python boost::program_options::positional_options_description p; p.add(kParameterSetOpt, 1).add(kPythonOpt, -1); // This --fwk option is not used anymore, but I'm leaving it around as // it might be useful again in the future for code development // purposes. We originally used it when implementing the boost // state machine code. boost::program_options::options_description hidden("hidden options"); hidden.add_options()("fwk", "For use only by Framework Developers") (kPythonOpt, boost::program_options::value< std::vector<std::string> >(), "options at the end to be passed to python"); boost::program_options::options_description all_options("All Options"); all_options.add(desc).add(hidden); boost::program_options::variables_map vm; try { store(boost::program_options::command_line_parser(argc, argv).options(all_options).positional(p).run(), vm); notify(vm); } catch (boost::program_options::error const& iException) { edm::LogAbsolute("CommandLineProcessing") << "cmsRun: Error while trying to process command line arguments:\n" << iException.what() << "\nFor usage and an options list, please do 'cmsRun --help'."; return edm::errors::CommandLineProcessing; } if (vm.count(kHelpOpt)) { std::cout << desc << std::endl; if (!vm.count(kParameterSetOpt)) edm::HaltMessageLogging(); return 0; } if (!vm.count(kParameterSetOpt)) { edm::LogAbsolute("ConfigFileNotFound") << "cmsRun: No configuration file given.\n" << "For usage and an options list, please do 'cmsRun --help'."; edm::HaltMessageLogging(); return edm::errors::ConfigFileNotFound; } std::string fileName(vm[kParameterSetOpt].as<std::string>()); if (vm.count(kStrictOpt)) { //edm::setStrictParsing(true); edm::LogSystem("CommandLineProcessing") << "Strict configuration processing is now done from python"; } context = "Creating the JobReport Service"; // Decide whether to enable creation of job report xml file // We do this first so any errors will be reported std::string jobReportFile; if (vm.count("jobreport")) { jobReportFile = vm["jobreport"].as<std::string>(); } else if(vm.count("enablejobreport")) { jobReportFile = "FrameworkJobReport.xml"; } jobReportStreamPtr = std::auto_ptr<std::ofstream>(jobReportFile.empty() ? 0 : new std::ofstream(jobReportFile.c_str())); //NOTE: JobReport must have a lifetime shorter than jobReportStreamPtr so that when the JobReport destructor // is called jobReportStreamPtr is still valid std::auto_ptr<edm::JobReport> jobRepPtr(new edm::JobReport(jobReportStreamPtr.get())); jobRep.reset(new edm::serviceregistry::ServiceWrapper<edm::JobReport>(jobRepPtr)); edm::ServiceToken jobReportToken = edm::ServiceRegistry::createContaining(jobRep); context = "Processing the python configuration file named "; context += fileName; boost::shared_ptr<edm::ProcessDesc> processDesc; try { boost::shared_ptr<edm::ParameterSet> parameterSet = edm::readConfig(fileName, argc, argv); processDesc.reset(new edm::ProcessDesc(parameterSet)); } catch(cms::Exception& iException) { edm::Exception e(edm::errors::ConfigFileReadError, "", iException); throw e; } context = "Initializing default service configurations"; std::vector<std::string> defaultServices; defaultServices.reserve(6); defaultServices.push_back("MessageLogger"); defaultServices.push_back("InitRootHandlers"); #ifdef linux defaultServices.push_back("EnableFloatingPointExceptions"); #endif defaultServices.push_back("UnixSignalService"); defaultServices.push_back("AdaptorConfig"); defaultServices.push_back("SiteLocalConfigService"); // Default parameters will be used for the default services // if they are not overridden from the configuration files. processDesc->addServices(defaultServices); context = "Setting MessageLogger defaults"; // Decide what mode of hardcoded MessageLogger defaults to use if (vm.count("mode")) { std::string jobMode = vm["mode"].as<std::string>(); edm::MessageDrop::instance()->jobMode = jobMode; } context = "Constructing the EventProcessor"; std::auto_ptr<edm::EventProcessor> procP(new edm::EventProcessor(processDesc, jobReportToken, edm::serviceregistry::kTokenOverrides)); EventProcessorWithSentry procTmp(procP); proc = procTmp; alwaysAddContext = false; context = "Calling beginJob"; proc->beginJob(); alwaysAddContext = true; context = "Calling EventProcessor::forkProcess"; if (!proc->forkProcess(jobReportFile)) { return 0; } alwaysAddContext = false; context = "Calling EventProcessor::runToCompletion (which does almost everything after beginJob and before endJob)"; proc.on(); bool onlineStateTransitions = false; edm::EventProcessor::StatusCode status = proc->runToCompletion(onlineStateTransitions); if (status == edm::EventProcessor::epSignal) { returnCode = edm::errors::CaughtSignal; } proc.off(); context = "Calling endJob"; proc->endJob(); } catch (cms::Exception& e) { throw; } // The functions in the following catch blocks throw an edm::Exception catch(std::bad_alloc& bda) { edm::convertException::badAllocToEDM(); } catch (std::exception& e) { edm::convertException::stdToEDM(e); } catch(std::string& s) { edm::convertException::stringToEDM(s); } catch(char const* c) { edm::convertException::charPtrToEDM(c); } catch (...) { edm::convertException::unknownToEDM(); } } // All exceptions which are not handled before propagating // into main will get caught here. catch (cms::Exception& ex) { returnCode = ex.returnCode(); if (!context.empty()) { if (alwaysAddContext) { ex.addContext(context); } else if (ex.context().empty()) { ex.addContext(context); } } if (!ex.alreadyPrinted()) { if (jobRep.get() != 0) { edm::printCmsException(ex, &(jobRep->get()), returnCode); } else { edm::printCmsException(ex); } } } // Disable Root Error Handler. SetErrorHandler(DefaultErrorHandler); return returnCode; }
int main(int argc, char* argv[]) { // NOTE: MacOs X has a lower rlimit for opened file descriptor than Linux (256 // in Snow Leopard vs 512 in SLC5). This is a problem for some of the workflows // that open many small root datafiles. Notice that this is safe to do also // for Linux, but we agreed not to change the behavior there for the moment. // Also the limits imposed by ulimit are not affected and still apply, if // there. #ifdef __APPLE__ struct rlimit limits; getrlimit(RLIMIT_NOFILE, &limits); limits.rlim_cur = (OPEN_MAX < limits.rlim_max) ? OPEN_MAX : limits.rlim_max; setrlimit(RLIMIT_NOFILE, &limits); #endif // We must initialize the plug-in manager first try { edmplugin::PluginManager::configure(edmplugin::standard::config()); } catch(const std::exception& e) { std::cerr << e.what() << std::endl; return 1; } // Decide whether to use the multi-thread or single-thread message logger // (Just walk the command-line arguments, since the boost parser will // be run below and can lead to error messages which should be sent via // the message logger) bool multiThreadML = false; for (int i=0; i<argc; ++i) { if ( (std::strncmp (argv[i],"-t", 20) == 0) || (std::strncmp (argv[i],"--multithreadML", 20) == 0) ) { multiThreadML = true; break; } } // TEMPORARY -- REMOVE AT ONCE!!!!! // if ( multiThreadML ) std::cerr << "\n\n multiThreadML \n\n"; // Load the message service plug-in boost::shared_ptr<edm::Presence> theMessageServicePresence; if (multiThreadML) { try { theMessageServicePresence = boost::shared_ptr<edm::Presence>(edm::PresenceFactory::get()-> makePresence("MessageServicePresence").release()); } catch(cms::Exception& e) { std::cerr << e.what() << std::endl; return 1; } } else { try { theMessageServicePresence = boost::shared_ptr<edm::Presence>(edm::PresenceFactory::get()-> makePresence("SingleThreadMSPresence").release()); } catch(cms::Exception& e) { std::cerr << e.what() << std::endl; return 1; } } // // Specify default services to be enabled with their default parameters. // // The parameters for these can be overridden from the configuration files. std::vector<std::string> defaultServices; defaultServices.reserve(6); defaultServices.push_back("MessageLogger"); defaultServices.push_back("InitRootHandlers"); #ifdef linux defaultServices.push_back("EnableFloatingPointExceptions"); #endif defaultServices.push_back("UnixSignalService"); defaultServices.push_back("AdaptorConfig"); defaultServices.push_back("SiteLocalConfigService"); // These cannot be overridden from the configuration files. // An exception will be thrown if any of these is specified there. std::vector<std::string> forcedServices; forcedServices.reserve(1); forcedServices.push_back("JobReportService"); std::string descString(argv[0]); descString += " [options] [--"; descString += kParameterSetOpt; descString += "] config_file \nAllowed options"; boost::program_options::options_description desc(descString); desc.add_options() (kHelpCommandOpt, "produce help message") (kParameterSetCommandOpt, boost::program_options::value<std::string>(), "configuration file") (kJobreportCommandOpt, boost::program_options::value<std::string>(), "file name to use for a job report file: default extension is .xml") (kEnableJobreportCommandOpt, "enable job report files (if any) specified in configuration file") (kJobModeCommandOpt, boost::program_options::value<std::string>(), "Job Mode for MessageLogger defaults - default mode is grid") (kMultiThreadMessageLoggerOpt, "MessageLogger handles multiple threads - default is single-thread") (kStrictOpt, "strict parsing"); // anything at the end will be ignored, and sent to python boost::program_options::positional_options_description p; p.add(kParameterSetOpt, 1).add(kPythonOpt, -1); // This --fwk option is not used anymore, but I'm leaving it around as // it might be useful again in the future for code development // purposes. We originally used it when implementing the boost // state machine code. boost::program_options::options_description hidden("hidden options"); hidden.add_options()("fwk", "For use only by Framework Developers") (kPythonOpt, boost::program_options::value< std::vector<std::string> >(), "options at the end to be passed to python"); boost::program_options::options_description all_options("All Options"); all_options.add(desc).add(hidden); boost::program_options::variables_map vm; try { store(boost::program_options::command_line_parser(argc,argv).options(all_options).positional(p).run(),vm); notify(vm); } catch(boost::program_options::error const& iException) { edm::LogError("FwkJob") << "Exception from command line processing: " << iException.what(); edm::LogSystem("CommandLineProcessing") << "Exception from command line processing: " << iException.what() << "\n"; return 7000; } if(vm.count(kHelpOpt)) { std::cout << desc <<std::endl; if(!vm.count(kParameterSetOpt)) edm::HaltMessageLogging(); return 0; } if(!vm.count(kParameterSetOpt)) { std::string shortDesc("ConfigFileNotFound"); std::ostringstream longDesc; longDesc << "cmsRun: No configuration file given.\n" << "For usage and an options list, please do '" << argv[0] << " --" << kHelpOpt << "'."; int exitCode = 7001; edm::LogAbsolute(shortDesc) << longDesc.str() << "\n"; edm::HaltMessageLogging(); return exitCode; } #ifdef CHANGED_FROM if(!vm.count(kParameterSetOpt)) { std::string shortDesc("ConfigFileNotFound"); std::ostringstream longDesc; longDesc << "No configuration file given \n" <<" please do '" << argv[0] << " --" << kHelpOpt << "'."; int exitCode = 7001; jobRep->reportError(shortDesc, longDesc.str(), exitCode); edm::LogSystem(shortDesc) << longDesc.str() << "\n"; return exitCode; } #endif // // Decide whether to enable creation of job report xml file // We do this first so any errors will be reported // std::string jobReportFile; if (vm.count("jobreport")) { jobReportFile = vm["jobreport"].as<std::string>(); } else if (vm.count("enablejobreport")) { jobReportFile = "FrameworkJobReport.xml"; } std::auto_ptr<std::ofstream> jobReportStreamPtr = std::auto_ptr<std::ofstream>(jobReportFile.empty() ? 0 : new std::ofstream(jobReportFile.c_str())); // // Make JobReport Service up front // //NOTE: JobReport must have a lifetime shorter than jobReportStreamPtr so that when the JobReport destructor // is called jobReportStreamPtr is still valid std::auto_ptr<edm::JobReport> jobRepPtr(new edm::JobReport(jobReportStreamPtr.get())); boost::shared_ptr<edm::serviceregistry::ServiceWrapper<edm::JobReport> > jobRep( new edm::serviceregistry::ServiceWrapper<edm::JobReport>(jobRepPtr) ); edm::ServiceToken jobReportToken = edm::ServiceRegistry::createContaining(jobRep); std::string fileName(vm[kParameterSetOpt].as<std::string>()); boost::shared_ptr<edm::ProcessDesc> processDesc; try { processDesc = edm::readConfig(fileName, argc, argv); } catch(cms::Exception& iException) { std::string shortDesc("ConfigFileReadError"); std::ostringstream longDesc; longDesc << "Problem with configuration file " << fileName << "\n" << iException.what(); int exitCode = 7002; jobRep->get().reportError(shortDesc, longDesc.str(), exitCode); edm::LogSystem(shortDesc) << longDesc.str() << "\n"; return exitCode; } processDesc->addServices(defaultServices, forcedServices); // // Decide what mode of hardcoded MessageLogger defaults to use // if (vm.count("mode")) { std::string jobMode = vm["mode"].as<std::string>(); edm::MessageDrop::instance()->jobMode = jobMode; } if(vm.count(kStrictOpt)) { //edm::setStrictParsing(true); edm::LogSystem("CommandLineProcessing") << "Strict configuration processing is now done from python"; } // Now create and configure the services // EventProcessorWithSentry proc; int rc = -1; // we should never return this value! try { std::auto_ptr<edm::EventProcessor> procP(new edm::EventProcessor(processDesc, jobReportToken, edm::serviceregistry::kTokenOverrides)); EventProcessorWithSentry procTmp(procP); proc = procTmp; proc->beginJob(); if(!proc->forkProcess(jobReportFile)) { return 0; } proc.on(); bool onlineStateTransitions = false; proc->runToCompletion(onlineStateTransitions); proc.off(); proc->endJob(); rc = 0; // Disable Root Error Handler so we do not throw because of ROOT errors. edm::ServiceToken token = proc->getToken(); edm::ServiceRegistry::Operate operate(token); edm::Service<edm::RootHandlers> rootHandler; rootHandler->disableErrorHandler(); } catch (edm::Exception& e) { rc = e.returnCode(); edm::printCmsException(e, kProgramName, &(jobRep->get()), rc); } catch (cms::Exception& e) { rc = 8001; edm::printCmsException(e, kProgramName, &(jobRep->get()), rc); } catch(std::bad_alloc& bda) { rc = 8004; edm::printBadAllocException(kProgramName, &(jobRep->get()), rc); } catch (std::exception& e) { rc = 8002; edm::printStdException(e, kProgramName, &(jobRep->get()), rc); } catch (...) { rc = 8003; edm::printUnknownException(kProgramName, &(jobRep->get()), rc); } // Disable Root Error Handler again, just in case an exception // caused the above disabling of the handler to be bypassed. SetErrorHandler(DefaultErrorHandler); return rc; }