blob: e1f82a01db2711bb476d897d4ad2c90aac89dc68 [file] [log] [blame]
Tyler Chatowa79419d2020-08-12 20:12:11 -07001#ifndef AOS_STARTER_STARTERD_LIB_H_
2#define AOS_STARTER_STARTERD_LIB_H_
3
Tyler Chatowa79419d2020-08-12 20:12:11 -07004#include <sys/signalfd.h>
5#include <sys/wait.h>
6
Tyler Chatowbf0609c2021-07-31 16:13:27 -07007#include <csignal>
8#include <cstdio>
Tyler Chatowa79419d2020-08-12 20:12:11 -07009#include <string>
10#include <unordered_map>
11#include <vector>
12
13#include "aos/configuration.h"
14#include "aos/events/shm_event_loop.h"
15#include "aos/ipc_lib/signalfd.h"
16#include "aos/macros.h"
17#include "aos/starter/starter_generated.h"
18#include "aos/starter/starter_rpc_generated.h"
19
20namespace aos {
21namespace starter {
22
23// RAII Pipe for sending individual ints between reader and writer.
24class ScopedPipe {
25 public:
26 class ScopedReadPipe;
27 class ScopedWritePipe;
28
29 static std::tuple<ScopedReadPipe, ScopedWritePipe> MakePipe();
30
31 virtual ~ScopedPipe();
32
33 int fd() const { return fd_; }
34
35 private:
36 ScopedPipe(int fd = -1);
37
38 int fd_;
39
40 ScopedPipe(const ScopedPipe &) = delete;
41 ScopedPipe &operator=(const ScopedPipe &) = delete;
42 ScopedPipe(ScopedPipe &&);
43 ScopedPipe &operator=(ScopedPipe &&);
44};
45
46class ScopedPipe::ScopedReadPipe : public ScopedPipe {
47 public:
48 std::optional<uint32_t> Read();
49
50 private:
51 using ScopedPipe::ScopedPipe;
52
53 friend class ScopedPipe;
54};
55
56class ScopedPipe::ScopedWritePipe : public ScopedPipe {
57 public:
58 void Write(uint32_t data);
59
60 private:
61 using ScopedPipe::ScopedPipe;
62
63 friend class ScopedPipe;
64};
65
66// Manages a running process, allowing starting and stopping, and restarting
67// automatically.
68class Application {
69 public:
70 Application(const aos::Application *application,
Austin Schuhfc304942021-10-16 14:20:05 -070071 aos::ShmEventLoop *event_loop, std::function<void()> on_change);
Tyler Chatowa79419d2020-08-12 20:12:11 -070072
73 flatbuffers::Offset<aos::starter::ApplicationStatus> PopulateStatus(
74 flatbuffers::FlatBufferBuilder *builder);
75
76 // Returns the last pid of this process. -1 if not started yet.
77 pid_t get_pid() const { return pid_; }
78
79 // Handles a SIGCHLD signal received by the parent. Does nothing if this
80 // process was not the target. Returns true if this Application should be
81 // removed.
82 bool MaybeHandleSignal();
83
84 // Handles a command. May do nothing if application is already in the desired
85 // state.
86 void HandleCommand(aos::starter::Command cmd);
87
88 void Start() { HandleCommand(aos::starter::Command::START); }
89
90 void Stop() { HandleCommand(aos::starter::Command::STOP); }
91
92 void Terminate();
93
94 void set_args(
95 const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
96 &args);
97
Austin Schuh5f79a5a2021-10-12 17:46:50 -070098 bool autostart() const { return autostart_; }
99
James Kuszmaule7c7e582022-01-07 18:50:01 -0800100 bool autorestart() const { return autorestart_; }
101
Tyler Chatowa79419d2020-08-12 20:12:11 -0700102 private:
103 void DoStart();
104
105 void DoStop(bool restart);
106
107 void QueueStart();
108
109 // Copy flatbuffer vector of strings to vector of std::string.
110 static std::vector<std::string> FbsVectorToVector(
111 const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> &v);
112
113 static std::optional<uid_t> FindUid(const char *name);
Austin Schuh529ac592021-10-14 16:11:13 -0700114 static std::optional<gid_t> FindPrimaryGidForUser(const char *name);
Tyler Chatowa79419d2020-08-12 20:12:11 -0700115
116 // Next unique id for all applications
117 static inline uint64_t next_id_ = 0;
118
119 std::string name_;
120 std::string path_;
121 std::vector<char *> args_;
James Kuszmaul4ff50272022-01-07 18:31:13 -0800122 std::string user_name_;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700123 std::optional<uid_t> user_;
Austin Schuh529ac592021-10-14 16:11:13 -0700124 std::optional<gid_t> group_;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700125
126 pid_t pid_ = -1;
127 ScopedPipe::ScopedReadPipe read_pipe_;
128 ScopedPipe::ScopedWritePipe write_pipe_;
129 uint64_t id_;
130 int exit_code_ = 0;
131 aos::monotonic_clock::time_point start_time_, exit_time_;
132 bool queue_restart_ = false;
133 bool terminating_ = false;
Austin Schuh5f79a5a2021-10-12 17:46:50 -0700134 bool autostart_ = true;
James Kuszmaule7c7e582022-01-07 18:50:01 -0800135 bool autorestart_ = true;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700136
137 aos::starter::State status_ = aos::starter::State::STOPPED;
138 aos::starter::LastStopReason stop_reason_ =
139 aos::starter::LastStopReason::STOP_REQUESTED;
140
141 aos::ShmEventLoop *event_loop_;
142 aos::TimerHandler *start_timer_, *restart_timer_, *stop_timer_;
143
Austin Schuhfc304942021-10-16 14:20:05 -0700144 std::function<void()> on_change_;
145
Tyler Chatowa79419d2020-08-12 20:12:11 -0700146 DISALLOW_COPY_AND_ASSIGN(Application);
147};
148
149// Registers a signalfd listener with the given event loop and calls callback
150// whenever a signal is received.
151class SignalListener {
152 public:
153 SignalListener(aos::ShmEventLoop *loop,
154 std::function<void(signalfd_siginfo)> callback);
155
156 ~SignalListener();
157
158 private:
159 aos::ShmEventLoop *loop_;
160 std::function<void(signalfd_siginfo)> callback_;
161 aos::ipc_lib::SignalFd signalfd_;
162
163 DISALLOW_COPY_AND_ASSIGN(SignalListener);
164};
165
James Kuszmaul293b2172021-11-10 16:20:48 -0800166const aos::Channel *StatusChannelForNode(const aos::Configuration *config,
167 const aos::Node *node);
168const aos::Channel *StarterRpcChannelForNode(const aos::Configuration *config,
169 const aos::Node *node);
170
Tyler Chatowa79419d2020-08-12 20:12:11 -0700171class Starter {
172 public:
173 Starter(const aos::Configuration *event_loop_config);
174
175 // Inserts a new application from config. Returns the inserted application if
176 // it was successful, otherwise nullptr if an application already exists
177 // with the given name.
178 Application *AddApplication(const aos::Application *application);
179
180 // Runs the event loop and starts all applications
181 void Run();
182
183 void Cleanup();
184
185 private:
186 // Signals which indicate starter has died
187 static const inline std::vector<int> kStarterDeath = {
188 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE,
189 SIGSEGV, SIGPIPE, SIGTERM, SIGBUS, SIGXCPU};
190
191 void OnSignal(signalfd_siginfo signal);
James Kuszmaul293b2172021-11-10 16:20:48 -0800192 void HandleStarterRpc(const StarterRpc &command);
Tyler Chatowa79419d2020-08-12 20:12:11 -0700193
Austin Schuhfc304942021-10-16 14:20:05 -0700194 // Sends the Status message if it wouldn't exceed the rate limit.
195 void MaybeSendStatus();
196
Tyler Chatowa79419d2020-08-12 20:12:11 -0700197 void SendStatus();
198
199 const std::string config_path_;
200 const aos::Configuration *config_msg_;
201
202 aos::ShmEventLoop event_loop_;
203 aos::Sender<aos::starter::Status> status_sender_;
204 aos::TimerHandler *status_timer_;
205 aos::TimerHandler *cleanup_timer_;
206
Austin Schuhfc304942021-10-16 14:20:05 -0700207 int status_count_ = 0;
208 const int max_status_count_;
209
Tyler Chatowa79419d2020-08-12 20:12:11 -0700210 std::unordered_map<std::string, Application> applications_;
211
212 // Set to true on cleanup to block rpc commands and ensure cleanup only
213 // happens once.
214 bool exiting_ = false;
215
216 SignalListener listener_;
217
218 DISALLOW_COPY_AND_ASSIGN(Starter);
219};
220
221} // namespace starter
222} // namespace aos
223
224#endif // AOS_STARTER_STARTERD_LIB_H_