Beefy Boxes and Bandwidth Generously Provided by pair Networks DiBona
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

The implementation of SIGHUP in Win32 Perl

by klaten (Novice)
on Aug 30, 2013 at 20:11 UTC ( #1051670=perlmeditation: print w/ replies, xml ) Need Help??

Greetings, all! I am an amateur programmer, and a first-time poster on PerlMonks so please forgive any impertinence I might have, but it appears to me that the current implementation of SIGHUP in Win32 Perl (the following code is from win32.c):

BOOL WINAPI win32_ctrlhandler(DWORD dwCtrlType) { #ifdef MULTIPLICITY dTHXa(PERL_GET_SIG_CONTEXT); if (!my_perl) return FALSE; #endif switch(dwCtrlType) { case CTRL_CLOSE_EVENT: /* A signal that the system sends to all processes attached to a + console when the user closes the console (either by choosing the Close command from the console window's System menu, or by choosing the End Task com +mand from the Task List */ if (do_raise(aTHX_ 1)) /* SIGHUP */ sig_terminate(aTHX_ 1); return TRUE;

is one function call away from being very useful.

If the return TRUE; was preceded by a Sleep(950); then a $SIG{ HUP } handler in a user's program would have about 9 and one-half seconds to clean itself up before being forcibly terminated by the OS. (Windows 7 terminates such processes after approximately 10 seconds). My understanding is that the OS terminates these processes upon the return from the handler, so currently, there is no time for a SIGHUP handler to effectively do anything.

None of this affects Linux in any way, this is just a Win32 thing. The code above operates in a different thread from the Perl program, so the Sleep() would not affect the main program at all. What do you think?

Comment on The implementation of SIGHUP in Win32 Perl
Select or Download Code
Re: The implementation of SIGHUP in Win32 Perl
by BrowserUk (Pope) on Aug 30, 2013 at 20:25 UTC
    (Windows 7 terminates such processes after approximately 10 seconds). My understanding is that the OS terminates these processes upon the return from the handler,

    Can you offer some evidence for either of these assertions?


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      BrowserUk, yes, there are some conversations over on StackOverflow and some MSDN notes, but I'll have to look up the links and post them later, sorry.

      This is becoming very interesting. This MSDN topic describes what I believe is the current behavior of the console control handlers. In this article, regarding the event handler returning "True" as it does in win32.c it says, "no other handler functions are called and the system terminates the process." I could find no definitive documentation of the "10 second" process timeout I described. However, this discussion on StackOverflow leads me to believe it is real.

      This behavior has changed over the years. This article provides a good description of how things worked at one point. Notice that there is no mention of threads at all. It seems that a change to the behavior of control handlers occurred beginning with Windows Vista (with Windows 7 apparently adding the previously mentioned 10 second timeout).

Re: The implementation of SIGHUP in Win32 Perl
by moritz (Cardinal) on Aug 31, 2013 at 09:08 UTC

      Regarding what happens if the main thread terminated, I assume that the termination is due to the Perl program stopping. Then, the C function, exit(), in the runtime library (called by Perl when stopping) would use the Win32 ExitProcess() system call and would take down all the process threads including the signal handler thread.

      Regarding what happens if there's another SIGHUP, the SIGHUP is actually coming from the control handler code which is triggered by a Win32 CTRL_CLOSE_EVENT. Keep in mind that under later versions of Windows, a single CTRL_CLOSE_EVENT means a process is doomed! Soon, or very soon, it's going down! So even if a second SIGHUP came in and caused a segfault in Perl the only thing that would be lost is a cleanup opportunity that we aren't even taking advantage of right now.

      Now, about that second or subsequent SIGHUP. Let's say it does get triggered and the sig_terminate(aTHX_ 1); from win32.c activates the $SIG{ 'HUP' } in the Perl program. I imagine it would have the same effect as any other repeated signal in Perl, that is the effect would depend on the $SIG handler, maybe it segfaults, maybe its ignored, maybe . . ., but it would be the same as in Linux or elsewhere.

Re: The implementation of SIGHUP in Win32 Perl
by BrowserUk (Pope) on Sep 01, 2013 at 09:32 UTC

    In theory, the process is only terminated if do_raise() returns true; that only happens if there is no signal handler set for sighup.

    If there is a signal handler set, it gets called by do_raise(), whence it has as long as it decides to take, and sig_terminate() is never called. There is no sense in adding a Sleep 950; (which is a little under a second not 9.5 seconds) anywhere.

    In reality, I can't get a sighup signal handler to ever be invoked even on 5.18. I run vista, and I never see a dialog prompting me; nor is there any delay 10s or otherwise between killing the process and it disappearing; regardless of whether I've installed a signal handler for HUP.

    I'm not really sure I understand your motivation for meditating on this; but I think you need to do a lot more reading and experimenting.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      You wrote, "I think you need to do a lot more reading and experimenting," and while that is certainly true (and will still be true the day I die) I hope you and others will consider what I write based upon its merit and utility rather than dismiss it due to my lack of standing within the Perl community.

      You also wrote, "I'm not really sure I understand your motivation for meditating on this." Here in Chicago where I live, the authorities run anti-terrorism public service announcements which say "If you see something, say something," about the need for everyone to contribute to the public safety by reporting their suspicions. I noticed what I believe to be serious problems with the SIGHUP implementation in Win32 Perl. I have some suggestions for how to resolve those problems but I lack the talent, experience, and reputation to resolve those issues myself. I've not seen another discussion covering this issue in the same way. I love Perl even though I don't make a dime from it. I'd feel irresponsible if I did not say anything about this. I have to "say something."

      Although I am a new member of PerlMonks, I've lurked here since Dave Roth was a Perl/Win32 "rock star." I know of your reputation as a current "rock star," and am thrilled by your attention. I believe if I can convince you of what I see as a problem, you have the "pull" to help get it resolved. So now you know my motivation.

        I hope you and others will consider what I write based upon its merit and utility rather than dismiss it due to my lack of standing within the Perl community.

        Hm. I spent 1 day waiting for you to reply to my first questions; and 2 days on and off experimenting with code and reading documentation before replying with my best explanation of my findings.

        If I ignore you in future; it won't be because of your lack of standing in the Perl community. (For all I know you could be Larry himself).

        But the attitude....

        I noticed what I believe to be serious problems with the SIGHUP implementation in Win32 Perl.

        My finding are that there is no implementation of SIGHUP on windows. What is there doesn't appear to do anything useful; and it is hard to see what use it would be put to if it did do something useful.

        Injecting a 9.5 second sleep into a signal handling routine is about as absurd an approach to 'fixing' it as I could imagine.

        But hey. What do I know. Good luck with that.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

      I've had some time to think some more about this issue. Here is additional information.

      IMHO, the key problem with the current implementation is that it seems to assume the console control handler code is being called as a callback (which is what I believe happens in Windows XP), when actually the console control handler code (in Windows Vista and later) is being called from another thread being started by Windows (see note 1, below). This control handler code then triggers Perl's signal handling code, from the other thread. The signal handling code in the Perl program will be running at the same time the Perl program is. I'd be very surprised if Perl were designed to do that!

      In my mind an equivalent scenario would be if I had a Perl program which ran an XSUB that (in C code) started a thread which then tried to call back into the Perl interpreter. Yes, because all the data structures are in the same process, my new thread could access and change things, sure, but due to synchronization and other thread safety issues I'd bet that my new thread would reek havoc upon the Perl interpreter and return results from my thread might be affected by the program still running in the Perl interpreter.

      The other problem is that since Windows Vista, the OS (not Perl) will terminate the process upon the return from the console control handler—regardless of the return value (see note 2, below, and from what I've read elsewhere, this process will eventually be terminated by the OS even if the control handler never returns, see note 3, below). This could abort any type of recovery a Perl signal handler might attempt.

      Here's what I propose as a possible solution. There is code in win32.c to convert a WM_USER_KILL message into a C runtime signal. Instead of having the console control handler code call back into Perl, have it post (or maybe in the case of SIGHUP, send -- so the thread could wait for a response) a message to the main thread of the console (possibly get the the console window handle via a GetWindowConsole-type function?). This would allow the existing code in win32c to recreate a SIGHUP (and also SIGINT and SIGBREAK, because they too would be affected by the threading issue) signal in the main thread, the thread running the Perl interpreter. Although slightly less efficient on Windows XP, this technique should operate on any Windows OS. Another advantage of this technique is that it would allow the use of a message spy type utility to determine whether or not the signal-simulation messages were actually reaching the console window.

      Regarding the process termination issue, I'm less certain. Originally I suggested a rather simplistic "sleep" type solution prior to returning from the console control handler, but I have to admit, that idea stinks. I read here that the timeout on Windows 7 is 10 seconds, but what about Windows Vista? Windows 8? Windows 9, 10, 11? I don't know. Maybe the answer is: just go ahead and let the OS kill the process at that point. I do believe that somehow, the console control handler should be kept from returning until the Perl $SIG handler has a chance to run. How could that happen? Could the idea about the SendMessage for the SIGHUP work? You know better than I on that.

      Anyway, here are my reference notes on this topic:

      1. From msdn: "When the signal is received, the system creates a new thread in the process to execute the function."
      2. From msdn: "The CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals give the process an opportunity to clean up before termination. A HandlerRoutine can perform any necessary cleanup, then take one of the following actions:
        • Call the ExitProcess function to terminate the process
        • Return FALSE. If none of the registered handler functions returns TRUE, the default handler terminates the process.
        • Return TRUE. In this case, no other handler functions are called and the system terminates the process."
      3. From the StackOverflow web site: "It looks like you can no longer ignore close requests on Windows 7. You do get the CTRL_CLOSE_EVENT event though, and from that moment on, you get 10 seconds to do whatever you need to do before it auto-closes."
      4. An interesting side note from msdn regarding the CTRL_LOGOFF_EVENT (a similar note appears in the description of the CTRL_SHUTDOWN_EVENT as well): "Note that this signal is received only by services. Interactive applications are terminated at logoff, so they are not present when the system sends this signal."
        The other problem is that since Windows Vista, the OS (not Perl) will terminate the process upon the return from the console control handleróregardless of the return value (see note 2, below, and from what I've read elsewhere, this process will eventually be terminated by the OS even if the control handler never returns, see note 3, below). This could abort any type of recovery a Perl signal handler might attempt.

        I think you've answered your own inquiry. There is nothing the perl process can do about being forcibly terminated.

        And I sincerely doubt there is any merit in trying.

        Windows doesn't do sighup; nor have I felt any need for it. As a Windows user, I know that forcing a program to terminate this way is likely to leave things in an incomplete state; and I use the option as a last resort with that in mind.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        IMHO, the key problem with the current implementation is that it seems to assume the console control handler code is being called as a callback (which is what I believe happens in Windows XP), when actually the console control handler code (in Windows Vista and later) is being called from another thread being started by Windows (see note 1, below). This control handler code then triggers Perl's signal handling code, from the other thread. The signal handling code in the Perl program will be running at the same time the Perl program is. I'd be very surprised if Perl were designed to do that!


        It is always executed in a separate thread in every NT OS, not just Vista. DOS Win I can't speak about, but it might have actually interrupted the main thread since in old MSDN docs for the CRT, on DOS Win ONLT, there a quite a number of more CRT signals that are catchable than on MS CRT on NT. The multi-threading of the console event dispatch often can cause assert fails and crashes from Perl if Perl is in a 100% CPU usage loop on a multi core machine. I've filed tickets about it in Perl RT. Signals block all other execution I think on Unix. The console event thing runs in a separate thread without stopping the first thread. The runloop in the main thread will get a NULL and exit quickly if the console event thread hasn't gotten to the exit() yet in most cases, or the main thread is in blocking IO and its not a problem for the child thread to reenter the same interp and do perl global destruction.

        My idea for the fix would be to do a SetThreadContext (C debugger-ish stuff) see http://msdn.microsoft.com/en-us/library/windows/desktop/ms680632%28v=vs.85%29.aspx, and try to implement it unix style with the event interrupting execution and executing in the context of the parent thread. NT does have its own implementation of Unix signals called asynchronous procedure calls (APCs) see http://msdn.microsoft.com/en-us/library/windows/desktop/ms681951%28v=vs.85%29.aspx, but if you read about them, they only run when you, the process, requests to rundown the APC queue, so they are always predictable unlike Unix signals (an intentional design), but most syscalls typical Win32 processes are never the "alertable" kind, and if you have a single DLL that you didn't write yourself in the process, you are probably screwed cuz that DLL will be making non-alertable syscalls. If someone really wanted to (space elevator fantasy here), they could DLL hook kernel32, or SSDT hook it, and add APC dispatching to syscalls that dont run APCs. The syscalls would have to be retried by the layer/shim when they fail because APCs ran. The kernel32 and ntdll alertable syscalls dont do that for you.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://1051670]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (15)
As of 2014-04-16 17:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (433 votes), past polls