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