diff --git a/.vscode/settings.json b/.vscode/settings.json index 95e62d7..f809d1f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -63,7 +63,17 @@ "typeinfo": "cpp", "variant": "cpp", "cstring": "cpp", - "cinttypes": "cpp" + "cinttypes": "cpp", + "any": "cpp", + "codecvt": "cpp", + "complex": "cpp", + "coroutine": "cpp", + "csignal": "cpp", + "list": "cpp", + "source_location": "cpp", + "future": "cpp", + "shared_mutex": "cpp", + "typeindex": "cpp" }, "editor.rulers": [80, 120] } \ No newline at end of file diff --git a/hcore/Makefile.am b/hcore/Makefile.am index 6ad78cf..5910b3c 100644 --- a/hcore/Makefile.am +++ b/hcore/Makefile.am @@ -2,5 +2,5 @@ SUBDIRS = deviceManager senseApis AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include" noinst_LIBRARIES = libhcore.a -libhcore_a_SOURCES = mind.cpp opts.cpp componentThreads.cpp +libhcore_a_SOURCES = mind.cpp opts.cpp componentThread.cpp diff --git a/hcore/componentThread.cpp b/hcore/componentThread.cpp new file mode 100644 index 0000000..e5fb5b3 --- /dev/null +++ b/hcore/componentThread.cpp @@ -0,0 +1,70 @@ +#include +#include + +namespace hk { + +namespace director { +ComponentThread director; +} +namespace simulator { +ComponentThread canvas; +} +namespace subconscious { +ComponentThread subconscious; +} + +std::unordered_map + ComponentThread::componentThreads = +{ + {director::director.thread.get_id(), director::director}, + {simulator::canvas.thread.get_id(), simulator::canvas}, + {subconscious::subconscious.thread.get_id(), subconscious::subconscious} +}; + +void ComponentThread::signalThread(std::thread::id id) +{ + auto it = componentThreads.find(id); + if (it == componentThreads.end()) + { + throw std::runtime_error(std::string(__func__) + + ": Thread ID not found in componentThreads map"); + } + + ComponentThread& componentThread = it->second; + { + std::lock_guard lock(componentThread.startupSync.mutex); + componentThread.startupSync.ready = true; + } + componentThread.startupSync.cv.notify_one(); +} + +void ComponentThread::main(ComponentThread& self) +{ + std::cout << __func__ << ": Entered." << std::endl; + // We sleep on spawn until the main thread tells us to continue. + { + std::unique_lock lock(self.startupSync.mutex); + self.startupSync.cv.wait(lock, [&self]() { + return self.startupSync.ready; + }); + } + + std::cout << __func__ << ": Starting event loop." << std::endl; + self.getIoService().run(); + std::cout << __func__ << ": Exiting." << std::endl; +} + +void ComponentThread::validateThreadIds(void) +{ + for (const auto& [id, componentThread] : componentThreads) + { + // std::thread::id() is usable as an invalid ID. + if (id == std::thread::id()) + { + throw std::runtime_error( + std::string(__func__) + ": Invalid Thread ID."); + } + } +} + +} // namespace hk diff --git a/hcore/componentThreads.cpp b/hcore/componentThreads.cpp deleted file mode 100644 index 0d9a460..0000000 --- a/hcore/componentThreads.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include - -namespace hk { - -namespace director { -ComponentThread director; -} -namespace simulator { -ComponentThread canvas; -} -namespace subconscious { -ComponentThread subconscious; -} - -std::unordered_map - ComponentThread::componentThreads = -{ - {director::director.thread.get_id(), director::director}, - {simulator::canvas.thread.get_id(), simulator::canvas}, - {subconscious::subconscious.thread.get_id(), subconscious::subconscious} -}; - -} // namespace hk diff --git a/hcore/include/componentThread.h b/hcore/include/componentThread.h index 8b3dcfc..d3bf516 100644 --- a/hcore/include/componentThread.h +++ b/hcore/include/componentThread.h @@ -13,7 +13,8 @@ class ComponentThread { public: ComponentThread() - : work(io_service), startupSync() + : work(io_service), startupSync(), + thread(ComponentThread::main, std::ref(*this)) {} boost::asio::io_service& getIoService(void) { return io_service; } @@ -31,10 +32,13 @@ public: return it->second.getIoService(); } + static void main(ComponentThread &self); + static void signalThread(std::thread::id id); + static void validateThreadIds(void); + public: boost::asio::io_service io_service; boost::asio::io_service::work work; - std::thread thread; struct StartupSync { std::mutex mutex; std::condition_variable cv; @@ -43,6 +47,10 @@ public: StartupSync() : ready(false) {} } startupSync; + /* Always ensure that this is last so that the thread is spawned after + * everything else. + */ + std::thread thread; static std::unordered_map componentThreads; }; diff --git a/main.cpp b/main.cpp index 819d28f..0df0852 100644 --- a/main.cpp +++ b/main.cpp @@ -14,8 +14,6 @@ namespace hk { static int initializeHarikoff(int argc, char **argv, char **envp); -void startThreads(); -void signalThreads(); } // namespace hk @@ -24,20 +22,29 @@ int main(int argc, char **argv, char **envp) try { std::cout << __func__ << ": Entering main()" << std::endl; - // Print out the keys for each index in the map - for (const auto& [id, componentThread] - : hk::ComponentThread::componentThreads) - { - std::cout << __func__ << ": Thread ID: " << id << std::endl; - } + // Validate thread IDs + hk::ComponentThread::validateThreadIds(); int ret = hk::initializeHarikoff(argc, argv, envp); if (ret != 0) { return ret; } + + // Signal all threads + for (const auto& [id, componentThread] + : hk::ComponentThread::componentThreads) { + hk::ComponentThread::signalThread(id); + } + + // Infinite loop calling yield + while (true) { + std::this_thread::yield(); + } } - catch (const std::exception& e) { - std::cerr << __func__ << ": Exception occurred: " << e.what() << std::endl; + catch (const std::exception& e) + { + std::cerr << __func__ << ": Exception occurred: " << e.what() + << std::endl; return EXIT_FAILURE; } catch (...) { @@ -64,8 +71,10 @@ static int initializeHarikoff(int argc, char **argv, char **envp) try { options.parseArguments(argc, argv, envp); } - catch (const std::invalid_argument& e) { - std::cerr << __func__ << ": Exception occurred: " << e.what() << '\n' << options.getUsage() << '\n'; + catch (const std::invalid_argument& e) + { + std::cerr << __func__ << ": Exception occurred: " << e.what() << '\n' + << options.getUsage() << '\n'; return EXIT_FAILURE; } @@ -80,38 +89,10 @@ static int initializeHarikoff(int argc, char **argv, char **envp) std::cout << DeviceManager::stringifyDeviceSpecs() << std::endl; sense_api::SenseApiManager::getInstance().loadAllSenseApiLibsFromOptions(); + /* Start the threads */ + std::cout << __func__ << ": Exiting" << std::endl; return 0; } -void startThreads() -{ - for (auto& [id, componentThread] : ComponentThread::componentThreads) { - componentThread.thread = std::thread([&componentThread]() { - // We sleep on spawn until the marionette tells us to continue. - { - std::unique_lock lock( - componentThread.startupSync.mutex); - - componentThread.startupSync.cv.wait(lock, [&componentThread]() { - return componentThread.startupSync.ready; - }); - } - - componentThread.getIoService().run(); - }); - } -} - -void signalThreads() -{ - for (auto& [id, componentThread] : ComponentThread::componentThreads) { - { - std::lock_guard lock(componentThread.startupSync.mutex); - componentThread.startupSync.ready = true; - } - componentThread.startupSync.cv.notify_one(); - } -} - } // namespace hk