Skip to content
This repository was archived by the owner on Oct 23, 2023. It is now read-only.

Commit 7cd6c18

Browse files
committed
Implement FIFOs for stdin/out/err and the "killed" flag.
1 parent c833d6a commit 7cd6c18

File tree

11 files changed

+193
-34
lines changed

11 files changed

+193
-34
lines changed

capnp/evaluation.capnp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,22 @@ struct ProcessRequest {
3737
localFile @1 :FileInfo;
3838
}
3939
args @2 :List(Text);
40-
stdin @3 :SHA256; # Hash of standard input
41-
inputFiles @4 :List(FileInfo); # Name and hash of other inputs
42-
outputFiles @5 :List(Text); # Name of outputs
43-
fifos @6 :List(FifoInfo); # Name and ID of FIFOs
44-
limits @7 :Resources;
45-
extraTime @8 :Float32; # Time that should be added to the cpu time limit.
40+
stdin :union {
41+
hash @3 :SHA256; # Hash of standard input
42+
fifo @4 :UInt32; # ID of the input FIFO
43+
}
44+
stdout @5 :UInt32; # ID of the stdout FIFO
45+
stderr @6 :UInt32; # ID of the stderr FIFO
46+
inputFiles @7 :List(FileInfo); # Name and hash of other inputs
47+
outputFiles @8 :List(Text); # Name of outputs
48+
fifos @9 :List(FifoInfo); # Name and ID of FIFOs
49+
limits @10 :Resources;
50+
extraTime @11 :Float32; # Time that should be added to the cpu time limit.
4651
}
4752

4853
struct Request {
4954
processes @0 :List(ProcessRequest);
5055
exclusive @1 :Bool; # If set, no other execution should run at the same time.
51-
52-
# TODO: FIFOs
5356
}
5457

5558
struct ProcessResult {
@@ -68,7 +71,8 @@ struct ProcessResult {
6871
stdout @10 :SHA256; # Hash of standard output
6972
stderr @11 :SHA256; # Hash of standard error
7073
outputFiles @12 :List(FileInfo); # Name and hash of other outputs
71-
wasCached @13 :Bool; # True if the answer comes from the cache.
74+
wasKilled @13 :Bool; # True if the execution was killed by the sandbox.
75+
wasCached @14 :Bool; # True if the answer comes from the cache.
7276
}
7377

7478
struct Result {

capnp/server.capnp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,25 @@ interface Execution {
3333
disableCache @5 ();
3434
makeExclusive @6 ();
3535
setLimits @7 (limits: Resources);
36-
setExtraTime @14 (extraTime: Float32);
36+
setExtraTime @8 (extraTime: Float32);
3737

3838
# Get file IDs representing outputs
39-
stdout @8 (isExecutable :Bool = false) -> (file :File);
40-
stderr @9 (isExecutable :Bool = false) -> (file :File);
41-
output @10 (name :Text, isExecutable :Bool = false) -> (file :File);
39+
stdout @9 (isExecutable :Bool = false) -> (file :File);
40+
stderr @10 (isExecutable :Bool = false) -> (file :File);
41+
output @11 (name :Text, isExecutable :Bool = false) -> (file :File);
4242

4343
# Add a FIFO
44-
addFifo @11 (name :Text, fifo :Fifo);
44+
setStdinFifo @12(fifo :Fifo);
45+
setStdoutFifo @13 (fifo :Fifo);
46+
setStderrFifo @14 (fifo :Fifo);
47+
addFifo @15 (name :Text, fifo :Fifo);
4548

4649
# To be called to be notified of the start of the evaluation
47-
notifyStart @12 ();
50+
notifyStart @16 ();
4851

4952
# The following methods will only complete (i.e. return or call callbacks)
5053
# when the evaluation is complete.
51-
getResult @13 () -> (result :ProcessResult);
54+
getResult @17 () -> (result :ProcessResult);
5255
}
5356

5457
interface ExecutionGroup {

cpp/frontend/frontend.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,30 @@ void Execution::addFifo(const std::string& name, Fifo* fifo) {
194194
builder_.AddPromise(req.send().ignoreResult());
195195
}));
196196
}
197+
void Execution::setStdinFifo(Fifo* fifo) {
198+
my_builder_.AddPromise(
199+
fifo->forked_promise.addBranch().then([this](auto fifo) {
200+
auto req = execution_.setStdinFifoRequest();
201+
req.setFifo(fifo);
202+
builder_.AddPromise(req.send().ignoreResult());
203+
}));
204+
}
205+
void Execution::setStdoutFifo(Fifo* fifo) {
206+
my_builder_.AddPromise(
207+
fifo->forked_promise.addBranch().then([this](auto fifo) {
208+
auto req = execution_.setStdoutFifoRequest();
209+
req.setFifo(fifo);
210+
builder_.AddPromise(req.send().ignoreResult());
211+
}));
212+
}
213+
void Execution::setStderrFifo(Fifo* fifo) {
214+
my_builder_.AddPromise(
215+
fifo->forked_promise.addBranch().then([this](auto fifo) {
216+
auto req = execution_.setStderrFifoRequest();
217+
req.setFifo(fifo);
218+
builder_.AddPromise(req.send().ignoreResult());
219+
}));
220+
}
197221

