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 */
threadGpioMon(void * i_config)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 */
threadListener(void * i_params)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 */
sendCmdLine(int i_argc,char ** i_argv)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 */
listenerMqExists()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