blob: 9d3a05acaf98e3fbfdb1a8cf17adb14ff841125b [file] [log] [blame]
Ben Tyner8c2f8b22020-03-27 10:39:31 -05001#include <libpdbg.h>
2
3#include <attn/attn_main.hpp>
4#include <boost/interprocess/ipc/message_queue.hpp>
5#include <cli.hpp>
6#include <listener.hpp>
7
8/** @brief openpower-hw-diags message queue name */
9static constexpr const char* mq_listener = "openpower-hw-diags-mq";
10
11/** @brief maximum length of command line parameter */
12static constexpr int max_command_len = 25;
13
14/** @brief end of command line args message */
15static const char* msg_send_end = "999999999999999";
16
Ben Tyner8c2f8b22020-03-27 10:39:31 -050017/**
18 * @brief Start a thread to monitor the attention GPIO
19 *
20 * @param i_config Attention handler configuration object
21 */
22void* threadGpioMon(void* i_config)
23{
24 // Configure and start attention monitor
25 attn::attnDaemon((attn::Config*)i_config);
26
27 pthread_exit(NULL);
28}
29
30/** @brief Start a thread to listen for attention handler messages */
31void* threadListener(void* i_params)
32{
33 using namespace boost::interprocess;
34
Ben Tyner8c2f8b22020-03-27 10:39:31 -050035 // remove listener message queue if exists (does not throw)
36 message_queue::remove(mq_listener);
37
38 // thread handle for gpio monitor
39 pthread_t ptidGpio;
40
41 // status of gpio monitor
42 bool gpioMonEnabled = false;
43
Ben Tyner8c2f8b22020-03-27 10:39:31 -050044 // create config
Ben Tyner72feadc2020-04-06 12:57:31 -050045 attn::Config attnConfig;
Ben Tyner8c2f8b22020-03-27 10:39:31 -050046
Ben Tyner8c2f8b22020-03-27 10:39:31 -050047 // This is the main listener loop. All the above code will be executed
48 // only once. All other communtication with the attention handler will
49 // originate from here via the message queue.
50 do
51 {
Ben Tynerd3cda742020-05-04 08:00:28 -050052 // vector to hold messages sent to listener
53 std::vector<std::string> messages;
Ben Tyner8c2f8b22020-03-27 10:39:31 -050054 // we will catch any exceptions from thread library
55 try
56 {
57 // create new message queue or open existing
58 message_queue mq(open_or_create, mq_listener, 1, max_command_len);
59
60 // message queue parameters
61 char buffer[max_command_len + 1];
62 size_t recvd_size;
63 unsigned int priority;
64
65 // We will continue receiving messages until we receive
66 // a msg_send_end message to indicate all command line parameters
67 // have been sent.
68 do
69 {
70 // wait for a message to arrive
71 mq.receive((void*)&buffer, max_command_len, recvd_size,
72 priority);
73
74 // null terminate message and store
75 buffer[recvd_size] = '\0';
76 messages.push_back(buffer);
77
78 } while (buffer != std::string(msg_send_end));
79
80 messages.pop_back(); // remove msg_send_end message
81
82 // convert messages to command line arguments
83 std::vector<char*> argv;
84
Ben Tyner1c4b02e2020-11-09 14:00:29 -060085 std::transform(messages.begin(), messages.end(),
86 std::back_inserter(argv), (char*)data());
Ben Tyner8c2f8b22020-03-27 10:39:31 -050087
88 int argc = argv.size();
89 argv.push_back(nullptr);
90
91 // stop attention handler daemon?
92 if (true == getCliOption(argv.data(), argv.data() + argc, "--stop"))
93 {
94 message_queue::remove(mq_listener);
95 break;
96 }
97
98 // parse config options
Ben Tyner72feadc2020-04-06 12:57:31 -050099 parseConfig(argv.data(), argv.data() + argc, &attnConfig);
Ben Tyner8c2f8b22020-03-27 10:39:31 -0500100
101 // start attention handler daemon?
102 if (true ==
103 getCliOption(argv.data(), argv.data() + argc, "--start"))
104 {
105 if (false == gpioMonEnabled)
106 {
107 if (0 == pthread_create(&ptidGpio, NULL, &threadGpioMon,
Ben Tyner72feadc2020-04-06 12:57:31 -0500108 &attnConfig))
Ben Tyner8c2f8b22020-03-27 10:39:31 -0500109 {
110 gpioMonEnabled = true;
111 }
112 else
113 {
114 break;
115 }
116 }
117 }
118 }
119
120 catch (interprocess_exception& e)
121 {
122 break;
123 }
124 } while (1);
125
126 // stop the gpio monitor if running
127 if (true == gpioMonEnabled)
128 {
129 pthread_cancel(ptidGpio);
130 }
131
132 pthread_exit(NULL);
133}
134
135/** @brief Send command line to a threadi */
136int sendCmdLine(int i_argc, char** i_argv)
137{
138 int count = 0; // number of arguments sent
139
140 using namespace boost::interprocess;
141
142 try
143 {
144 message_queue mq(open_only, mq_listener);
145
146 while (count < i_argc)
147 {
148 mq.send(i_argv[count], strlen(i_argv[count]), 0);
149 count++;
150 }
151 // indicate to listener last cmdline arg was sent
152 mq.send(msg_send_end, strlen(msg_send_end), 0);
153 }
154 catch (interprocess_exception& e)
155 {
156 count = 0; // assume no arguments sent
157 }
158 return count;
159}
160
161/** @brief See if the listener thread message queue exists */
162bool listenerMqExists()
163{
164 using namespace boost::interprocess;
165
166 try
167 {
168 message_queue mq(open_only, mq_listener);
169 return true;
170 }
171 catch (interprocess_exception& e)
172 {
173 return false;
174 }
175}