18c2f8b24SBen Tyner #include <libpdbg.h>
28c2f8b24SBen Tyner
38c2f8b24SBen Tyner #include <attn/attn_main.hpp>
48c2f8b24SBen Tyner #include <boost/interprocess/ipc/message_queue.hpp>
58c2f8b24SBen Tyner #include <cli.hpp>
68c2f8b24SBen Tyner #include <listener.hpp>
78c2f8b24SBen Tyner
88c2f8b24SBen Tyner /** @brief openpower-hw-diags message queue name */
98c2f8b24SBen Tyner static constexpr const char* mq_listener = "openpower-hw-diags-mq";
108c2f8b24SBen Tyner
118c2f8b24SBen Tyner /** @brief maximum length of command line parameter */
128c2f8b24SBen Tyner static constexpr int max_command_len = 25;
138c2f8b24SBen Tyner
148c2f8b24SBen Tyner /** @brief end of command line args message */
158c2f8b24SBen Tyner static const char* msg_send_end = "999999999999999";
168c2f8b24SBen Tyner
178c2f8b24SBen Tyner /**
188c2f8b24SBen Tyner * @brief Start a thread to monitor the attention GPIO
198c2f8b24SBen Tyner *
208c2f8b24SBen Tyner * @param i_config Attention handler configuration object
218c2f8b24SBen Tyner */
threadGpioMon(void * i_config)228c2f8b24SBen Tyner void* threadGpioMon(void* i_config)
238c2f8b24SBen Tyner {
248c2f8b24SBen Tyner // Configure and start attention monitor
258c2f8b24SBen Tyner attn::attnDaemon((attn::Config*)i_config);
268c2f8b24SBen Tyner
278c2f8b24SBen Tyner pthread_exit(NULL);
288c2f8b24SBen Tyner }
298c2f8b24SBen Tyner
308c2f8b24SBen Tyner /** @brief Start a thread to listen for attention handler messages */
threadListener(void * i_params)318c2f8b24SBen Tyner void* threadListener(void* i_params)
328c2f8b24SBen Tyner {
338c2f8b24SBen Tyner using namespace boost::interprocess;
348c2f8b24SBen Tyner
358c2f8b24SBen Tyner // remove listener message queue if exists (does not throw)
368c2f8b24SBen Tyner message_queue::remove(mq_listener);
378c2f8b24SBen Tyner
388c2f8b24SBen Tyner // thread handle for gpio monitor
398c2f8b24SBen Tyner pthread_t ptidGpio;
408c2f8b24SBen Tyner
418c2f8b24SBen Tyner // status of gpio monitor
428c2f8b24SBen Tyner bool gpioMonEnabled = false;
438c2f8b24SBen Tyner
448c2f8b24SBen Tyner // create config
4572feadcfSBen Tyner attn::Config attnConfig;
468c2f8b24SBen Tyner
478c2f8b24SBen Tyner // This is the main listener loop. All the above code will be executed
488c2f8b24SBen Tyner // only once. All other communtication with the attention handler will
498c2f8b24SBen Tyner // originate from here via the message queue.
508c2f8b24SBen Tyner do
518c2f8b24SBen Tyner {
52d3cda742SBen Tyner // vector to hold messages sent to listener
53d3cda742SBen Tyner std::vector<std::string> messages;
548c2f8b24SBen Tyner // we will catch any exceptions from thread library
558c2f8b24SBen Tyner try
568c2f8b24SBen Tyner {
578c2f8b24SBen Tyner // create new message queue or open existing
588c2f8b24SBen Tyner message_queue mq(open_or_create, mq_listener, 1, max_command_len);
598c2f8b24SBen Tyner
608c2f8b24SBen Tyner // message queue parameters
618c2f8b24SBen Tyner char buffer[max_command_len + 1];
628c2f8b24SBen Tyner size_t recvd_size;
638c2f8b24SBen Tyner unsigned int priority;
648c2f8b24SBen Tyner
658c2f8b24SBen Tyner // We will continue receiving messages until we receive
668c2f8b24SBen Tyner // a msg_send_end message to indicate all command line parameters
678c2f8b24SBen Tyner // have been sent.
688c2f8b24SBen Tyner do
698c2f8b24SBen Tyner {
708c2f8b24SBen Tyner // wait for a message to arrive
718c2f8b24SBen Tyner mq.receive((void*)&buffer, max_command_len, recvd_size,
728c2f8b24SBen Tyner priority);
738c2f8b24SBen Tyner
748c2f8b24SBen Tyner // null terminate message and store
758c2f8b24SBen Tyner buffer[recvd_size] = '\0';
768c2f8b24SBen Tyner messages.push_back(buffer);
778c2f8b24SBen Tyner
788c2f8b24SBen Tyner } while (buffer != std::string(msg_send_end));
798c2f8b24SBen Tyner
808c2f8b24SBen Tyner messages.pop_back(); // remove msg_send_end message
818c2f8b24SBen Tyner
828c2f8b24SBen Tyner // convert messages to command line arguments
838c2f8b24SBen Tyner std::vector<char*> argv;
848c2f8b24SBen Tyner
85*1c4b02eaSBen Tyner std::transform(messages.begin(), messages.end(),
86*1c4b02eaSBen Tyner std::back_inserter(argv), (char*)data());
878c2f8b24SBen Tyner
888c2f8b24SBen Tyner int argc = argv.size();
898c2f8b24SBen Tyner argv.push_back(nullptr);
908c2f8b24SBen Tyner
918c2f8b24SBen Tyner // stop attention handler daemon?
928c2f8b24SBen Tyner if (true == getCliOption(argv.data(), argv.data() + argc, "--stop"))
938c2f8b24SBen Tyner {
948c2f8b24SBen Tyner message_queue::remove(mq_listener);
958c2f8b24SBen Tyner break;
968c2f8b24SBen Tyner }
978c2f8b24SBen Tyner
988c2f8b24SBen Tyner // parse config options
9972feadcfSBen Tyner parseConfig(argv.data(), argv.data() + argc, &attnConfig);
1008c2f8b24SBen Tyner
1018c2f8b24SBen Tyner // start attention handler daemon?
1028c2f8b24SBen Tyner if (true ==
1038c2f8b24SBen Tyner getCliOption(argv.data(), argv.data() + argc, "--start"))
1048c2f8b24SBen Tyner {
1058c2f8b24SBen Tyner if (false == gpioMonEnabled)
1068c2f8b24SBen Tyner {
1078c2f8b24SBen Tyner if (0 == pthread_create(&ptidGpio, NULL, &threadGpioMon,
10872feadcfSBen Tyner &attnConfig))
1098c2f8b24SBen Tyner {
1108c2f8b24SBen Tyner gpioMonEnabled = true;
1118c2f8b24SBen Tyner }
1128c2f8b24SBen Tyner else
1138c2f8b24SBen Tyner {
1148c2f8b24SBen Tyner break;
1158c2f8b24SBen Tyner }
1168c2f8b24SBen Tyner }
1178c2f8b24SBen Tyner }
1188c2f8b24SBen Tyner }
1198c2f8b24SBen Tyner
1208c2f8b24SBen Tyner catch (interprocess_exception& e)
1218c2f8b24SBen Tyner {
1228c2f8b24SBen Tyner break;
1238c2f8b24SBen Tyner }
1248c2f8b24SBen Tyner } while (1);
1258c2f8b24SBen Tyner
1268c2f8b24SBen Tyner // stop the gpio monitor if running
1278c2f8b24SBen Tyner if (true == gpioMonEnabled)
1288c2f8b24SBen Tyner {
1298c2f8b24SBen Tyner pthread_cancel(ptidGpio);
1308c2f8b24SBen Tyner }
1318c2f8b24SBen Tyner
1328c2f8b24SBen Tyner pthread_exit(NULL);
1338c2f8b24SBen Tyner }
1348c2f8b24SBen Tyner
1358c2f8b24SBen Tyner /** @brief Send command line to a threadi */
sendCmdLine(int i_argc,char ** i_argv)1368c2f8b24SBen Tyner int sendCmdLine(int i_argc, char** i_argv)
1378c2f8b24SBen Tyner {
1388c2f8b24SBen Tyner int count = 0; // number of arguments sent
1398c2f8b24SBen Tyner
1408c2f8b24SBen Tyner using namespace boost::interprocess;
1418c2f8b24SBen Tyner
1428c2f8b24SBen Tyner try
1438c2f8b24SBen Tyner {
1448c2f8b24SBen Tyner message_queue mq(open_only, mq_listener);
1458c2f8b24SBen Tyner
1468c2f8b24SBen Tyner while (count < i_argc)
1478c2f8b24SBen Tyner {
1488c2f8b24SBen Tyner mq.send(i_argv[count], strlen(i_argv[count]), 0);
1498c2f8b24SBen Tyner count++;
1508c2f8b24SBen Tyner }
1518c2f8b24SBen Tyner // indicate to listener last cmdline arg was sent
1528c2f8b24SBen Tyner mq.send(msg_send_end, strlen(msg_send_end), 0);
1538c2f8b24SBen Tyner }
1548c2f8b24SBen Tyner catch (interprocess_exception& e)
1558c2f8b24SBen Tyner {
1568c2f8b24SBen Tyner count = 0; // assume no arguments sent
1578c2f8b24SBen Tyner }
1588c2f8b24SBen Tyner return count;
1598c2f8b24SBen Tyner }
1608c2f8b24SBen Tyner
1618c2f8b24SBen Tyner /** @brief See if the listener thread message queue exists */
listenerMqExists()1628c2f8b24SBen Tyner bool listenerMqExists()
1638c2f8b24SBen Tyner {
1648c2f8b24SBen Tyner using namespace boost::interprocess;
1658c2f8b24SBen Tyner
1668c2f8b24SBen Tyner try
1678c2f8b24SBen Tyner {
1688c2f8b24SBen Tyner message_queue mq(open_only, mq_listener);
1698c2f8b24SBen Tyner return true;
1708c2f8b24SBen Tyner }
1718c2f8b24SBen Tyner catch (interprocess_exception& e)
1728c2f8b24SBen Tyner {
1738c2f8b24SBen Tyner return false;
1748c2f8b24SBen Tyner }
1758c2f8b24SBen Tyner }
176