Re: [PATCH/RFC] console: avoid master-thread suspend request from non-master processes

Johannes Schindelin <[email protected]>
Newsgroups gmane.os.cygwin.patches
Message-ID <[email protected]>
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/[email protected]/)
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
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.