commit: d466b9677a6d659afd25dd8c21cb98ac47347623 Author: Michał Górny <mgorny <AT> gentoo <DOT> org> AuthorDate: Sat Jan 10 10:18:17 2026 +0000 Commit: Michał Górny <mgorny <AT> gentoo <DOT> org> CommitDate: Sun Jan 11 02:27:51 2026 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=d466b967
Scheduler: implicit jobserver slot support Introduce the support for implicit jobserver slot when emerge is running under a jobserver client such as GNU make or stevie. Notably, we're using the distinction between MAKEFLAGS being set in the calling environment by the client (which takes precedence over make.conf) vs. it being set via make.conf. In the former case, we are assuming that we can always run one job without acquiring a token. This fixes the protocol compliance and ensures full build count when emerge is being run under a jobserver client. It also enables users to deliberately do that in order to preacquire a single token and ensure that emerge process is not blocked from starting any job by other jobserver clients, and that CPU consumption during dependency calculation is accounted for. Bug: https://bugs.gentoo.org/692576 Signed-off-by: Michał Górny <mgorny <AT> gentoo.org> Part-of: https://github.com/gentoo/portage/pull/1543 lib/_emerge/Scheduler.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/_emerge/Scheduler.py b/lib/_emerge/Scheduler.py index 9ad1713280..a6233229af 100644 --- a/lib/_emerge/Scheduler.py +++ b/lib/_emerge/Scheduler.py @@ -248,6 +248,7 @@ class Scheduler(PollScheduler): features = self.settings.features self._jobserver_fd = None + self._jobserver_has_implicit_token = False self._jobserver_tokens = {} self._fetch_log = os.path.join( @@ -1639,6 +1640,13 @@ class Scheduler(PollScheduler): out = portage.output.EOutput() out.ewarn(f"Unsupported jobserver type: {flag}") if jobserver_path is not None: + # If MAKEFLAGS were passed via environment, we're likely running + # under a jobserver client (make, stevie) and a token was acquired + # for us, so use an implicit slot. If they were set via make.conf, + # we are the top-level process and need to acquire tokens for all + # jobs. + if "MAKEFLAGS" in os.environ: + self._jobserver_has_implicit_token = True try: self._jobserver_fd = os.open( jobserver_path, os.O_RDWR | os.O_NONBLOCK @@ -2130,6 +2138,10 @@ class Scheduler(PollScheduler): """ if self._jobserver_fd is None: return b"" + if self._jobserver_has_implicit_token: + # If our implicit slot is free, use it. + self._jobserver_has_implicit_token = False + return b"" try: return os.read(self._jobserver_fd, 1) except BlockingIOError: @@ -2154,6 +2166,11 @@ class Scheduler(PollScheduler): """ token = self._jobserver_tokens.pop(task_id, None) if token is not None and self._jobserver_fd is not None: + if token == b"": + # This job was running in our implicit slot. + assert not self._jobserver_has_implicit_token + self._jobserver_has_implicit_token = True + return try: os.write(self._jobserver_fd, token) except OSError as exception:
