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