C++11 library providing functionality common to all adapters.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

457 lines
14 KiB

  1. // This file is under GNU General Public License 3.0
  2. // see LICENSE.txt
  3. #include "AbstractPityUnit.hh"
  4. #include "../../../src/std_utils.hh"
  5. #include <iostream>
  6. #include <unistd.h>
  7. #include <cstdlib>
  8. #include <sys/stat.h>
  9. #include <exception>
  10. #include <memory>
  11. #include <sys/wait.h>
  12. namespace pEp {
  13. namespace PityTest11 {
  14. // static
  15. std::string AbstractPityUnit::_global_root_dir = "./pitytest_data/";
  16. // static
  17. bool AbstractPityUnit::debug_log_enabled = false;
  18. // static
  19. int AbstractPityUnit::_procUnitsCount = 0;
  20. AbstractPityUnit::AbstractPityUnit(const std::string &name, ExecutionMode exec_mode) :
  21. PityTree<AbstractPityUnit>(*this, name), _exec_mode{ exec_mode }, _procUnitNr{ 0 }
  22. {
  23. _init();
  24. }
  25. AbstractPityUnit::AbstractPityUnit(
  26. AbstractPityUnit &parent,
  27. const std::string &name,
  28. ExecutionMode exec_mode) :
  29. PityTree<AbstractPityUnit>(*this, name, parent),
  30. _exec_mode{ exec_mode }, _procUnitNr{ 0 }
  31. {
  32. _init();
  33. }
  34. AbstractPityUnit::AbstractPityUnit(const AbstractPityUnit &rhs, AbstractPityUnit &self) :
  35. PityTree<AbstractPityUnit>(rhs, self)
  36. {
  37. _procUnitNr = rhs._procUnitNr;
  38. _exec_mode = rhs._exec_mode;
  39. _transport = rhs._transport;
  40. _transport_endpoints = rhs._transport_endpoints;
  41. _init();
  42. }
  43. AbstractPityUnit &AbstractPityUnit::operator=(const AbstractPityUnit &rhs)
  44. {
  45. _procUnitNr = rhs._procUnitNr;
  46. _exec_mode = rhs._exec_mode;
  47. _transport = rhs._transport;
  48. _transport_endpoints = rhs._transport_endpoints;
  49. return *this;
  50. }
  51. void AbstractPityUnit::_init()
  52. {
  53. _log_mutex = std::make_shared<fs_mutex>("log.mutex");
  54. _log_mutex->release();
  55. }
  56. // static
  57. void AbstractPityUnit::setGlobalRootDir(const std::string &dir)
  58. {
  59. AbstractPityUnit::_global_root_dir = dir;
  60. }
  61. // static
  62. std::string AbstractPityUnit::getGlobalRootDir()
  63. {
  64. return AbstractPityUnit::_global_root_dir;
  65. }
  66. // For:
  67. // RootUnit - "<name>"
  68. // ProcessUnit - ".../<proc>"
  69. // When Process as dir. parent - ".../<proc>/name"
  70. // When no process as dir. parent - ".../<proc>/.../name"
  71. std::string AbstractPityUnit::getPathShort() const
  72. {
  73. std::string ret;
  74. if (isRoot()) {
  75. ret = getName();
  76. } else {
  77. if (_isProcessUnit()) {
  78. ret += ".../" + getName();
  79. } else {
  80. if (&(parentingProcessUnit()) == (getParent())) {
  81. ret = parentingProcessUnit().getPathShort() + "/" + getName();
  82. } else {
  83. ret = parentingProcessUnit().getPathShort() + "/.../" + getName();
  84. }
  85. }
  86. }
  87. return ret;
  88. }
  89. // Every process has its own dir inside its rootUnitDir
  90. // All other units inherit processDir from their Root/ProcessUnit
  91. std::string AbstractPityUnit::processDir()
  92. {
  93. if (isRoot()) {
  94. return _rootUnitDir();
  95. } else {
  96. if (_isProcessUnit()) {
  97. return _rootUnitDir() + getName() + "/";
  98. } else {
  99. return getParent()->processDir();
  100. }
  101. }
  102. }
  103. // Every RootUnit has its own dir
  104. std::string AbstractPityUnit::_rootUnitDir()
  105. {
  106. return getGlobalRootDir() + getRoot().getName() + "/";
  107. }
  108. // Every process has its own dir inside its rootUnitDir
  109. // All other units inherit transportDir from their Root/ProcessUnit
  110. std::string AbstractPityUnit::transportDir()
  111. {
  112. if (isRoot()) {
  113. throw std::runtime_error("No transport dir");
  114. } else {
  115. if (_isProcessUnit()) {
  116. return processDir() + "inbox/";
  117. } else {
  118. return getParent()->transportDir();
  119. }
  120. }
  121. }
  122. void AbstractPityUnit::_initProcUnitNrRecurse()
  123. {
  124. if (!isRoot()) {
  125. // Inherit
  126. _procUnitNr = getParent()->_procUnitNr;
  127. //Or update if procUnit
  128. if (_isProcessUnit()) {
  129. _procUnitsCount++;
  130. _procUnitNr = _procUnitsCount;
  131. }
  132. } else {
  133. _procUnitNr = _procUnitsCount;
  134. }
  135. // Recurse
  136. for (const auto &chld : getChildRefs()) {
  137. chld.second._initProcUnitNrRecurse();
  138. }
  139. }
  140. void AbstractPityUnit::_initTransportRecurse()
  141. {
  142. logger_debug.set_instancename(getPath());
  143. if (!isRoot()) {
  144. if (_isProcessUnit()) {
  145. _createTransport();
  146. }
  147. }
  148. // Recurse
  149. for (const auto &chld : getChildRefs()) {
  150. chld.second._initTransportRecurse();
  151. }
  152. }
  153. void AbstractPityUnit::_initDirsRecursive()
  154. {
  155. Utils::dir_recreate(processDir());
  156. // Recurse
  157. for (const auto &child : getChildRefs()) {
  158. child.second._initDirsRecursive();
  159. }
  160. }
  161. void AbstractPityUnit::run(bool init_tree)
  162. {
  163. pEpLogClass("called");
  164. if (init_tree) {
  165. logH1("PityTest Starting...");
  166. _logRaw("RootUnit: " + getPath());
  167. _logRaw("GlobalRootDir: " + getGlobalRootDir());
  168. _logRaw("Ensuring GlobalRootDir...");
  169. Utils::dir_ensure(getGlobalRootDir());
  170. _logRaw("Recreating process dirs recursively...");
  171. _initDirsRecursive();
  172. _logRaw("Initializing Transport recursively...");
  173. _initTransportRecurse();
  174. _logRaw("\n\nTestTree");
  175. _logRaw("--------");
  176. _logRaw(to_string() + "\n");
  177. _procUnitsCount = 0;
  178. _initProcUnitNrRecurse();
  179. }
  180. // TODO: hack
  181. setenv("HOME", processDir().c_str(), true);
  182. // Execute in fork and wait here until process ends
  183. if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL) { // fork
  184. _executeInFork(std::bind(&AbstractPityUnit::_runRecurse, this), true);
  185. // Execute in fork and go on, wait for process execution in the end
  186. } else if (_exec_mode == ExecutionMode::PROCESS_PARALLEL) {
  187. _executeInFork(std::bind(&AbstractPityUnit::_runRecurse, this), false);
  188. // Execute as normal function
  189. } else if (_exec_mode == ExecutionMode::FUNCTION) {
  190. _runRecurse();
  191. } else if (_exec_mode == ExecutionMode::THREAD_PARALLEL) {
  192. throw std::invalid_argument(to_string(_exec_mode) + " - not implemented");
  193. } else if (_exec_mode == ExecutionMode::THREAD_SEQUENTIAL) {
  194. throw std::invalid_argument(to_string(_exec_mode) + " - not implemented");
  195. }
  196. if (init_tree) {
  197. _waitChildProcesses();
  198. }
  199. }
  200. std::string AbstractPityUnit::to_string(bool recursive, int indent)
  201. {
  202. std::string ret;
  203. std::stringstream builder;
  204. builder << std::string(indent * 4, ' ');
  205. builder << getName();
  206. builder << " [ ";
  207. builder << to_string(_exec_mode) << " - ";
  208. builder << "\"" << processDir() << "\"";
  209. builder << " ]";
  210. builder << std::endl;
  211. ret = builder.str();
  212. if (recursive) {
  213. if (!getChildRefs().empty()) {
  214. indent++;
  215. for (const auto child : getChildRefs()) {
  216. ret += child.second.to_string(true, indent);
  217. }
  218. indent--;
  219. }
  220. }
  221. return ret;
  222. }
  223. std::string AbstractPityUnit::to_string(const ExecutionMode &emode)
  224. {
  225. switch (emode) {
  226. case ExecutionMode::FUNCTION:
  227. return "FUNCTION";
  228. case ExecutionMode::PROCESS_SEQUENTIAL:
  229. return "PROC_SEQ";
  230. case ExecutionMode::PROCESS_PARALLEL:
  231. return "PROC_PAR";
  232. case ExecutionMode::THREAD_SEQUENTIAL:
  233. return "THREAD_S";
  234. case ExecutionMode::THREAD_PARALLEL:
  235. return "THREAD_P";
  236. case ExecutionMode::INHERIT:
  237. return "INHERIT";
  238. default:
  239. return "UNDEFINED EXECUTION MODE";
  240. }
  241. }
  242. void AbstractPityUnit::registerAsTransportEndpoint()
  243. {
  244. transportEndpoints().insert({ getName(), transportDir() });
  245. }
  246. Endpoints &AbstractPityUnit::transportEndpoints()
  247. {
  248. if (isRoot()) {
  249. return _transport_endpoints;
  250. } else {
  251. return getRoot().transportEndpoints();
  252. }
  253. }
  254. void AbstractPityUnit::log(const std::string &msg) const
  255. {
  256. std::stringstream builder;
  257. builder << "[ ";
  258. builder << std::to_string(getpid());
  259. builder << " - ";
  260. builder << getPathShort();
  261. builder << " ] - ";
  262. builder << msg;
  263. _logRaw(builder.str());
  264. }
  265. void AbstractPityUnit::logH1(const std::string &msg) const
  266. {
  267. Adapter::pEpLog::logH1(msg, _color());
  268. }
  269. void AbstractPityUnit::logH2(const std::string &msg) const
  270. {
  271. Adapter::pEpLog::logH2(msg, _color());
  272. }
  273. void AbstractPityUnit::logH3(const std::string &msg) const
  274. {
  275. Adapter::pEpLog::logH3(msg, _color());
  276. }
  277. // PRIVATE ---------------------------------------------------------------------------------
  278. void AbstractPityUnit::_runRecurse()
  279. {
  280. logH2(_status_string("STARTING"));
  281. _runSelf();
  282. if (!getChildRefs().empty()) {
  283. for (const auto child : getChildRefs()) {
  284. child.second.run(false);
  285. }
  286. }
  287. }
  288. void AbstractPityUnit::_executeInFork(std::function<void(void)> func, bool wait_child) const
  289. {
  290. pid_t pid;
  291. pid = fork();
  292. if (pid == pid_t(0)) {
  293. func();
  294. exit(0);
  295. } else if (pid < pid_t(0)) {
  296. throw std::runtime_error("Error forking");
  297. }
  298. if (wait_child) {
  299. _waitChildProcesses();
  300. }
  301. }
  302. void AbstractPityUnit::_waitChildProcesses() const
  303. {
  304. int status;
  305. pid_t pid;
  306. while ((pid = wait(&status)) > 0) {
  307. std::string color;
  308. if (status == 0) {
  309. color = "\033[1m\033[32m"; // Green
  310. } else {
  311. color = "\033[1m\033[31m"; // Red
  312. }
  313. logH3(
  314. color + "PROCESS [ " + std::to_string((int)pid) +
  315. " ] EXITED with status code: " + std::to_string(status) +
  316. Utils::to_termcol(_color()));
  317. }
  318. }
  319. bool AbstractPityUnit::_isProcessUnit() const
  320. {
  321. bool ret = false;
  322. if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL ||
  323. _exec_mode == ExecutionMode::PROCESS_PARALLEL) {
  324. ret = true;
  325. }
  326. return ret;
  327. }
  328. const AbstractPityUnit &AbstractPityUnit::parentingProcessUnit() const
  329. {
  330. if (isRoot() || _isProcessUnit()) {
  331. return *this;
  332. } else {
  333. return getParent()->parentingProcessUnit();
  334. }
  335. }
  336. // Inherited (if null see parent recursively)
  337. void AbstractPityUnit::_createTransport()
  338. {
  339. registerAsTransportEndpoint();
  340. _transport = std::make_shared<PityTransport>(transportDir(), transportEndpoints());
  341. }
  342. // Inherited (if null see parent recursively)
  343. PityTransport *AbstractPityUnit::transport() const
  344. {
  345. // pEpLogClass("called");
  346. PityTransport *ret = nullptr;
  347. if (_transport != nullptr) {
  348. ret = _transport.get();
  349. } else {
  350. if (!isRoot()) {
  351. ret = getParent()->transport();
  352. }
  353. }
  354. return ret;
  355. }
  356. std::string AbstractPityUnit::_status_string(const std::string &msg) const
  357. {
  358. std::string ret;
  359. ret = "[ " + to_string(_exec_mode) + ":" + std::to_string(getpid()) + " ] [ " +
  360. getPathShort() + " ] [ " + msg + " ]";
  361. return ret;
  362. }
  363. //static
  364. Utils::Color AbstractPityUnit::_colForProcUnitNr(int procUnitNr)
  365. {
  366. int nrColors = 7;
  367. switch (procUnitNr % nrColors) {
  368. case 0:
  369. return Utils::Color::WHITE;
  370. case 1:
  371. return Utils::Color::GREEN;
  372. case 2:
  373. return Utils::Color::YELLOW;
  374. case 3:
  375. return Utils::Color::CYAN;
  376. case 4:
  377. return Utils::Color::BLUE;
  378. case 5:
  379. return Utils::Color::MAGENTA;
  380. case 6:
  381. return Utils::Color::RED;
  382. default:
  383. return Utils::Color::WHITE;
  384. }
  385. }
  386. Utils::Color AbstractPityUnit::_color() const
  387. {
  388. return _colForProcUnitNr(_procUnitNr);
  389. }
  390. void AbstractPityUnit::_logRaw(const std::string &msg) const
  391. {
  392. // fs-mutex to sync across processes
  393. _log_mutex->aquire();
  394. Adapter::pEpLog::log(msg, _color());
  395. _log_mutex->release();
  396. }
  397. } // namespace PityTest11
  398. } // namespace pEp