diff --git a/docker-build-centos.sh b/docker-build-centos.sh index ea09c2e..72e50fe 100755 --- a/docker-build-centos.sh +++ b/docker-build-centos.sh @@ -19,10 +19,10 @@ export PATH=/opt/rh/devtoolset-7/root/usr/bin:\$PATH mkdir /build cd /build -wget -O capnproto.tar.gz https://github.com/capnproto/capnproto/archive/06a7136708955d91f8ddc1fa3d54e620eacba13e.tar.gz +wget -O capnproto.tar.gz https://github.com/capnproto/capnproto/archive/df67f26862c011c6efb31a28fb0d2a2ca1b94ac8.tar.gz wget -O rapidjson.tar.gz https://github.com/miloyip/rapidjson/archive/v1.1.0.tar.gz md5sum -c <sendMessage(j.str()); - } Laminar::~Laminar() { @@ -501,21 +500,6 @@ std::shared_ptr Laminar::queueJob(std::string name, ParamMap params) { return run; } -// Reaps a zombie and steps the corresponding Run to its next state. -// Should be called on SIGCHLD -void Laminar::reapChildren() { - int ret = 0; - pid_t pid; - while((pid = waitpid(-1, &ret, WNOHANG)) > 0) { - LLOG(INFO, "Reaping", pid); - auto it = pids.find(pid); - it->second->fulfill(kj::mv(ret)); - pids.erase(it); - } - - assignNewJobs(); -} - void Laminar::notifyConfigChanged() { loadConfiguration(); @@ -688,6 +672,7 @@ bool Laminar::tryStartRun(std::shared_ptr run, int queueIndex) { // notify the rpc client if the start command was used run->started.fulfiller->fulfill(); + // this actually spawns the first step srv->addTask(handleRunStep(run.get()).then([this,run]{ runFinished(run.get()); })); @@ -716,11 +701,9 @@ kj::Promise Laminar::handleRunStep(Run* run) { return kj::READY_NOW; } + kj::Promise exited = srv->onChildExit(run->current_pid); // promise is fulfilled when the process is reaped. But first we wait for all // output from the pipe (Run::output_fd) to be consumed. - auto paf = kj::newPromiseAndFulfiller(); - pids.emplace(run->current_pid, kj::mv(paf.fulfiller)); - return srv->readDescriptor(run->output_fd, [this,run](const char*b,size_t n){ // handle log output std::string s(b, n); @@ -729,7 +712,7 @@ kj::Promise Laminar::handleRunStep(Run* run) { if(c->scope.wantsLog(run->name, run->build)) c->sendMessage(s); } - }).then([p = std::move(paf.promise)]() mutable { + }).then([p = std::move(exited)]() mutable { // wait until the process is reaped return kj::mv(p); }).then([this, run](int status){ @@ -791,7 +774,9 @@ void Laminar::runFinished(Run * r) { w->complete(r); } - // erase reference to run from activeJobs + // erase reference to run from activeJobs. Since runFinished is called in a + // lambda whose context contains a shared_ptr, the run won't be deleted + // until the context is destroyed at the end of the lambda execution. activeJobs.byRunPtr().erase(r); // remove old run directories @@ -813,6 +798,9 @@ void Laminar::runFinished(Run * r) { break; fs::remove_all(d); } + + // in case we freed up an executor, check the queue + assignNewJobs(); } class MappedFileImpl : public MappedFile { diff --git a/src/laminar.h b/src/laminar.h index ce00895..8c898b2 100644 --- a/src/laminar.h +++ b/src/laminar.h @@ -58,7 +58,6 @@ public: kj::Own getArtefact(std::string path) override; std::string getCustomCss() override; void abortAll() override; - void reapChildren() override; void notifyConfigChanged() override; private: @@ -83,7 +82,6 @@ private: std::unordered_map> jobTags; RunSet activeJobs; - std::map>> pids; Database* db; Server* srv; NodeMap nodes; diff --git a/src/main.cpp b/src/main.cpp index 73f025d..a76b51f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,8 +18,8 @@ /// #include "laminar.h" #include "log.h" - #include +#include static Laminar* laminar; @@ -35,9 +35,10 @@ int main(int argc, char** argv) { } laminar = new Laminar; - + kj::UnixEventPort::captureChildExit(); signal(SIGINT, &laminar_quit); signal(SIGTERM, &laminar_quit); + laminar->run(); delete laminar; diff --git a/src/run.cpp b/src/run.cpp index 2fc8169..3b3186f 100644 --- a/src/run.cpp +++ b/src/run.cpp @@ -139,7 +139,10 @@ void Run::addEnv(std::string path) { void Run::abort() { // clear all pending scripts std::queue