Subject: bug#19868: #19868 25.0.50; Compilation eats buffers

From: Eli Zaretskii <[email-masked]>
Date: Wed, 17 Aug 2016 18:15:39 +0300

> From: Noam Postavsky <[email-masked]>
> Date: Tue, 16 Aug 2016 17:17:20 -0400
> Cc: [email-masked], Richard Copley <[email-masked]>
> 
> >> going to _close(5)... // here Emacs hangs until I kill bug.exe
> >
> > Can you tell what descriptor 5 is open on?  Is it for input, for
> > output, for something else?
> 
> I found this enum which indicates that i=2 would be READ_FROM_SUBPROCESS.

OK.

> I printed all open_fd values from deactivate_process, just before the
> closing loop, I got
> 
> deactivate_process()open_fd[0] = -1, open_fd[1] = 4, open_fd[2] = 5,
> open_fd[3] = -1, open_fd[4] = -1, open_fd[5] = -1,
> 
> So, only WRITE_TO_SUBPROCESS and READ_FROM_SUBPROCESS are open. When
> compiling bug.c without -mwindows, all open_fd values are -1 at that
> spot.

The last sentence shows an important difference between the two
cases.  Can you spot the code which makes the 2 handles -1 in the case
of a console (not -mwindows) application?  That might give us a clue
about the reason for Emacs hanging in _close.

One possibility is that the reader thread is trying to read from the
descriptor which we are trying to close.  Maybe that prevents _close
from completing its job.  Then the question is how does this succeed
in the case of a console application?

compilation-start sends SIGINT to the subprocess, then waits for 1
sec, then calls delete-process.  On Windows, interrupting a process is
implemented in w32proc.c:sys_kill.  My guess is that with a console
application, sending the simulated Ctrl-C to cmdproxy kills both
cmdproxy and the application, while in the -mwindows case only
cmdproxy (and perhaps its child cmd.exe) is killed.  But the details
still evade me: how would the above explain the fact that the
descriptors are already -1 when deactivate_process is called, who
closes them, and by what trigger?

Another thing to try is to set w32-start-process-share-console to a
non-nil value.  I don't know if it will help or make things worse, I
think this option was never seriously used, and I don't know what GUI
applications do on Windows when their control handler function is
called.  MSDN says in
https://msdn.microsoft.com/en-us/library/windows/desktop/ms683155(v=vs.85).aspx:

  All console processes have a default handler function that calls the
  ExitProcess function.

which says nothing about non-console applications.  And I think
non-console applications are not attached to any console anyway, so
this option will probably do nothing useful.  Still, it could give us
some clues about what's going on.

Some more interesting (though very vague) documentation is here:

 https://msdn.microsoft.com/en-us/library/windows/desktop/ms686016(v=vs.85).aspx

> Another observation: if I close Emacs while it's running bug.exe,
> Emacs closes successfully, but leaves bug.exe running (even though I
> answer yes at the prompt to kill it).

That's just another manifestation of the fact that we cannot reliably
kill grandchildren processes on MS-Windows, especially when they are
not console applications.  We can only kill the immediate child
process, in this case cmdproxy (and probably its child cmd.exe as
well).

Thanks.

P.S. Don't hesitate to ask questions about how this stuff works, if
something is unclear.  There's a large comment around line 390 in
w32proc.c which provides an overview, so if you didn't already read
it, it could help.