blob: 60732c30a48c9ced611a1d1064abdad47bf1b1d0 [file] [log] [blame]
James Kuszmaul3224b8e2022-01-07 19:00:39 -08001#ifndef AOS_STARTER_SUBPROCESS_H_
2#define AOS_STARTER_SUBPROCESS_H_
3
James Kuszmauld42edb42022-01-07 18:00:16 -08004#include <memory>
James Kuszmaul3224b8e2022-01-07 19:00:39 -08005#include <string>
James Kuszmauld42edb42022-01-07 18:00:16 -08006#include <tuple>
James Kuszmaul3224b8e2022-01-07 19:00:39 -08007#include <vector>
8
9#include "aos/events/event_loop.h"
10#include "aos/events/shm_event_loop.h"
11#include "aos/starter/starter_generated.h"
12#include "aos/starter/starter_rpc_generated.h"
13#include "aos/util/scoped_pipe.h"
James Kuszmaul6295a642022-03-22 15:23:59 -070014#include "aos/util/top.h"
James Kuszmaul3224b8e2022-01-07 19:00:39 -080015
16namespace aos::starter {
17
18// Registers a signalfd listener with the given event loop and calls callback
19// whenever a signal is received.
20class SignalListener {
21 public:
22 SignalListener(aos::ShmEventLoop *loop,
23 std::function<void(signalfd_siginfo)> callback);
24 SignalListener(aos::ShmEventLoop *loop,
25 std::function<void(signalfd_siginfo)> callback,
26 std::initializer_list<unsigned int> signals);
27
28 ~SignalListener();
29
30 private:
31 aos::ShmEventLoop *loop_;
32 std::function<void(signalfd_siginfo)> callback_;
33 aos::ipc_lib::SignalFd signalfd_;
34
35 DISALLOW_COPY_AND_ASSIGN(SignalListener);
36};
37
Austin Schuhbbeb37e2022-08-17 16:19:27 -070038// Class to use the V1 cgroup API to limit memory usage.
39class MemoryCGroup {
40 public:
41 MemoryCGroup(std::string_view name);
42 ~MemoryCGroup();
43
44 // Adds a thread ID to be managed by the cgroup.
45 void AddTid(pid_t pid = 0);
46
47 // Sets the provided limit to the provided value.
48 void SetLimit(std::string_view limit_name, uint64_t limit_value);
49
50 private:
51 std::string cgroup_;
52};
53
James Kuszmaul3224b8e2022-01-07 19:00:39 -080054// Manages a running process, allowing starting and stopping, and restarting
55// automatically.
56class Application {
57 public:
payton.rehl2841b1c2023-05-25 17:23:55 -070058 enum class QuietLogging { kYes, kNo };
James Kuszmauld42edb42022-01-07 18:00:16 -080059 Application(const aos::Application *application, aos::EventLoop *event_loop,
payton.rehl2841b1c2023-05-25 17:23:55 -070060 std::function<void()> on_change,
61 QuietLogging quiet_flag = QuietLogging::kNo);
James Kuszmauld42edb42022-01-07 18:00:16 -080062
Sarah Newman2c1b1212022-08-10 10:05:48 -070063 // executable_name is the actual executable path.
64 // When sudo is not used, name is used as argv[0] when exec'ing
65 // executable_name. When sudo is used it's not possible to pass in a
66 // distinct argv[0].
James Kuszmauld42edb42022-01-07 18:00:16 -080067 Application(std::string_view name, std::string_view executable_name,
payton.rehl2841b1c2023-05-25 17:23:55 -070068 aos::EventLoop *event_loop, std::function<void()> on_change,
69 QuietLogging quiet_flag = QuietLogging::kNo);
James Kuszmaul3224b8e2022-01-07 19:00:39 -080070
71 flatbuffers::Offset<aos::starter::ApplicationStatus> PopulateStatus(
James Kuszmaul6295a642022-03-22 15:23:59 -070072 flatbuffers::FlatBufferBuilder *builder, util::Top *top);
James Kuszmauld42edb42022-01-07 18:00:16 -080073 aos::starter::State status() const { return status_; };
James Kuszmaul3224b8e2022-01-07 19:00:39 -080074
75 // Returns the last pid of this process. -1 if not started yet.
76 pid_t get_pid() const { return pid_; }
77
78 // Handles a SIGCHLD signal received by the parent. Does nothing if this
79 // process was not the target. Returns true if this Application should be
80 // removed.
81 bool MaybeHandleSignal();
James Kuszmauld42edb42022-01-07 18:00:16 -080082 void DisableChildDeathPolling() { child_status_handler_->Disable(); }
James Kuszmaul3224b8e2022-01-07 19:00:39 -080083
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
James Kuszmauld42edb42022-01-07 18:00:16 -080094 void set_args(std::vector<std::string> args);
95 void set_capture_stdout(bool capture);
96 void set_capture_stderr(bool capture);
Sanjay Narayanan01a228f2022-04-26 14:19:30 -070097 void set_run_as_sudo(bool value) { run_as_sudo_ = value; }
James Kuszmaul3224b8e2022-01-07 19:00:39 -080098
99 bool autostart() const { return autostart_; }
100
101 bool autorestart() const { return autorestart_; }
102
James Kuszmauld42edb42022-01-07 18:00:16 -0800103 const std::string &GetStdout();
104 const std::string &GetStderr();
105 std::optional<int> exit_code() const { return exit_code_; }
106
Austin Schuhbbeb37e2022-08-17 16:19:27 -0700107 // Sets the memory limit for the application to the provided limit.
108 void SetMemoryLimit(size_t limit) {
109 if (!memory_cgroup_) {
110 memory_cgroup_ = std::make_unique<MemoryCGroup>(name_);
111 }
112 memory_cgroup_->SetLimit("memory.limit_in_bytes", limit);
113 }
114
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800115 private:
James Kuszmauld42edb42022-01-07 18:00:16 -0800116 typedef aos::util::ScopedPipe::PipePair PipePair;
Sanjay Narayanan01a228f2022-04-26 14:19:30 -0700117
Philipp Schrader790cb542023-07-05 21:06:52 -0700118 static constexpr const char *const kSudo{"sudo"};
Sanjay Narayanan01a228f2022-04-26 14:19:30 -0700119
James Kuszmauld42edb42022-01-07 18:00:16 -0800120 void set_args(
121 const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
122 &args);
123
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800124 void DoStart();
125
126 void DoStop(bool restart);
127
128 void QueueStart();
129
130 // Copy flatbuffer vector of strings to vector of std::string.
131 static std::vector<std::string> FbsVectorToVector(
132 const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> &v);
133
134 static std::optional<uid_t> FindUid(const char *name);
135 static std::optional<gid_t> FindPrimaryGidForUser(const char *name);
136
James Kuszmauld42edb42022-01-07 18:00:16 -0800137 void FetchOutputs();
138
139 // Provides an std::vector of the args (such that CArgs().data() ends up being
140 // suitable to pass to execve()).
141 // The points are invalidated when args_ changes (e.g., due to a set_args
142 // call).
143 std::vector<char *> CArgs();
144
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800145 // Next unique id for all applications
146 static inline uint64_t next_id_ = 0;
147
148 std::string name_;
149 std::string path_;
James Kuszmauld42edb42022-01-07 18:00:16 -0800150 std::vector<std::string> args_;
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800151 std::string user_name_;
152 std::optional<uid_t> user_;
153 std::optional<gid_t> group_;
Sanjay Narayanan01a228f2022-04-26 14:19:30 -0700154 bool run_as_sudo_ = false;
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800155
James Kuszmauld42edb42022-01-07 18:00:16 -0800156 bool capture_stdout_ = false;
157 PipePair stdout_pipes_;
158 std::string stdout_;
159 bool capture_stderr_ = false;
160 PipePair stderr_pipes_;
161 std::string stderr_;
162
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800163 pid_t pid_ = -1;
James Kuszmauld42edb42022-01-07 18:00:16 -0800164 PipePair status_pipes_;
165 uint64_t id_ = 0;
166 std::optional<int> exit_code_;
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800167 aos::monotonic_clock::time_point start_time_, exit_time_;
168 bool queue_restart_ = false;
169 bool terminating_ = false;
James Kuszmauld42edb42022-01-07 18:00:16 -0800170 bool autostart_ = false;
171 bool autorestart_ = false;
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800172
173 aos::starter::State status_ = aos::starter::State::STOPPED;
174 aos::starter::LastStopReason stop_reason_ =
175 aos::starter::LastStopReason::STOP_REQUESTED;
176
177 aos::EventLoop *event_loop_;
James Kuszmauld42edb42022-01-07 18:00:16 -0800178 aos::TimerHandler *start_timer_, *restart_timer_, *stop_timer_, *pipe_timer_,
179 *child_status_handler_;
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800180
181 std::function<void()> on_change_;
182
Austin Schuhbbeb37e2022-08-17 16:19:27 -0700183 std::unique_ptr<MemoryCGroup> memory_cgroup_;
184
payton.rehl2841b1c2023-05-25 17:23:55 -0700185 QuietLogging quiet_flag_ = QuietLogging::kNo;
186
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800187 DISALLOW_COPY_AND_ASSIGN(Application);
188};
189
190} // namespace aos::starter
James Kuszmauld42edb42022-01-07 18:00:16 -0800191#endif // AOS_STARTER_SUBPROCESS_H_