Added IPC support to attention handler
Created a listener thread that configures and starts the attention
gpio monitor. The listener remains resident in memory and accepts
run-time commands to configure (or stop) the attention handler.
Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I032fe25a49d43d91a1f7d41cc34318839cd7de05
diff --git a/listener.cpp b/listener.cpp
new file mode 100644
index 0000000..c8ae642
--- /dev/null
+++ b/listener.cpp
@@ -0,0 +1,208 @@
+#include <libpdbg.h>
+
+#include <attn/attn_main.hpp>
+#include <boost/interprocess/ipc/message_queue.hpp>
+#include <cli.hpp>
+#include <listener.hpp>
+
+/** @brief openpower-hw-diags message queue name */
+static constexpr const char* mq_listener = "openpower-hw-diags-mq";
+
+/** @brief maximum length of command line parameter */
+static constexpr int max_command_len = 25;
+
+/** @brief end of command line args message */
+static const char* msg_send_end = "999999999999999";
+
+/** @brief structure for holding main args (for threads) */
+typedef struct
+{
+ int argc;
+ char** argv;
+} MainArgs_t;
+
+/**
+ * @brief Start a thread to monitor the attention GPIO
+ *
+ * @param i_config Attention handler configuration object
+ */
+void* threadGpioMon(void* i_config)
+{
+ // Configure and start attention monitor
+ attn::attnDaemon((attn::Config*)i_config);
+
+ pthread_exit(NULL);
+}
+
+/** @brief Start a thread to listen for attention handler messages */
+void* threadListener(void* i_params)
+{
+ using namespace boost::interprocess;
+
+ // convert thread params to main arguments
+ int argc = static_cast<MainArgs_t*>(i_params)->argc;
+ char** argv = static_cast<MainArgs_t*>(i_params)->argv;
+
+ // vector to hold messages sent to listener
+ std::vector<std::string> messages;
+
+ // remove listener message queue if exists (does not throw)
+ message_queue::remove(mq_listener);
+
+ // thread handle for gpio monitor
+ pthread_t ptidGpio;
+
+ // status of gpio monitor
+ bool gpioMonEnabled = false;
+
+ // Parse command line args to see if any flags were passed, update the
+ // booleans accordingly and pass them to the config object constructor.
+ bool vital_enable = true;
+ bool checkstop_enable = true;
+ bool ti_enable = true;
+ bool bp_enable = true;
+
+ // parse config options
+ parseConfig(argv, argv + argc, vital_enable, checkstop_enable, ti_enable,
+ bp_enable);
+
+ // create config
+ attn::Config config(vital_enable, checkstop_enable, ti_enable, bp_enable);
+
+ // initialize pdbg targets
+ pdbg_targets_init(nullptr);
+
+ // This is the main listener loop. All the above code will be executed
+ // only once. All other communtication with the attention handler will
+ // originate from here via the message queue.
+ do
+ {
+ // we will catch any exceptions from thread library
+ try
+ {
+ // create new message queue or open existing
+ message_queue mq(open_or_create, mq_listener, 1, max_command_len);
+
+ // message queue parameters
+ char buffer[max_command_len + 1];
+ size_t recvd_size;
+ unsigned int priority;
+
+ // We will continue receiving messages until we receive
+ // a msg_send_end message to indicate all command line parameters
+ // have been sent.
+ do
+ {
+ // wait for a message to arrive
+ mq.receive((void*)&buffer, max_command_len, recvd_size,
+ priority);
+
+ // null terminate message and store
+ buffer[recvd_size] = '\0';
+ messages.push_back(buffer);
+
+ } while (buffer != std::string(msg_send_end));
+
+ messages.pop_back(); // remove msg_send_end message
+
+ // convert messages to command line arguments
+ std::vector<char*> argv;
+
+ for (const auto& arg : messages)
+ {
+ argv.push_back((char*)arg.data());
+ }
+
+ int argc = argv.size();
+ argv.push_back(nullptr);
+
+ // stop attention handler daemon?
+ if (true == getCliOption(argv.data(), argv.data() + argc, "--stop"))
+ {
+ message_queue::remove(mq_listener);
+ break;
+ }
+
+ // parse config options
+ parseConfig(argv.data(), argv.data() + argc, vital_enable,
+ checkstop_enable, ti_enable, bp_enable);
+
+ // set config
+ config.setConfig(vital_enable, checkstop_enable, ti_enable,
+ bp_enable);
+
+ // start attention handler daemon?
+ if (true ==
+ getCliOption(argv.data(), argv.data() + argc, "--start"))
+ {
+ if (false == gpioMonEnabled)
+ {
+ if (0 == pthread_create(&ptidGpio, NULL, &threadGpioMon,
+ &config))
+ {
+ gpioMonEnabled = true;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ catch (interprocess_exception& e)
+ {
+ break;
+ }
+ } while (1);
+
+ // stop the gpio monitor if running
+ if (true == gpioMonEnabled)
+ {
+ pthread_cancel(ptidGpio);
+ }
+
+ pthread_exit(NULL);
+}
+
+/** @brief Send command line to a threadi */
+int sendCmdLine(int i_argc, char** i_argv)
+{
+ int count = 0; // number of arguments sent
+
+ using namespace boost::interprocess;
+
+ try
+ {
+ message_queue mq(open_only, mq_listener);
+
+ while (count < i_argc)
+ {
+ mq.send(i_argv[count], strlen(i_argv[count]), 0);
+ count++;
+ }
+ // indicate to listener last cmdline arg was sent
+ mq.send(msg_send_end, strlen(msg_send_end), 0);
+ }
+ catch (interprocess_exception& e)
+ {
+ count = 0; // assume no arguments sent
+ }
+ return count;
+}
+
+/** @brief See if the listener thread message queue exists */
+bool listenerMqExists()
+{
+ using namespace boost::interprocess;
+
+ try
+ {
+ message_queue mq(open_only, mq_listener);
+ return true;
+ }
+ catch (interprocess_exception& e)
+ {
+ return false;
+ }
+}