Skip to content

Commit 3598a3e

Browse files
committed
workshop/Workplace: move code to WorkshopOperator::Start()
1 parent b037c6d commit 3598a3e

File tree

3 files changed

+133
-121
lines changed

3 files changed

+133
-121
lines changed

src/workshop/Operator.cxx

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@
2525
#include "io/FdHolder.hxx"
2626
#include "io/FileAt.hxx"
2727
#include "io/Open.hxx"
28+
#include "io/Pipe.hxx"
2829
#include "util/DeleteDisposer.hxx"
30+
#include "util/StringCompare.hxx"
2931
#include "util/UTF8.hxx"
3032
#include "AllocatorPtr.hxx"
3133
#include "CgroupAccounting.hxx"
34+
#include "debug.h"
3235

3336
#include <fmt/core.h>
3437

@@ -98,6 +101,131 @@ WorkshopOperator::~WorkshopOperator() noexcept
98101
children.clear_and_dispose(DeleteDisposer{});
99102
}
100103

104+
static void
105+
PrepareChildProcess(PreparedChildProcess &p, const char *plan_name,
106+
const Plan &plan,
107+
FileDescriptor stderr_fd, SocketDescriptor control_fd)
108+
{
109+
p.hook_info = plan_name;
110+
p.stderr_fd = p.stdout_fd = stderr_fd;
111+
p.control_fd = control_fd.ToFileDescriptor();
112+
113+
if (!debug_mode) {
114+
p.uid_gid.effective_uid = plan.uid;
115+
p.uid_gid.effective_gid = plan.gid;
116+
117+
std::copy(plan.groups.begin(), plan.groups.end(),
118+
p.uid_gid.supplementary_groups.begin());
119+
}
120+
121+
if (!plan.chroot.empty())
122+
p.chroot = plan.chroot.c_str();
123+
124+
p.umask = plan.umask;
125+
p.rlimits = plan.rlimits;
126+
p.priority = plan.priority;
127+
p.sched_idle = plan.sched_idle;
128+
p.ioprio_idle = plan.ioprio_idle;
129+
p.ns.enable_network = plan.private_network;
130+
131+
if (plan.private_tmp)
132+
p.ns.mount.mount_tmp_tmpfs = "";
133+
134+
p.no_new_privs = true;
135+
}
136+
137+
void
138+
WorkshopOperator::Start(FileDescriptor stderr_w,
139+
SocketDescriptor control_child)
140+
{
141+
auto &spawn_service = workplace.GetSpawnService();
142+
143+
PreparedChildProcess p;
144+
PrepareChildProcess(p, job.plan_name.c_str(), *plan,
145+
stderr_w, control_child);
146+
147+
/* use a per-plan cgroup */
148+
149+
CgroupOptions cgroup;
150+
151+
UniqueSocketDescriptor return_cgroup;
152+
153+
if (auto *client = dynamic_cast<SpawnServerClient *>(&spawn_service)) {
154+
if (client->SupportsCgroups()) {
155+
p.cgroup = &cgroup;
156+
p.cgroup_session = job.id.c_str();
157+
158+
cgroup.name = job.plan_name.c_str();
159+
160+
std::tie(return_cgroup, p.return_cgroup) = CreateSocketPair(SOCK_SEQPACKET);
161+
}
162+
}
163+
164+
/* create stdout/stderr pipes */
165+
166+
UniqueFileDescriptor stdout_w;
167+
168+
if (!plan->control_channel) {
169+
/* if there is no control channel, read progress from the
170+
stdout pipe */
171+
UniqueFileDescriptor stdout_r;
172+
std::tie(stdout_r, stdout_w) = CreatePipe();
173+
174+
SetOutput(std::move(stdout_r));
175+
p.stdout_fd = stdout_w;
176+
}
177+
178+
/* build command line */
179+
180+
std::list<std::string> args;
181+
args.insert(args.end(), plan->args.begin(), plan->args.end());
182+
args.insert(args.end(), job.args.begin(), job.args.end());
183+
184+
Expand(args);
185+
186+
for (const auto &i : args) {
187+
if (p.args.size() >= 4096)
188+
throw std::runtime_error("Too many command-line arguments");
189+
190+
p.args.push_back(i.c_str());
191+
}
192+
193+
for (const auto &i : job.env) {
194+
if (p.env.size() >= 64)
195+
throw std::runtime_error("Too many environment variables");
196+
197+
if (StringStartsWith(i.c_str(), "LD_"))
198+
/* reject - too dangerous */
199+
continue;
200+
201+
p.env.push_back(i.c_str());
202+
}
203+
204+
/* fork */
205+
206+
SetPid(spawn_service.SpawnChildProcess(job.id.c_str(),
207+
std::move(p)));
208+
209+
logger(2, "job ", job.id, " (plan '", job.plan_name,
210+
"') started");
211+
212+
if (return_cgroup.IsDefined()) {
213+
/* close the other side of the socketpair if it's
214+
still open to avoid blocking the following receive
215+
call if the spawner has closed the socket without
216+
sending something */
217+
if (p.return_cgroup.IsDefined())
218+
p.return_cgroup.Close();
219+
220+
try {
221+
SetCgroup(EasyReceiveMessageWithOneFD(return_cgroup));
222+
} catch (...) {
223+
logger(1, "Failed to receive cgroup fd: ",
224+
std::current_exception());
225+
}
226+
}
227+
}
228+
101229
void
102230
WorkshopOperator::ScheduleTimeout() noexcept
103231
{

src/workshop/Operator.hxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ public:
108108
return job.plan_name;
109109
}
110110

