| Ben Tyner | 8c2f8b2 | 2020-03-27 10:39:31 -0500 | [diff] [blame] | 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 |  | 
| Ben Tyner | 8c2f8b2 | 2020-03-27 10:39:31 -0500 | [diff] [blame] | 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 |  | 
| Ben Tyner | 8c2f8b2 | 2020-03-27 10:39:31 -0500 | [diff] [blame] | 51 | // create config | 
| Ben Tyner | 72feadc | 2020-04-06 12:57:31 -0500 | [diff] [blame] | 52 | attn::Config attnConfig; | 
| Ben Tyner | 8c2f8b2 | 2020-03-27 10:39:31 -0500 | [diff] [blame] | 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 | { | 
| Ben Tyner | d3cda74 | 2020-05-04 08:00:28 -0500 | [diff] [blame] | 62 | // vector to hold messages sent to listener | 
|  | 63 | std::vector<std::string> messages; | 
| Ben Tyner | 8c2f8b2 | 2020-03-27 10:39:31 -0500 | [diff] [blame] | 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 | 
| Ben Tyner | 72feadc | 2020-04-06 12:57:31 -0500 | [diff] [blame] | 111 | parseConfig(argv.data(), argv.data() + argc, &attnConfig); | 
| Ben Tyner | 8c2f8b2 | 2020-03-27 10:39:31 -0500 | [diff] [blame] | 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, | 
| Ben Tyner | 72feadc | 2020-04-06 12:57:31 -0500 | [diff] [blame] | 120 | &attnConfig)) | 
| Ben Tyner | 8c2f8b2 | 2020-03-27 10:39:31 -0500 | [diff] [blame] | 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 | } |