Loading executor.cpp +12 −4 Changes for executor.cpp: 12 added lines, 4 removed lines. Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ #include <sys/wait.h> #include <unistd.h> #include <spawn.h> #include <poll.h> extern char** environ; Loading Loading @@ -334,19 +335,26 @@ std::vector<std::string> Executor::collect_exports(const Makefile& mf) { bool Executor::js_acquire(bool& used_free) { used_free = false; if (!js_active_) return true; for (;;) { // Prefer this process's implicit free token. Re-checked every loop so a // sibling thread releasing it (an atomic store) lets a waiter proceed. bool expected = true; if (js_free_token_.compare_exchange_strong(expected, false)) { used_free = true; return true; } for (;;) { // Try to grab a shared token from the (non-blocking) jobserver pipe. char tok; ssize_t n = ::read(js_read_fd_, &tok, 1); if (n == 1) return true; if (n < 0 && errno == EINTR) continue; // Pipe closed/error: fall back to running without a token rather than // deadlocking the build. return true; if (n == 0) return true; // write end fully closed: avoid deadlock if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) return true; // unexpected error: avoid deadlock // No token available right now. Wait briefly for the pipe to become // readable, but cap the wait so a freed-up free token is noticed. struct pollfd pfd{ js_read_fd_, POLLIN, 0 }; ::poll(&pfd, 1, 50); } } Loading executor.h +11 −0 Changes for executor.h: 11 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ #include <queue> #include <atomic> #include <memory> #include <fcntl.h> namespace makeplus { Loading @@ -28,6 +29,16 @@ public: js_read_fd_ = read_fd; js_write_fd_ = write_fd; js_active_ = (read_fd >= 0 && write_fd >= 0); if (js_active_) { // The whole recursive make tree is makeplus, so we control both ends // of the jobserver pipe. Make the read end non-blocking: a worker // waiting for a token must be able to wake up when this process's // per-process "free" token is released (an atomic, which cannot wake // a blocking read()), otherwise a thread that has committed to a // target could hang forever once the pipe is empty. int fl = ::fcntl(read_fd, F_GETFL); if (fl != -1) ::fcntl(read_fd, F_SETFL, fl | O_NONBLOCK); } } int build(const std::vector<std::string>& targets); Loading Loading
executor.cpp +12 −4 Changes for executor.cpp: 12 added lines, 4 removed lines. Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ #include <sys/wait.h> #include <unistd.h> #include <spawn.h> #include <poll.h> extern char** environ; Loading Loading @@ -334,19 +335,26 @@ std::vector<std::string> Executor::collect_exports(const Makefile& mf) { bool Executor::js_acquire(bool& used_free) { used_free = false; if (!js_active_) return true; for (;;) { // Prefer this process's implicit free token. Re-checked every loop so a // sibling thread releasing it (an atomic store) lets a waiter proceed. bool expected = true; if (js_free_token_.compare_exchange_strong(expected, false)) { used_free = true; return true; } for (;;) { // Try to grab a shared token from the (non-blocking) jobserver pipe. char tok; ssize_t n = ::read(js_read_fd_, &tok, 1); if (n == 1) return true; if (n < 0 && errno == EINTR) continue; // Pipe closed/error: fall back to running without a token rather than // deadlocking the build. return true; if (n == 0) return true; // write end fully closed: avoid deadlock if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) return true; // unexpected error: avoid deadlock // No token available right now. Wait briefly for the pipe to become // readable, but cap the wait so a freed-up free token is noticed. struct pollfd pfd{ js_read_fd_, POLLIN, 0 }; ::poll(&pfd, 1, 50); } } Loading
executor.h +11 −0 Changes for executor.h: 11 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ #include <queue> #include <atomic> #include <memory> #include <fcntl.h> namespace makeplus { Loading @@ -28,6 +29,16 @@ public: js_read_fd_ = read_fd; js_write_fd_ = write_fd; js_active_ = (read_fd >= 0 && write_fd >= 0); if (js_active_) { // The whole recursive make tree is makeplus, so we control both ends // of the jobserver pipe. Make the read end non-blocking: a worker // waiting for a token must be able to wake up when this process's // per-process "free" token is released (an atomic, which cannot wake // a blocking read()), otherwise a thread that has committed to a // target could hang forever once the pipe is empty. int fl = ::fcntl(read_fd, F_GETFL); if (fl != -1) ::fcntl(read_fd, F_SETFL, fl | O_NONBLOCK); } } int build(const std::vector<std::string>& targets); Loading