44 #include <Ice/Communicator.h>
45 #include <Ice/Initialize.h>
46 #include <Ice/LocalException.h>
47 #include <Ice/NativePropertiesAdmin.h>
48 #include <Ice/ObjectF.h>
49 #include <Ice/Process.h>
50 #include <Ice/Properties.h>
51 #include <Ice/Properties.h>
52 #include <Ice/PropertiesAdmin.h>
53 #include <Ice/PropertiesAdmin.h>
54 #include <IceUtil/Time.h>
56 #include <SimoxUtility/algorithm/string/string_tools.h>
71 #include "ArmarXCore/interface/core/Log.h"
72 #include "ArmarXCore/interface/core/Profiler.h"
77 #include "../logging/ArmarXLogBuf.h"
99 std::mutex Application::instanceMutex;
101 Ice::StringSeq Application::ProjectDependendencies;
102 std::string Application::ProjectName;
104 std::string
errormsg =
"Segmentation fault - Backtrace: \n";
120 std::array<void*, 20> array;
122 size = backtrace(array.data(), 20);
124 #pragma GCC diagnostic push
125 #pragma GCC diagnostic ignored "-Wunused-result"
127 #pragma GCC diagnostic pop
128 backtrace_symbols_fd(array.data(), size, STDERR_FILENO);
132 std::stringstream
str;
136 str <<
"Error: Abort\nBacktrace:\n";
140 str <<
"Error: signal " << sig;
153 s <<
"qtcreator -debug " << getpid();
155 res = system(
s.str().c_str());
167 Application::loadLibrariesFromProperties()
169 auto loadLibString = getProperty<std::string>(
"LoadLibraries").getValue();
170 if (!loadLibString.empty())
172 if (!libLoadingEnabled)
174 throw LocalException(
"Loading of dynamic libraries is not enabled in this application. "
175 "The Application needs to call enableLibLoading()");
177 auto entries =
armarx::Split(loadLibString,
";",
true,
true);
178 for (
auto& entry : entries)
182 std::filesystem::path path;
189 auto elements =
Split(entry,
":");
191 std::string libFileName =
"lib" + elements.at(1) +
"." +
196 std::filesystem::path testPath(libDir);
197 testPath /= libFileName;
198 if (std::filesystem::exists(testPath))
207 <<
"' in any of the following paths: " << p.getLibraryPaths();
228 return forbidThreadCreation;
234 forbidThreadCreation =
value;
235 if (forbidThreadCreation)
237 ARMARX_INFO <<
"Thread creation with RunningTask and PeriodicTask is now forbidden in this "
242 ARMARX_INFO <<
"Thread creation with RunningTask and PeriodicTask is now allowed again in "
250 this->libLoadingEnabled = enable;
257 <<
"Command line arguments were already set: " <<
VAROUT(commandLineArguments);
258 commandLineArguments.reserve(argc);
259 for (
int i = 0; i < argc; ++i)
261 commandLineArguments.emplace_back(argv[i]);
265 const std::vector<std::string>&
268 return commandLineArguments;
290 std::unique_lock lock(instanceMutex);
298 std::unique_lock lock(instanceMutex);
312 armarXManager->setComponentIceProperties(properties);
325 armarXManager->updateComponentIceProperties(properties);
335 if (changedProperties.count(
"DisableLogging") &&
336 getProperty<bool>(
"DisableLogging").isSet())
339 armarXManager->enableLogging(!getProperty<bool>(
"DisableLogging").getValue());
342 if (changedProperties.count(
"EnableProfiling"))
344 armarXManager->enableProfiling(getProperty<bool>(
"EnableProfiling").getValue());
346 if (changedProperties.count(
"Verbosity"))
348 armarXManager->setGlobalMinimumLoggingLevel(
349 getProperty<MessageTypeT>(
"Verbosity").getValue());
398 std::cout <<
"Version: " <<
GetVersion() << std::endl;
410 const Ice::PropertyDict& env_props =
413 for (
const auto& [name,
value] : env_props)
415 const std::string short_name = name.substr(4);
416 ARMARX_INFO <<
"Setting environment variable '" << short_name <<
"' to value '" <<
value
418 setenv(short_name.c_str(),
value.c_str(), 1);
422 if (getProperty<std::uint64_t>(
"SecondsStartupDelay").isSet())
424 const auto delay = getProperty<std::uint64_t>(
"SecondsStartupDelay").getValue();
425 ARMARX_INFO <<
"startup delay: " << delay <<
" seconds";
426 std::this_thread::sleep_for(std::chrono::seconds{delay});
434 if (getProperty<std::string>(
"ApplicationName").isSet())
436 applicationName = getProperty<std::string>(
"ApplicationName").getValue();
441 const bool redirectStdout = getProperty<bool>(
"RedirectStdout").getValue();
444 std::streambuf* cout_sbuf =
nullptr;
445 std::streambuf* cerr_sbuf =
nullptr;
448 cout_sbuf = std::cout.rdbuf();
449 cerr_sbuf = std::cerr.rdbuf();
450 std::cout.rdbuf(&buf);
451 std::cerr.rdbuf(&errbuf);
458 std::cout.rdbuf(cout_sbuf);
459 std::cerr.rdbuf(cerr_sbuf);
463 int result = EXIT_SUCCESS;
465 threadPool.reset(
new ThreadPool(getProperty<unsigned int>(
"ThreadPoolSize").getValue()));
469 armarXManager =
new ArmarXManager(applicationName, communicator());
471 catch (Ice::ConnectFailedException&)
476 armarXManager->setDataPaths(getProperty<std::string>(
"DataPath").getValue());
485 callbackOnInterrupt();
489 if (applicationNetworkStats)
491 ProfilerListenerPrx profilerTopic =
492 armarXManager->getIceManager()->getTopic<ProfilerListenerPrx>(
493 armarx::Profiler::PROFILER_TOPIC_NAME);
494 applicationNetworkStats->start(profilerTopic, applicationName);
497 loadLibrariesFromProperties();
502 setup(armarXManager, properties);
507 armarXManager->shutdown();
511 result =
exec(armarXManager);
517 shutdownThread->join();
530 armarXManager->waitForShutdown();
546 std::string configFiles = communicator()->getProperties()->getProperty(
"ArmarX.Config");
552 if (!configFiles.empty() && configFiles.compare(
"1") != 0)
556 for (std::string configFile : configFileList)
558 if (!configFile.empty())
560 properties->load(configFile);
584 std::ofstream out(options.
outfile);
594 std::cout <<
"Could not write to file " << options.
outfile << std::endl;
609 this->applicationName = name;
615 return applicationName;
622 if (applicationNetworkStats)
624 applicationNetworkStats->stopTask();
627 shutdownThread.reset(
new std::thread{[
this]
630 this->armarXManager->shutdown();
639 dependencies = simox::alg::replace_all(dependencies,
"\"",
"");
642 for (
size_t i = 0; i < resultList.size(); i++)
652 ARMARX_INFO_S <<
"loading took " << (IceUtil::Time::now() - start).toMilliSeconds();
655 std::vector<std::string>
658 Ice::StringSeq result = getProperty<Ice::StringSeq>(
"DefaultPackages").getValue();
659 Ice::StringSeq additional = getProperty<Ice::StringSeq>(
"AdditionalPackages").getValue();
660 result.insert(result.end(), additional.begin(), additional.end());
668 char* env_armarx_workspace = getenv(
"ARMARX_WORKSPACE");
669 char* env_armarx_default_config_dir_name = getenv(
"ARMARX_CONFIG_DIR_NAME");
671 std::filesystem::path armarx_workspace;
672 std::filesystem::path armarx_config_dir;
674 if (env_armarx_workspace)
676 armarx_workspace = std::filesystem::path(env_armarx_workspace);
680 char* home = getenv(
"HOME");
684 armarx_workspace = std::filesystem::path(home);
688 armarx_workspace =
"~/";
692 if (env_armarx_default_config_dir_name)
694 armarx_config_dir = std::filesystem::path(env_armarx_default_config_dir_name);
698 if (env_armarx_workspace)
700 armarx_config_dir =
"armarx_config";
705 armarx_config_dir =
".armarx";
711 return (armarx_workspace / armarx_config_dir).string();
715 if (env_armarx_workspace)
717 return "${ARMARX_WORKSPACE}/" + armarx_config_dir.string();
722 return "${HOME}/" + armarx_config_dir.string();
730 return armarXManager;
739 Ice::InitializationData id(initData);
744 if (
id.properties->getProperty(
"Ice.Admin.InstanceName").empty())
746 id.properties->setProperty(
"Ice.Admin.InstanceName", this->
getName());
748 if (
id.properties->getProperty(
"Ice.Admin.Endpoints").empty())
750 id.properties->setProperty(
"Ice.Admin.Endpoints",
"tcp -h 127.0.0.1");
753 if (initData.properties->getProperty(
"ArmarX.NetworkStats") ==
"1")
756 id.observer = applicationNetworkStats;
758 const auto oldFacets = initData.properties->getPropertyAsList(
"Ice.Admin.Facets");
759 if (oldFacets.empty())
761 initData.properties->setProperty(
"Ice.Admin.Facets",
"Metrics");
763 else if (std::find(oldFacets.begin(), oldFacets.end(),
"Metrics") == oldFacets.end())
765 std::stringstream
str;
767 for (
const auto& facet : oldFacets)
771 initData.properties->setProperty(
"Ice.Admin.Facets",
str.str());
773 initData.properties->setProperty(
"IceMX.Metrics.NetworkStats.GroupBy",
"none");
776 return Ice::Application::doMain(argc, argv,
id, i);
783 const std::string configFileName =
"default.cfg";
784 const std::string generatedConfigFileName =
"default.generated.cfg";
785 Ice::StringSeq defaultsPaths;
787 std::filesystem::path absBasePath;
790 absBasePath = defaultsPathVar;
796 defaultsPaths.push_back((absBasePath / configFileName).
string());
797 defaultsPaths.push_back((absBasePath / generatedConfigFileName).
string());
798 return defaultsPaths;
814 for (std::string path : defaultsPath)
820 Ice::PropertyDict defaultCfg = p->getPropertiesForPrefix(
"");
823 for (
auto e : defaultCfg)
825 if (properties->getProperty(e.first).empty())
827 properties->setProperty(e.first, e.second);
831 catch (Ice::FileException& e)
846 const Ice::StringSeq&
849 return ProjectDependendencies;
863 std::string dependenciesConfig =
getIceProperties()->getProperty(
"ArmarX.DependenciesConfig");
865 if (!dependenciesConfig.empty())
867 if (std::filesystem::exists(dependenciesConfig))
870 prop->load(dependenciesConfig);
872 ProjectName = prop->getProperty(
"ArmarX.ProjectName");
873 std::string dependencies = prop->getProperty(
"ArmarX.ProjectDependencies");
890 defineOptionalProperty<std::string>(
891 "Config",
"",
"Comma-separated list of configuration files ");
892 defineOptionalProperty<std::string>(
893 "DependenciesConfig",
894 "./config/dependencies.cfg",
895 "Path to the (usually generated) config file containing all data paths of all dependent "
896 "projects. This property usually does not need to be edited.");
897 defineOptionalProperty<Ice::StringSeq>(
904 "RobotSkillTemplates",
911 "List of ArmarX packages which are accessible by default. Comma separated List. If you "
912 "want to add your own packages and use all default ArmarX packages, use the property "
913 "'AdditionalPackages'.");
914 defineOptionalProperty<Ice::StringSeq>(
915 "AdditionalPackages",
917 "List of additional ArmarX packages which should be in the list of default packages. If "
918 "you have custom packages, which should be found by the gui or other apps, specify them "
919 "here. Comma separated List.");
921 defineOptionalProperty<std::string>(
"ApplicationName",
"",
"Application name");
923 defineOptionalProperty<bool>(
"DisableLogging",
925 "Turn logging off in whole application",
928 defineOptionalProperty<MessageTypeT>(
"Verbosity",
930 "Global logging level for whole application",
933 defineOptionalProperty<std::string>(
936 "The logging group is transmitted with every ArmarX log message over Ice in order to group "
937 "the message in the GUI.");
940 defineOptionalProperty<std::string>(
941 "DataPath",
"",
"Semicolon-separated search list for data files");
943 defineOptionalProperty<std::string>(
946 std::string(
"Path for cache files. If relative path AND env. variable ") +
948 " is set, the cache path will be made relative to " +
950 ". Otherwise if relative it will be relative to the default ArmarX config dir (" +
953 defineOptionalProperty<bool>(
"EnableProfiling",
955 "Enable profiling of CPU load produced by this application",
958 defineOptionalProperty<bool>(
959 "RedirectStdout",
true,
"Redirect std::cout and std::cerr to ArmarXLog");
961 defineOptionalProperty<std::string>(
964 "Suffix appended to all topic names for outgoing topics. This is mainly used to direct all "
965 "topics to another name for TopicReplaying purposes.");
967 defineOptionalProperty<bool>(
968 "UseTimeServer",
false,
"Enable using a global Timeserver (e.g. from ArmarXSimulator)");
970 defineOptionalProperty<unsigned int>(
971 "RemoteHandlesDeletionTimeout",
973 "The timeout (in ms) before a remote handle deletes the managed object after the use count "
974 "reached 0. This time can be used by a client to increment the count again (may be "
975 "required when transmitting remote handles)");
976 defineOptionalProperty<bool>(
"StartDebuggerOnCrash",
978 "If this application crashes (segmentation fault) qtcreator will "
979 "attach to this process and start the debugger.");
980 defineOptionalProperty<unsigned int>(
981 "ThreadPoolSize", 1,
"Size of the ArmarX ThreadPool that is always running.");
982 defineOptionalProperty<std::string>(
985 "Libraries to load at start up of the application. Must be enabled by the Application with "
986 "enableLibLoading(). Format: PackageName:LibraryName;... or /absolute/path/to/library;...");
987 defineOptionalProperty<std::uint64_t>(
988 "SecondsStartupDelay",
990 "The startup will be delayed by this number of seconds (useful for debugging)");