xref: /openbmc/openpower-hw-diags/listener.cpp (revision 1c4b02ea682b62a74bc28986c574774755d6cdaf)
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