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