1 #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 */
9 static constexpr const char* mq_listener = "openpower-hw-diags-mq";
10 
11 /** @brief maximum length of command line parameter */
12 static constexpr int max_command_len = 25;
13 
14 /** @brief end of command line args message */
15 static const char* msg_send_end = "999999999999999";
16 
17 /** @brief structure for holding main args (for threads) */
18 typedef 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  */
29 void* 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 */
38 void* 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 */
169 int 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 */
195 bool 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 }
209