Add a shutdown option to main loop

A shutdown option allows another thread to shut the server
down.  Typically this is only done at the end of a testcase
that runs the server in one thread, and then executes tests
from another.

Change-Id: I7658bba79285d7c3e41b578c3510faa3363c5e01
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/mainloop.cpp b/mainloop.cpp
index 6244b91..012b993 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -20,18 +20,30 @@
 #include "sensorcache.hpp"
 #include "hwmon.hpp"
 #include "sysfs.hpp"
+#include "mainloop.hpp"
 
-int serverMain(const char* path)
+MainLoop::MainLoop(const std::string& path)
+    : _shutdown(false), _path(path)
+{
+
+}
+
+void MainLoop::shutdown() noexcept
+{
+    _shutdown = true;
+}
+
+void MainLoop::run()
 {
     // Check sysfs for available sensors.
-    auto sensors = std::make_unique<SensorSet>(path);
+    auto sensors = std::make_unique<SensorSet>(_path);
     auto sensor_cache = std::make_unique<SensorCache>();
 
     // TODO: Issue#3 - Need to make calls to the dbus sensor cache here to
     //       ensure the objects all exist?
 
     // Polling loop.
-    while (true)
+    while (!_shutdown)
     {
         // Iterate through all the sensors.
         for (auto& i : *sensors)
@@ -40,7 +52,7 @@
             {
                 // Read value from sensor.
                 int value = 0;
-                read_sysfs(make_sysfs_path(path,
+                read_sysfs(make_sysfs_path(_path,
                                            i.first.first, i.first.second,
                                            hwmon::entry::input),
                            value);
@@ -66,8 +78,6 @@
         // TODO: Issue#7 - Should probably periodically check the SensorSet
         //       for new entries.
     }
-
-    return 0;
 }
 
 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/mainloop.hpp b/mainloop.hpp
index d3a5f96..4bc08c4 100644
--- a/mainloop.hpp
+++ b/mainloop.hpp
@@ -1,3 +1,39 @@
 #pragma once
 
-int serverMain(const char* path);
+#include <string>
+
+/** @class MainLoop
+ *  @brief hwmon-readd main application loop.
+ */
+class MainLoop
+{
+    public:
+        MainLoop() = delete;
+        MainLoop(const MainLoop&) = delete;
+        MainLoop& operator=(const MainLoop&) = delete;
+        MainLoop(MainLoop&&) = default;
+        MainLoop& operator=(MainLoop&&) = default;
+        ~MainLoop() = default;
+
+        /** @brief Constructor
+         *
+         *  @param[in] path - hwmon sysfs instance to manage
+         */
+        explicit MainLoop(const std::string& path);
+
+        /** @brief Start polling loop and process dbus traffic. */
+        void run();
+
+        /** @brief Stop loop from another thread.
+         *
+         *  Typically only used by testcases.
+         */
+        void shutdown() noexcept;
+
+    private:
+
+        /** @brief Shutdown requested. */
+        volatile bool _shutdown;
+        /** @brief Path to hwmon sysfs instance. */
+        std::string _path;
+};
diff --git a/readd.cpp b/readd.cpp
index 1ac5ddc..0c611b6 100644
--- a/readd.cpp
+++ b/readd.cpp
@@ -41,7 +41,10 @@
     // Finished getting options out, so cleanup the parser.
     options.reset();
 
-    return serverMain(path.c_str());
+    MainLoop loop(path);
+    loop.run();
+
+    return 0;
 }
 
 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4