[PATCH/RFC] console: avoid master-thread suspend request from non-master processes
Johannes Schindelin
Johannes.Schindelin@gmx.de
Thu Aug 13 09:43:08 GMT 2026
Hi Chris,
On Thu, 13 Aug 2026, 飛飛飛 wrote:
> Hi,
> I have been investigating a reproducible hang in highly parallel builds on
> Windows 11, especially while building LibreOffice with multiple jobs.
> The hang appears to involve fhandler_console::close() calling:
>
> set_disable_master_thread (true, this);
>
>
> even from processes that do not have a local console master thread.
>
> set_disable_master_thread() updates the shared disable_master_thread state
> and then waits for:
>
> while (con.master_thread_suspended != x)
> Sleep (1);
>
> During testing I captured a case where one process published a suspend
> request (true) and started waiting for
>
> master_thread_suspended == true,
>
> but another process later published false into the same shared state before
> the first request had completed.
>
> The first process was then left waiting indefinitely.
> In the captured trace, both requesting processes had:
>
> master_thread_started = 0
>
> while the actual console owner/master-thread process was a different
> process.
Thanks for the trace; it exposes a real race:
`set_disable_master_thread()` publishes shared state, drops `input_mutex`,
then waits, allowing another process to overwrite the request.
> A minimal guard in
> fhandler_console::close() avoids this:
>
> if (master_thread_started)
> set_disable_master_thread (true, this);
>
> This prevents processes without a local master thread from entering the
> master-thread suspend request/wait path.
> The intent is not to change Windows process/thread scheduling. It only
> restricts Cygwin's shared console master-thread control to a process which
> actually has a local master thread.
> This also avoids non-master processes entering a wait loop whose completion
> condition may be invalidated by another process modifying the same shared
> state.
The proposed guard does not fix this bug. `master_thread_started` is
process-local and false in every non-owner, so it says nothing about the
owner's master thread. It would also leave the following `tty::restore`
changes running while that thread remains active, undoing the ordering
introduced by `733d5a953fa9`. Other callers could still overwrite the
shared state, too.
Could you capture, on unpatched HEAD, the stuck process' call site and
stack, `con.owner` and whether it is alive, plus both shared flags?
Cross-process request serialization is likely needed, and I believe that
Takashi's patch (now at v12, see
https://inbox.sourceware.org/cygwin-patches/20260807121459.3116-1-takashi.yano@nifty.ne.jp/)
is the right approach, even if v12 still has a known lock-order deadlock.
Ciao,
Johannes
> Test results:
>
> Windows 11
> AMD Ryzen 7 9800X3D
> Intel i7-13620
> parallel LibreOffice builds
>
> repeated high-parallelism testing
> full LibreOffice build completed successfully with the guard applied
> Without the guard, I was able to reproduce the hang and capture the request
> overwrite described above.
> With the guard restored, the full LibreOffice build completed successfully
> with exit code 0.
>
> One possible trade-off is that processes without a local master thread can
> no longer request suspension of the console master thread through this
> path. So this narrows some existing cross-process master-thread control
> behavior.
>
> So far I have not observed a functional regression from this restriction on
> the tested Windows 11 systems.
> My current understanding is that the important behavioral change is very
> small: processes without master_thread_started no longer enter the
> potentially unbounded set_disable_master_thread() wait path.
> I would appreciate feedback on whether this ownership restriction is
> consistent with the intended console master-thread design.
> Thanks.
>
>
>
>
> Trace Process Log
>
> Process A:
> started=0
> publish disable=1
> wait for suspended=1
>
> Process B:
> started=0
> publish disable=0
> completes immediately
>
> Process A:
> never completes
>
More information about the Cygwin-patches
mailing list