198222
void Execution::setArgs(const std::vector<std::string>& args) {
199223
auto req = execution_.setArgsRequest();
@@ -314,6 +338,7 @@ void Execution::getResult(std::function<void(Result)> callback,
314338
result.resources.stack =
315339
r.getResourceUsage().getStack();
316340
result.was_cached = r.getWasCached();
341+
result.was_killed = r.getWasKilled();
317342
callback(result);
318343
},
319344
[errored](auto exc) {

cpp/frontend/frontend.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct Result {
3232
uint32_t return_code;
3333
std::string error;
3434
Resources resources;
35+
bool was_killed;
3536
bool was_cached;
3637
};
3738

@@ -170,6 +171,9 @@ class Execution {
170171
void setStdin(File* file);
171172
void addInput(const std::string& name, File* file);
172173
void addFifo(const std::string& name, Fifo* fifo);
174+
void setStdinFifo(Fifo* fifo);
175+
void setStdoutFifo(Fifo* fifo);
176+
void setStderrFifo(Fifo* fifo);
173177

174178
void setArgs(const std::vector<std::string>& args);
175179

cpp/frontend/python/frontend.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ PYBIND11_MODULE(task_maker_frontend, m) {
6565
.def_readonly("error", &frontend::Result::error)
6666
.def_readonly("resources", &frontend::Result::resources)
6767
.def_readonly("was_cached", &frontend::Result::was_cached)
68+
.def_readonly("was_killed", &frontend::Result::was_killed)
6869
.def("__repr__", [](const frontend::Result& res) {
6970
std::string message = "<Result ";
7071
if (res.status == capnproto::ProcessResult::Status::Which::SUCCESS)
@@ -118,6 +119,9 @@ PYBIND11_MODULE(task_maker_frontend, m) {
118119
.def("setStdin", &frontend::Execution::setStdin, "file"_a)
119120
.def("addInput", &frontend::Execution::addInput, "name"_a, "file"_a)
120121
.def("addFifo", &frontend::Execution::addFifo, "name"_a, "fifo"_a)
122+
.def("setStdinFifo", &frontend::Execution::setStdinFifo, "fifo"_a)
123+
.def("setStdoutFifo", &frontend::Execution::setStdoutFifo, "fifo"_a)
124+
.def("setStderrFifo", &frontend::Execution::setStderrFifo, "fifo"_a)
121125
.def("setArgs", &frontend::Execution::setArgs, "args"_a)
122126
.def("disableCache", &frontend::Execution::disableCache)
123127
.def("makeExclusive", &frontend::Execution::makeExclusive)

cpp/sandbox/sandbox.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ struct ExecutionInfo {
7171
int64_t memory_usage_kb = 0;
7272
int32_t status_code = 0;
7373
int32_t signal = 0;
74+
bool killed = false;
7475
char message[8192] = {};
7576
};
7677

cpp/sandbox/unix.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,9 @@ bool Unix::Wait(ExecutionInfo* info, std::string* error_msg) {
369369
#endif
370370
info->status_code = WIFEXITED(child_status) ? WEXITSTATUS(child_status) : 0;
371371
info->signal = WIFSIGNALED(child_status) ? WTERMSIG(child_status) : 0;
372+
// If the child received a KILL or XCPU signal, assume we killed it
373+
// because of memory or time limits.
374+
info->killed = info->signal == SIGKILL || info->signal == SIGXCPU;
372375
info->wall_time_millis = elapsed_millis();
373376
info->cpu_time_millis =
374377
rusage.ru_utime.tv_sec * 1000LL + rusage.ru_utime.tv_usec / 1000;

cpp/server/cache.cpp

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ inline void hash_combine(std::size_t& hash, const T& v) {
1717
}
1818

1919
uint64_t RequestHasher::operator()(capnproto::Request::Reader reader_) const {
20-
size_t hash = 0;
20+
size_t hash = reader_.getProcesses().size();
2121
for (auto reader : reader_.getProcesses()) {
2222
hash_combine(hash, reader.getExecutable().which());
2323
switch (reader.getExecutable().which()) {
@@ -35,7 +35,18 @@ uint64_t RequestHasher::operator()(capnproto::Request::Reader reader_) const {
3535
for (std::string arg : reader.getArgs()) {
3636
hash_combine(hash, arg);
3737
}
38-
hash_combine(hash, util::SHA256_t(reader.getStdin()).Hex());
38+
hash_combine(hash, reader.getStdin().which());
39+
switch (reader.getStdin().which()) {
40+
case capnproto::ProcessRequest::Stdin::FIFO:
41+
hash_combine(hash, reader.getStdin().getFifo());
42+
break;
43+
case capnproto::ProcessRequest::Stdin::HASH:
44+
hash_combine(hash, util::SHA256_t(reader.getStdin().getHash()).Hex());
45+
break;
46+
}
47+
hash_combine(hash, reader.getStdout());
48+
hash_combine(hash, reader.getStderr());
49+
// TODO: be consistent if the files are permuted.
3950
for (auto in : reader.getInputFiles()) {
4051
hash_combine(hash, std::string(in.getName()));
4152
hash_combine(hash, util::SHA256_t(in.getHash()).Hex());
@@ -44,6 +55,10 @@ uint64_t RequestHasher::operator()(capnproto::Request::Reader reader_) const {
4455
for (std::string out : reader.getOutputFiles()) {
4556
hash_combine(hash, out);
4657
}
58+
for (auto in : reader.getFifos()) {
59+
hash_combine(hash, std::string(in.getName()));
60+
hash_combine(hash, in.getId());
61+
}
4762
hash_combine(hash, reader.getLimits().getCpuTime());
4863
hash_combine(hash, reader.getLimits().getWallTime());
4964
hash_combine(hash, reader.getLimits().getMemory());
@@ -84,9 +99,19 @@ bool RequestComparator::operator()(capnproto::Request::Reader a_,
8499
for (size_t i = 0; i < aargs.size(); i++) {
85100
if (aargs[i] != bargs[i]) return false;
86101
}
87-
if (util::SHA256_t(a.getStdin()).Hex() !=
88-
util::SHA256_t(b.getStdin()).Hex())
89-
return false;
102+
if (a.getStdin().which() != b.getStdin().which()) return false;
103+
switch (a.getStdin().which()) {
104+
case capnproto::ProcessRequest::Stdin::FIFO:
105+
if (a.getStdin().getFifo() != b.getStdin().getFifo()) return false;
106+
break;
107+
case capnproto::ProcessRequest::Stdin::HASH:
108+
if (util::SHA256_t(a.getStdin().getHash()).Hex() !=
109+
util::SHA256_t(b.getStdin().getHash()).Hex())
110+
return false;
111+
break;
112+
}
113+
if (a.getStdout() != b.getStdout()) return false;
114+
if (a.getStderr() != b.getStderr()) return false;
90115
std::vector<std::tuple<std::string, std::string, bool>> ainput;
91116
std::vector<std::tuple<std::string, std::string, bool>> binput;
92117
for (auto in : a.getInputFiles()) {
@@ -100,6 +125,17 @@ bool RequestComparator::operator()(capnproto::Request::Reader a_,
100125
std::sort(ainput.begin(), ainput.end());
101126
std::sort(binput.begin(), binput.end());
102127
if (ainput != binput) return false;
128+
std::vector<std::tuple<std::string, uint32_t>> afifo;
129+
std::vector<std::tuple<std::string, uint32_t>> bfifo;
130+
for (auto f : a.getFifos()) {
131+
afifo.emplace_back(f.getName(), f.getId());
132+
}
133+
for (auto f : b.getFifos()) {
134+
bfifo.emplace_back(f.getName(), f.getId());
135+
}
136+
std::sort(afifo.begin(), afifo.end());
137+
std::sort(bfifo.begin(), bfifo.end());
138+
if (afifo != bfifo) return false;
103139
std::vector<std::string> aoutput;
104140
std::vector<std::string> boutput;
105141
for (auto out : a.getOutputFiles()) {
@@ -132,7 +168,9 @@ std::vector<util::SHA256_t> Hashes(capnproto::Request::Reader req_,
132168
if (!hash.isZero()) ans.push_back(hash);
133169
};
134170
for (auto req : req_.getProcesses()) {
135-
add(req.getStdin());
171+
if (req.getStdin().isHash()) {
172+
add(req.getStdin().getHash());
173+
}
136174
if (req.getExecutable().isLocalFile())
137175
add(req.getExecutable().getLocalFile().getHash());
138176
for (auto f : req.getInputFiles()) add(f.getHash());

cpp/server/server.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ kj::Promise<void> Execution::setExecutable(SetExecutableContext context) {
177177
return kj::READY_NOW;
178178
}
179179
kj::Promise<void> Execution::setStdin(SetStdinContext context) {
180+
KJ_ASSERT(!stdin_ && !stdin_fifo_);
180181
KJ_LOG(INFO, "Execution " + description_,
181182
"Setting stdin file with id " +
182183
std::to_string(context.getParams().getFile().getId()));
@@ -233,7 +234,35 @@ kj::Promise<void> Execution::addFifo(AddFifoContext context) {
233234
context.getParams().getFifo().getId());
234235
return kj::READY_NOW;
235236
}
237+
kj::Promise<void> Execution::setStdinFifo(SetStdinFifoContext context) {
238+
KJ_ASSERT(!stdin_ && !stdin_fifo_);
239+
KJ_LOG(INFO, "Execution " + description_,
240+
"Adding FIFO with id " +
241+
std::to_string(context.getParams().getFifo().getId()) +
242+
" as stdin");
243+
stdin_fifo_ = context.getParams().getFifo().getId();
244+
return kj::READY_NOW;
245+
}
246+
kj::Promise<void> Execution::setStdoutFifo(SetStdoutFifoContext context) {
247+
KJ_ASSERT(!stdout_ && !stdout_fifo_);
248+
KJ_LOG(INFO, "Execution " + description_,
249+
"Addoutg FIFO with id " +
250+
std::to_string(context.getParams().getFifo().getId()) +
251+
" as stdout");
252+
stdout_fifo_ = context.getParams().getFifo().getId();
253+
return kj::READY_NOW;
254+
}
255+
kj::Promise<void> Execution::setStderrFifo(SetStderrFifoContext context) {
256+
KJ_ASSERT(!stderr_ && !stderr_fifo_);
257+
KJ_LOG(INFO, "Execution " + description_,
258+
"Adderrg FIFO with id " +
259+
std::to_string(context.getParams().getFifo().getId()) +
260+
" as stderr");
261+
stderr_fifo_ = context.getParams().getFifo().getId();
262+
return kj::READY_NOW;
263+
}
236264
kj::Promise<void> Execution::stdout(StdoutContext context) {
265+
KJ_ASSERT(!stdout_ && !stdout_fifo_);
237266
stdout_ = AddFileInfo(
238267
frontend_context_.last_file_id_, frontend_context_.file_info_,
239268
context.getResults().initFile(), context.getParams().getIsExecutable(),
@@ -243,6 +272,7 @@ kj::Promise<void> Execution::stdout(StdoutContext context) {
243272
return kj::READY_NOW;
244273
}
245274
kj::Promise<void> Execution::stderr(StderrContext context) {
275+
KJ_ASSERT(!stderr_ && !stderr_fifo_);
246276
stderr_ = AddFileInfo(
247277
frontend_context_.last_file_id_, frontend_context_.file_info_,
248278
context.getResults().initFile(), context.getParams().getIsExecutable(),
@@ -300,7 +330,15 @@ void Execution::prepareRequest() {
300330
hash.ToCapnp(builder);
301331
};
302332
if (stdin_) {
303-
get_hash(stdin_, request_.initStdin());
333+
get_hash(stdin_, request_.initStdin().initHash());
334+
} else if (stdin_fifo_) {
335+
request_.initStdin().setFifo(stdin_fifo_);
336+
}
337+
if (stdout_fifo_) {
338+
request_.setStdout(stdout_fifo_);
339+
}
340+
if (stderr_fifo_) {
341+
request_.setStderr(stderr_fifo_);
304342
}
305343
if (executable_) {
306344
get_hash(executable_, request_.getExecutable().getLocalFile().initHash());

cpp/server/server.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class Execution : public capnproto::Execution::Server {
4545
kj::Promise<void> setLimits(SetLimitsContext context);
4646
kj::Promise<void> setExtraTime(SetExtraTimeContext context);
4747
kj::Promise<void> addFifo(AddFifoContext context);
48+
kj::Promise<void> setStdinFifo(SetStdinFifoContext context);
49+
kj::Promise<void> setStdoutFifo(SetStdoutFifoContext context);
50+
kj::Promise<void> setStderrFifo(SetStderrFifoContext context);
4851
kj::Promise<void> stdout(StdoutContext context);
4952
kj::Promise<void> stderr(StderrContext context);
5053
kj::Promise<void> output(OutputContext context);
@@ -70,8 +73,11 @@ class Execution : public capnproto::Execution::Server {
7073
std::unordered_map<std::string, uint32_t> fifos_;
7174
uint32_t executable_ = 0;
7275
uint32_t stdin_ = 0;
76+
uint32_t stdin_fifo_ = 0;
7377
uint32_t stdout_ = 0;
78+
uint32_t stdout_fifo_ = 0;
7479
uint32_t stderr_ = 0;
80+
uint32_t stderr_fifo_ = 0;
7581
kj::PromiseFulfillerPair<void> finish_promise_ =
7682
kj::newPromiseAndFulfiller<void>();
7783
friend class ExecutionGroup;
@@ -104,7 +110,7 @@ class ExecutionGroup : public capnproto::ExecutionGroup::Server {
104110
uint32_t cache_enabled_ = true;
105111
kj::PromiseFulfillerPair<void> start_ = kj::newPromiseAndFulfiller<void>();
106112
kj::ForkedPromise<void> forked_start_ = start_.promise.fork();
107-
size_t next_fifo_ = 0;
113+
size_t next_fifo_ = 1;
108114
};
109115

110116
class FrontendContext : public capnproto::FrontendContext::Server {

0 commit comments

Comments
 (0)