blob: 008c46f085b3b4cec56b9750743b9c63cee359b2 [file] [log] [blame]
Tyler Chatowa79419d2020-08-12 20:12:11 -07001#include "starterd_lib.h"
2
Tyler Chatowa79419d2020-08-12 20:12:11 -07003#include <algorithm>
4#include <utility>
5
James Kuszmaul293b2172021-11-10 16:20:48 -08006#include "absl/strings/str_format.h"
7#include "aos/json_to_flatbuffer.h"
Tyler Chatowa79419d2020-08-12 20:12:11 -07008#include "glog/logging.h"
9#include "glog/stl_logging.h"
10
11namespace aos {
12namespace starter {
13
James Kuszmaul293b2172021-11-10 16:20:48 -080014const aos::Channel *StatusChannelForNode(const aos::Configuration *config,
15 const aos::Node *node) {
16 return configuration::GetChannel<Status>(config, "/aos", "", node);
17}
18const aos::Channel *StarterRpcChannelForNode(const aos::Configuration *config,
19 const aos::Node *node) {
20 return configuration::GetChannel<StarterRpc>(config, "/aos", "", node);
21}
22
Tyler Chatowa79419d2020-08-12 20:12:11 -070023Starter::Starter(const aos::Configuration *event_loop_config)
24 : config_msg_(event_loop_config),
25 event_loop_(event_loop_config),
26 status_sender_(event_loop_.MakeSender<aos::starter::Status>("/aos")),
Austin Schuhfc304942021-10-16 14:20:05 -070027 status_timer_(event_loop_.AddTimer([this] {
28 SendStatus();
29 status_count_ = 0;
30 })),
Tyler Chatowa79419d2020-08-12 20:12:11 -070031 cleanup_timer_(event_loop_.AddTimer([this] { event_loop_.Exit(); })),
Austin Schuhfc304942021-10-16 14:20:05 -070032 max_status_count_(
33 event_loop_.GetChannel<aos::starter::Status>("/aos")->frequency() -
34 1),
Tyler Chatowa79419d2020-08-12 20:12:11 -070035 listener_(&event_loop_,
36 [this](signalfd_siginfo signal) { OnSignal(signal); }) {
Tyler Chatowa79419d2020-08-12 20:12:11 -070037 event_loop_.SkipAosLog();
38
39 event_loop_.OnRun([this] {
40 status_timer_->Setup(event_loop_.monotonic_now(),
Austin Schuhfc304942021-10-16 14:20:05 -070041 std::chrono::milliseconds(1000));
Tyler Chatowa79419d2020-08-12 20:12:11 -070042 });
43
James Kuszmaul293b2172021-11-10 16:20:48 -080044 if (!aos::configuration::MultiNode(config_msg_)) {
45 event_loop_.MakeWatcher(
46 "/aos",
47 [this](const aos::starter::StarterRpc &cmd) { HandleStarterRpc(cmd); });
48 } else {
49 for (const aos::Node *node : aos::configuration::GetNodes(config_msg_)) {
50 const Channel *channel = StarterRpcChannelForNode(config_msg_, node);
51 CHECK(channel != nullptr) << ": Failed to find channel /aos for "
52 << StarterRpc::GetFullyQualifiedName() << " on "
53 << node->name()->string_view();
54 if (!aos::configuration::ChannelIsReadableOnNode(channel,
55 event_loop_.node())) {
56 LOG(INFO) << "StarterRpc channel "
57 << aos::configuration::StrippedChannelToString(channel)
58 << " is not readable on "
59 << event_loop_.node()->name()->string_view();
60 } else {
61 event_loop_.MakeWatcher(channel->name()->string_view(),
62 [this](const aos::starter::StarterRpc &cmd) {
63 HandleStarterRpc(cmd);
64 });
65 }
Tyler Chatowa79419d2020-08-12 20:12:11 -070066 }
James Kuszmaul293b2172021-11-10 16:20:48 -080067 }
Tyler Chatowa79419d2020-08-12 20:12:11 -070068
69 if (config_msg_->has_applications()) {
70 const flatbuffers::Vector<flatbuffers::Offset<aos::Application>>
71 *applications = config_msg_->applications();
Ravago Jones7e2dd322020-11-21 15:58:58 -080072
73 if (aos::configuration::MultiNode(config_msg_)) {
74 std::string_view current_node = event_loop_.node()->name()->string_view();
75 for (const aos::Application *application : *applications) {
76 CHECK(application->has_nodes());
77 for (const flatbuffers::String *node : *application->nodes()) {
78 if (node->string_view() == current_node) {
79 AddApplication(application);
80 break;
81 }
82 }
83 }
84 } else {
85 for (const aos::Application *application : *applications) {
86 AddApplication(application);
87 }
Tyler Chatowa79419d2020-08-12 20:12:11 -070088 }
89 }
90}
91
James Kuszmaul293b2172021-11-10 16:20:48 -080092void Starter::HandleStarterRpc(const StarterRpc &command) {
93 if (!command.has_command() || !command.has_name() || exiting_) {
94 return;
95 }
96
97 LOG(INFO) << "Received " << aos::FlatbufferToJson(&command);
98
99 if (command.has_nodes()) {
100 CHECK(aos::configuration::MultiNode(config_msg_));
101 bool relevant_to_this_node = false;
102 for (const flatbuffers::String *node : *command.nodes()) {
103 if (node->string_view() == event_loop_.node()->name()->string_view()) {
104 relevant_to_this_node = true;
105 }
106 }
107 if (!relevant_to_this_node) {
108 return;
109 }
110 }
111 // If not populated, restart regardless of node.
112
113 auto search = applications_.find(command.name()->str());
114 if (search != applications_.end()) {
115 // If an applicatione exists by the given name, dispatch the command
116 search->second.HandleCommand(command.command());
117 }
118}
119
Austin Schuhfc304942021-10-16 14:20:05 -0700120void Starter::MaybeSendStatus() {
121 if (status_count_ < max_status_count_) {
122 SendStatus();
123 ++status_count_;
124 } else {
125 VLOG(1) << "That's enough " << status_count_ << " " << max_status_count_;
126 }
127}
128
Tyler Chatowa79419d2020-08-12 20:12:11 -0700129void Starter::Cleanup() {
130 if (exiting_) {
131 return;
132 }
133 exiting_ = true;
134 for (auto &application : applications_) {
135 application.second.Terminate();
136 }
137 cleanup_timer_->Setup(event_loop_.monotonic_now() +
138 std::chrono::milliseconds(1500));
139}
140
141void Starter::OnSignal(signalfd_siginfo info) {
Tyler Chatowa79419d2020-08-12 20:12:11 -0700142 if (info.ssi_signo == SIGCHLD) {
143 // SIGCHLD messages can be collapsed if multiple are received, so all
144 // applications must check their status.
145 for (auto iter = applications_.begin(); iter != applications_.end();) {
146 if (iter->second.MaybeHandleSignal()) {
147 iter = applications_.erase(iter);
148 } else {
149 ++iter;
150 }
151 }
152
153 if (exiting_ && applications_.empty()) {
154 event_loop_.Exit();
155 }
Austin Schuh3204b332021-10-16 14:20:10 -0700156 } else {
157 LOG(INFO) << "Received signal '" << strsignal(info.ssi_signo) << "'";
158
159 if (std::find(kStarterDeath.begin(), kStarterDeath.end(), info.ssi_signo) !=
160 kStarterDeath.end()) {
161 LOG(WARNING) << "Starter shutting down";
162 Cleanup();
163 }
Tyler Chatowa79419d2020-08-12 20:12:11 -0700164 }
165}
166
167Application *Starter::AddApplication(const aos::Application *application) {
Austin Schuhfc304942021-10-16 14:20:05 -0700168 auto [iter, success] =
169 applications_.try_emplace(application->name()->str(), application,
170 &event_loop_, [this]() { MaybeSendStatus(); });
Tyler Chatowa79419d2020-08-12 20:12:11 -0700171 if (success) {
James Kuszmauld42edb42022-01-07 18:00:16 -0800172 // We should be catching and handling SIGCHLD correctly in the starter, so
173 // don't leave in the crutch for polling for the child process status (this
174 // is less about efficiency, and more about making sure bit rot doesn't
175 // result in the signal handling breaking).
176 iter->second.DisableChildDeathPolling();
Tyler Chatowa79419d2020-08-12 20:12:11 -0700177 return &(iter->second);
178 }
179 return nullptr;
180}
181
182void Starter::Run() {
Tyler Chatow03fdb2a2020-12-26 18:39:36 -0800183#ifdef AOS_ARCHITECTURE_arm_frc
184 PCHECK(setuid(0) == 0) << "Failed to change user to root";
185#endif
186
Tyler Chatowa79419d2020-08-12 20:12:11 -0700187 for (auto &application : applications_) {
Austin Schuh5f79a5a2021-10-12 17:46:50 -0700188 if (application.second.autostart()) {
189 application.second.Start();
190 }
Tyler Chatowa79419d2020-08-12 20:12:11 -0700191 }
192
193 event_loop_.Run();
194}
195
196void Starter::SendStatus() {
197 aos::Sender<aos::starter::Status>::Builder builder =
198 status_sender_.MakeBuilder();
199
200 std::vector<flatbuffers::Offset<aos::starter::ApplicationStatus>> statuses;
201
202 for (auto &application : applications_) {
203 statuses.push_back(application.second.PopulateStatus(builder.fbb()));
204 }
205
206 auto statuses_fbs = builder.fbb()->CreateVector(statuses);
207
208 aos::starter::Status::Builder status_builder(*builder.fbb());
209 status_builder.add_statuses(statuses_fbs);
milind1f1dca32021-07-03 13:50:07 -0700210 builder.CheckOk(builder.Send(status_builder.Finish()));
Tyler Chatowa79419d2020-08-12 20:12:11 -0700211}
212
213} // namespace starter
214} // namespace aos