blob: c8ae64276f2d0e65be8539d41571e4d5db833f59 [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
17/** @brief structure for holding main args (for threads) */
18typedef struct
19{
20 int argc;
21 char** argv;
22} MainArgs_t;
23
24/**
25 * @brief Start a thread to monitor the attention GPIO
26 *
27 * @param i_config Attention handler configuration object
28 */
29void* threadGpioMon(void* i_config)
30{
31 // Configure and start attention monitor
32 attn::attnDaemon((attn::Config*)i_config);
33
34 pthread_exit(NULL);
35}
36
37/** @brief Start a thread to listen for attention handler messages */
38void* threadListener(void* i_params)
39{
40 using namespace boost::interprocess;
41
42 // convert thread params to main arguments
43 int argc = static_cast<MainArgs_t*>(i_params)->argc;
44 char** argv = static_cast<MainArgs_t*>(i_params)->argv;
45
46 // vector to hold messages sent to listener
47 std::vector<std::string> messages;
48
49 // remove listener message queue if exists (does not throw)
50 message_queue::remove(mq_listener);
51
52 // thread handle for gpio monitor
53 pthread_t ptidGpio;
54
55 // status of gpio monitor
56 bool gpioMonEnabled = false;
57
58 // Parse command line args to see if any flags were passed, update the
59 // booleans accordingly and pass them to the config object constructor.
60 bool vital_enable = true;
61 bool checkstop_enable = true;
62 bool ti_enable = true;
63 bool bp_enable = true;
64
65 // parse config options
66 parseConfig(argv, argv + argc, vital_enable, checkstop_enable, ti_enable,
67 bp_enable);
68
69 // create config
70 attn::Config config(vital_enable, checkstop_enable, ti_enable, bp_enable);
71
72 // initialize pdbg targets
73 pdbg_targets_init(nullptr);
74
75 // This is the main listener loop. All the above code will be executed
76 // only once. All other communtication with the attention handler will
77 // originate from here via the message queue.
78 do
79 {
80 // we will catch any exceptions from thread library
81 try
82 {
83 // create new message queue or open existing
84 message_queue mq(open_or_create, mq_listener, 1, max_command_len);
85
86 // message queue parameters
87 char buffer[max_command_len + 1];
88 size_t recvd_size;
89 unsigned int priority;
90
91 // We will continue receiving messages until we receive
92 // a msg_send_end message to indicate all command line parameters
93 // have been sent.
94 do
95 {
96 // wait for a message to arrive
97 mq.receive((void*)&buffer, max_command_len, recvd_size,
98 priority);
99
100 // null terminate message and store
101 buffer[recvd_size] = '\0';
102 messages.push_back(buffer);
103
104 } while (buffer != std::string(msg_send_end));
105
106 messages.pop_back(); // remove msg_send_end message
107
108 // convert messages to command line arguments
109 std::vector<char*> argv;
110
111 for (const auto& arg : messages)
112 {
113 argv.push_back((char*)arg.data());
114 }
115
116 int argc = argv.size();
117 argv.push_back(nullptr);
118
119 // stop attention handler daemon?
120 if (true == getCliOption(argv.data(), argv.data() + argc, "--stop"))
121 {
122 message_queue::remove(mq_listener);
123 break;
124 }
125
126 // parse config options
127 parseConfig(argv.data(), argv.data() + argc, vital_enable,
128 checkstop_enable, ti_enable, bp_enable);
129
130 // set config
131 config.setConfig(vital_enable, checkstop_enable, ti_enable,
132 bp_enable);
133
134 // start attention handler daemon?
135 if (true ==
136 getCliOption(argv.data(), argv.data() + argc, "--start"))
137 {
138 if (false == gpioMonEnabled)
139 {
140 if (0 == pthread_create(&ptidGpio, NULL, &threadGpioMon,
141 &config))
142 {
143 gpioMonEnabled = true;
144 }
145 else
146 {
147 break;
148 }
149 }
150 }
151 }
152
153 catch (interprocess_exception& e)
154 {
155 break;
156 }
157 } while (1);
158
159 // stop the gpio monitor if running
160 if (true == gpioMonEnabled)
161 {
162 pthread_cancel(ptidGpio);
163 }
164
165 pthread_exit(NULL);
166}
167
168/** @brief Send command line to a threadi */
169int sendCmdLine(int i_argc, char** i_argv)
170{
171 int count = 0; // number of arguments sent
172
173 using namespace boost::interprocess;
174
175 try
176 {
177 message_queue mq(open_only, mq_listener);
178
179 while (count < i_argc)
180 {
181 mq.send(i_argv[count], strlen(i_argv[count]), 0);
182 count++;
183 }
184 // indicate to listener last cmdline arg was sent
185 mq.send(msg_send_end, strlen(msg_send_end), 0);
186 }
187 catch (interprocess_exception& e)
188 {
189 count = 0; // assume no arguments sent
190 }
191 return count;
192}
193
194/** @brief See if the listener thread message queue exists */
195bool listenerMqExists()
196{
197 using namespace boost::interprocess;
198
199 try
200 {
201 message_queue mq(open_only, mq_listener);
202 return true;
203 }
204 catch (interprocess_exception& e)
205 {
206 return false;
207 }
208}