[PATCH 1 of 2] win32: spawndetached returns pid of detached process and not of cmd.exe

Simon Heimberg Simohe at besonet.ch
Sat Feb 15 13:09:29 CST 2014


On 2014-02-12 12:46, Yuya Nishihara wrote:
> On Tue, 11 Feb 2014 23:50:29 +0100, Adrian Buehlmann wrote:
>> On 2014-02-11 23:06, Simon Heimberg wrote:
>>> --On 2014-02-11 22:09 +0900 Yuya Nishihara <yuya at tcha.org> wrote:
>>>> On Mon, 10 Feb 2014 20:08:01 +0100, Mads Kiilerich wrote:
>>>>> On 02/10/2014 06:02 PM, Simon Heimberg wrote:
>>>>>> I would recommend to the user to use the kill command that the system
>>>>>> provides. (`kill PID` on linux, `taskkill /pid PID` or the task
>>>>>> manager on windows, ...)
>>>>>
>>>>> Sure - if taskkill works and is reliable now. I guess few users are
>>>>> aware of taskkill. It should probably be mentioned in hg help serve -
>>>>> together with kill for unix-ish systems.
>>>>>
>>>>> Still, it would also be nice to have a cross platform way to terminate
>>>>> the daemon we started. Something that not only sent the signal, but also
>>>>> waited for the process to actually terminate...
>>>>
>>>> IIRC, Windows has equivalent for `kill -KILL`, but not for `kill -SIGINT`.


kernel32.TerminateProcess and the command taskkill /F do a "hard" kill, 
I see. The process does not get a chance to do any cleanup.
So `hg serve --kill` with this functionality would really be nice.

>>>> `GenerateConsoleCtrlEvent(CTRL_C_EVENT)` only works if receiver processes
>>>> shares the same console.
>>>>
>>>> http://msdn.microsoft.com/en-us/library/windows/desktop/ms683155(v=vs.85).aspx

We can attach to a console of a process with AttachConsole(pid). Not 
sure if the process created by spawndetached always has a console, but 
at least here it does.

The code would look similar to this (according to 
http://stackoverflow.com/a/15281070):

CTRL_C_EVENT = 0
def _StopProcess(pid):
     _check(kernel32.FreeConsole()) # detach from my console
     # stderr/stdout to console do not work from here!

     _check(_kernel32.AttachConsole(pid)) # attach to console of pid
     # disable Ctrl-Chandler
     _check(kernel32.SetConsoleCtrlHandler(None, True))

     _check(_kernel32.GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0))

     _check(_kernel32.FreeConsole())
     kernel32.AttachConsole(-1) # reattach to my console
     # TODO: fix stderr/stdin when they were at the console

     #ToDo: wait for process to quit

     # enable Ctrl-C handler
     _check(kernel32.SetConsoleCtrlHandler(None, False))

If this is run in a separate process, this simplification seems to work:

CTRL_C_EVENT = 0
def _StopProcess(pid):
     _check(kernel32.FreeConsole()) # detach from my console
     # stderr/stdout to console do not work now!

     _check(_kernel32.AttachConsole(pid)) # attach to console of pid
     # Send Ctrl-C to process (and myself)
     _check(_kernel32.GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0))

When I try to catch the Ctrl-C exception on myself, I fail. The cases 
"except:" and "except BaseException:" are not executed, only "finally:". 
So maybe this is also true for the stopped process.

This only works as expected for processes started by spawndetached (like 
hg serve -d). When I start multiple serve processes from one console (hg 
serve&) and tell to stop one pid, all are stopped. (They belong to the 
same console.)
This could be changed by sending CTRL_BREAK to the process group of the 
PID (CTRL_C can not be sent to a group). But for this we must start the 
process with process group creation enabled. and CTRL_BREAK could have 
side-effects.


New thought. Would it help?
When creating a service, we set a signal handler in 
commands.httpservice, which calls _kernel32.ExitProcess on any event 
(Ctrl-C, Ctrl-Break, Ctrl-Close, ...). Does this do any cleanup? (The 
handler is win32.set_signal_handler [2].)

[2] http://selenic.com/repo/hg/file/7648e9aef6ee/mercurial/win32.py#l296


>>>>
>>>> It seems `taskkill` sends WM_CLOSE message if `/F` option isn't specified,
>>>> but hg has no message loop.
>>>
>>> I'm playing around with handling the return value of
>>> kernel32.TerminateProcess and with
>>> kernel32.WaitForSingleObject(processHandle, timeout). But it's not yet
>>> ready.

killdaemons.py waits now for the process to terminate, see acbd19b9fbe1.

>
> I guess `taskkill /F` will do TerminateProcess.
>
>> It's nice that you are working on this.
>>
>> Perhaps you will find some old remarks helpful:
>>
>>    http://markmail.org/message/gbyni4dlxpjxqrtw
>>
>> In particular the ones from Matt there.
>
> Thanks for the pointer.
>
> OT: I'm trying to terminate command server cleanly by using named pipe
> or window message.  It's a real pain on Windows.
>
> Regards,
>



More information about the Mercurial-devel mailing list