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     // remove listener message queue if exists (does not throw)
43     message_queue::remove(mq_listener);
44 
45     // thread handle for gpio monitor
46     pthread_t ptidGpio;
47 
48     // status of gpio monitor
49     bool gpioMonEnabled = false;
50 
51     // create config
52     attn::Config attnConfig;
53 
54     // This is the main listener loop. All the above code will be executed
55     // only once. All other communtication with the attention handler will
56     // originate from here via the message queue.
57     do
58     {
59         // vector to hold messages sent to listener
60         std::vector<std::string> messages;
61         // we will catch any exceptions from thread library
62         try
63         {
64             // create new message queue or open existing
65             message_queue mq(open_or_create, mq_listener, 1, max_command_len);
66 
67             // message queue parameters
68             char buffer[max_command_len + 1];
69             size_t recvd_size;
70             unsigned int priority;
71 
72             // We will continue receiving messages until we receive
73             // a msg_send_end message to indicate all command line parameters
74             // have been sent.
75             do
76             {
77                 // wait for a message to arrive
78                 mq.receive((void*)&buffer, max_command_len, recvd_size,
79                            priority);
80 
81                 // null terminate message and store
82                 buffer[recvd_size] = '\0';
83                 messages.push_back(buffer);
84 
85             } while (buffer != std::string(msg_send_end));
86 
87             messages.pop_back(); // remove msg_send_end message
88 
89             // convert messages to command line arguments
90             std::vector<char*> argv;
91 
92             for (const auto& arg : messages)
93             {
94                 argv.push_back((char*)arg.data());
95             }
96 
97             int argc = argv.size();
98             argv.push_back(nullptr);
99 
100             // stop attention handler daemon?
101             if (true == getCliOption(argv.data(), argv.data() + argc, "--stop"))
102             {
103                 message_queue::remove(mq_listener);
104                 break;
105             }
106 
107             // parse config options
108             parseConfig(argv.data(), argv.data() + argc, &attnConfig);
109 
110             // start attention handler daemon?
111             if (true ==
112                 getCliOption(argv.data(), argv.data() + argc, "--start"))
113             {
114                 if (false == gpioMonEnabled)
115                 {
116                     if (0 == pthread_create(&ptidGpio, NULL, &threadGpioMon,
117                                             &attnConfig))
118                     {
119                         gpioMonEnabled = true;
120                     }
121                     else
122                     {
123                         break;
124                     }
125                 }
126             }
127         }
128 
129         catch (interprocess_exception& e)
130         {
131             break;
132         }
133     } while (1);
134 
135     // stop the gpio monitor if running
136     if (true == gpioMonEnabled)
137     {
138         pthread_cancel(ptidGpio);
139     }
140 
141     pthread_exit(NULL);
142 }
143 
144 /** @brief Send command line to a threadi */
145 int sendCmdLine(int i_argc, char** i_argv)
146 {
147     int count = 0; // number of arguments sent
148 
149     using namespace boost::interprocess;
150 
151     try
152     {
153         message_queue mq(open_only, mq_listener);
154 
155         while (count < i_argc)
156         {
157             mq.send(i_argv[count], strlen(i_argv[count]), 0);
158             count++;
159         }
160         // indicate to listener last cmdline arg was sent
161         mq.send(msg_send_end, strlen(msg_send_end), 0);
162     }
163     catch (interprocess_exception& e)
164     {
165         count = 0; // assume no arguments sent
166     }
167     return count;
168 }
169 
170 /** @brief See if the listener thread message queue exists */
171 bool listenerMqExists()
172 {
173     using namespace boost::interprocess;
174 
175     try
176     {
177         message_queue mq(open_only, mq_listener);
178         return true;
179     }
180     catch (interprocess_exception& e)
181     {
182         return false;
183     }
184 }
185