111+
void Start(FileDescriptor stderr_w,
112+
SocketDescriptor control_child);
113+
111114
void SetPid(std::unique_ptr<ChildProcessHandle> &&_pid) noexcept {
112115
pid = std::move(_pid);
113116
pid->SetExitListener(*this);

src/workshop/Workplace.cxx

Lines changed: 2 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
#include "Workplace.hxx"
66
#include "Operator.hxx"
7-
#include "debug.h"
87
#include "Plan.hxx"
98
#include "Job.hxx"
109
#include "pg/Array.hxx"
@@ -17,7 +16,6 @@
1716
#include "net/UniqueSocketDescriptor.hxx"
1817
#include "io/Pipe.hxx"
1918
#include "util/DeleteDisposer.hxx"
20-
#include "util/StringCompare.hxx"
2119

2220
#include <cassert>
2321
#include <string>
@@ -86,39 +84,6 @@ WorkshopWorkplace::GetFullPlanNames() const noexcept
8684
return Pg::EncodeArray(list);
8785
}
8886

89-
static void
90-
PrepareChildProcess(PreparedChildProcess &p, const char *plan_name,
91-
const Plan &plan,
92-
FileDescriptor stderr_fd, SocketDescriptor control_fd)
93-
{
94-
p.hook_info = plan_name;
95-
p.stderr_fd = p.stdout_fd = stderr_fd;
96-
p.control_fd = control_fd.ToFileDescriptor();
97-
98-
if (!debug_mode) {
99-
p.uid_gid.effective_uid = plan.uid;
100-
p.uid_gid.effective_gid = plan.gid;
101-
102-
std::copy(plan.groups.begin(), plan.groups.end(),
103-
p.uid_gid.supplementary_groups.begin());
104-
}
105-
106-
if (!plan.chroot.empty())
107-
p.chroot = plan.chroot.c_str();
108-
109-
p.umask = plan.umask;
110-
p.rlimits = plan.rlimits;
111-
p.priority = plan.priority;
112-
p.sched_idle = plan.sched_idle;
113-
p.ioprio_idle = plan.ioprio_idle;
114-
p.ns.enable_network = plan.private_network;
115-
116-
if (plan.private_tmp)
117-
p.ns.mount.mount_tmp_tmpfs = "";
118-
119-
p.no_new_privs = true;
120-
}
121-
12287
void
12388
WorkshopWorkplace::Start(EventLoop &event_loop, const WorkshopJob &job,
12489
std::shared_ptr<Plan> plan,
@@ -147,97 +112,13 @@ WorkshopWorkplace::Start(EventLoop &event_loop, const WorkshopJob &job,
147112
? stderr_w.Duplicate()
148113
: UniqueFileDescriptor{};
149114

150-
auto o = std::make_unique<WorkshopOperator>(event_loop, *this, job, plan,
115+
auto o = std::make_unique<WorkshopOperator>(event_loop, *this, job, std::move(plan),
151116
std::move(stderr_r),
152117
std::move(stderr_w_for_operator),
153118
std::move(control_parent),
154119
max_log,
155120
enable_journal);
156-
157-
PreparedChildProcess p;
158-
PrepareChildProcess(p, job.plan_name.c_str(), *plan,
159-
stderr_w, control_child);
160-
161-
/* use a per-plan cgroup */
162-
163-
CgroupOptions cgroup;
164-
165-
UniqueSocketDescriptor return_cgroup;
166-
167-
if (auto *client = dynamic_cast<SpawnServerClient *>(&spawn_service)) {
168-
if (client->SupportsCgroups()) {
169-
p.cgroup = &cgroup;
170-
p.cgroup_session = job.id.c_str();
171-
172-
cgroup.name = job.plan_name.c_str();
173-
174-
std::tie(return_cgroup, p.return_cgroup) = CreateSocketPair(SOCK_SEQPACKET);
175-
}
176-
}
177-
178-
/* create stdout/stderr pipes */
179-
180-
UniqueFileDescriptor stdout_w;
181-
182-
if (!plan->control_channel) {
183-
/* if there is no control channel, read progress from the
184-
stdout pipe */
185-
UniqueFileDescriptor stdout_r;
186-
std::tie(stdout_r, stdout_w) = CreatePipe();
187-
188-
o->SetOutput(std::move(stdout_r));
189-
p.stdout_fd = stdout_w;
190-
}
191-
192-
/* build command line */
193-
194-
std::list<std::string> args;
195-
args.insert(args.end(), plan->args.begin(), plan->args.end());
196-
args.insert(args.end(), job.args.begin(), job.args.end());
197-
198-
o->Expand(args);
199-
200-
for (const auto &i : args) {
201-
if (p.args.size() >= 4096)
202-
throw std::runtime_error("Too many command-line arguments");
203-
204-
p.args.push_back(i.c_str());
205-
}
206-
207-
for (const auto &i : job.env) {
208-
if (p.env.size() >= 64)
209-
throw std::runtime_error("Too many environment variables");
210-
211-
if (StringStartsWith(i.c_str(), "LD_"))
212-
/* reject - too dangerous */
213-
continue;
214-
215-
p.env.push_back(i.c_str());
216-
}
217-
218-
/* fork */
219-
220-
o->SetPid(spawn_service.SpawnChildProcess(job.id.c_str(),
221-
std::move(p)));
222-
223-
logger(2, "job ", job.id, " (plan '", job.plan_name,
224-
"') started");
225-
226-
if (return_cgroup.IsDefined()) {
227-
/* close the other side of the socketpair if it's
228-
still open to avoid blocking the following receive
229-
call if the spawner has closed the socket without
230-
sending something */
231-
if (p.return_cgroup.IsDefined())
232-
p.return_cgroup.Close();
233-
234-
try {
235-
o->SetCgroup(EasyReceiveMessageWithOneFD(return_cgroup));
236-
} catch (...) {
237-
logger(1, "Failed to receive cgroup fd: ",
238-
std::current_exception());
239-
}
240-
}
121+
o->Start(stderr_w, control_child);
241122

242123
operators.push_back(*o.release());
243124
}

0 commit comments

Comments
 (0)