From 8308950ca5611565b842800e285ad4c8378344f5 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Sun, 14 Mar 2004 05:35:19 +0000 Subject: [PATCH] minor cleanup --- winsup/cygwin/how-signals-work.txt | 75 ++++++++++++++++-------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/winsup/cygwin/how-signals-work.txt b/winsup/cygwin/how-signals-work.txt index cc0b26ff8..4d94c79dc 100644 --- a/winsup/cygwin/how-signals-work.txt +++ b/winsup/cygwin/how-signals-work.txt @@ -27,28 +27,29 @@ the perl script "gendef". This function notices exported cygwin functions which are labelled as SIGFE and generates a front end assembly file "sigfe.s" which contains the wrapper glue necessary for every function to call sigfe prior to actually dispatching to the real cygwin -function. This generated function contains low-level signal related +function. This generated file contains low-level signal related functions: _sigfe, _sigbe, sigdelayed, sigreturn, longjmp, and setjmp. The signal stack maintained by sigfe/sigbe and friends is a secondary shadow stack. Addresses from this stack are swapped into the "real" stack as needed to control program flow. The intent is that executing -cygwin functions will still see roughly the same stack layout and will -be able to retrieve arguments from the stack but will always return -to the _sigbe routine so that any signal handlers will be properly -called. +cygwin functions will still see the same stack layout as if they had +been called directly and will be able to retrieve arguments from the +stack but will always return to the _sigbe routine so that any signal +handlers will be properly called. Upon receipt of a "non-special" (see below) signal, the function sigpacket::process is called. This function determines what action, if -any, to take on the signal. Possible actions are: Ignore the signal (e.g., -SIGUSR1), terminate the program (SIGKILL, SIGTERM), stop the program -(SIGSTOP, SIGTSTP, etc.), wake up a sigwait or sigwaitinfo in a -targetted thread, or call a signal handler (possibly in a thread). -If no thread information has been sent to sigpacket::process, it determines -the correct thread to use based on various heuristics, as per UNIX. -Signals sent via the UNIX kill() function are normally sent to the -main thread. Ditto signals sent as the result of pressing tty keys, -like CTRL-C. +any, to take on the signal. Possible actions are: Ignore the signal +(e.g., SIGUSR1), terminate the program (SIGKILL, SIGTERM), stop the +program (SIGSTOP, SIGTSTP, etc.), wake up a sigwait or sigwaitinfo in a +targetted thread, or call a signal handler (possibly in a thread). If +no thread information has been sent to sigpacket::process, it determines +the correct thread to use based on various heuristics, as per UNIX. As +per linux, the only time a handler is called in a thread is when there +is some kind of fault like SIGSEGV, SIGILL, etc. Signals sent via the +UNIX kill() function are normally sent to the main thread. Ditto +signals sent as the result of pressing tty keys, like CTRL-C. Signals which stop a process are handled by a special internal handler: sig_handle_tty_stop. Some signals (e.g., SIGKILL, SIGSTOP) are @@ -73,26 +74,26 @@ parent via a false value. Otherwise processing continues. (For pending signals, the theory is that the signal handler thread will be forced to be rerun by having some strategic cygwin function call -sig_send with a __SIGFLUSH "argument" to it. This causes the signal -handler to rescan the signal array looking for pending signals.) +sig_send with a __SIGFLUSH argument. This causes the signal handler to +rescan the signal array looking for pending signals.) After determining that it's ok to send a signal, setup_handler will lock the cygtls stack to ensure that it has complete access. It will then -inspect the thread's 'incyg' element. If this is true, the thread is +inspect the thread's 'incyg' boolean. If this is true, the thread is currently executing a cygwin function. If it is false, the thread is unlocked and it is assumed that the thread is executing "user" code. The actions taken by setup_handler differ based on whether the program is executing a cygwin routine or not. If the program is executing a cygwin routine, then the -interrupt_on_return function is called which sets the address of the -'sigdelayed' function is pushed onto the thread's signal stack, and the -signal's mask and handler is saved in the tls structure. Then the -'signal_arrived' event is signalled, as well as any thread-specific wait -event. +interrupt_on_return function is called which causes the address of the +'sigdelayed' function to be pushed onto the thread's signal stack, and +the signal's mask and handler to be saved in the tls structure. After +performing these operations, the 'signal_arrived' event is signalled, as +well as any thread-specific wait event. Since the sigdelayed function was saved on the thread's signal stack, -when the cygwin functio returns, it will eventually return to the +when the cygwin function returns, it will eventually return to the sigdelayed "front end". The sigdelayed function will save a lot of state on the stack and set the signal mask as appropriate for POSIX. It uses information from the _cygtls structure which has been filled in @@ -124,13 +125,14 @@ SA_RESTART. UNIX allows some blocking functions to be interrupted by a signal handler and then return to blocking. In cygwin, so far, only -read/readv() operate in this fashion. To accommodate this behavior, -readv notices when a signal comes in and then calls the _cygtls function -'call_signal_handler_now'. 'call_signal_handler_now' emulates the -behavior of both sigdelayed and sigreturn. It sets the appropriate -masks and calls the handler, returning true to the caller if SA_RESTART -is active. If SA_RESTART is active, readv will loop. Otherwise -it will return -1 and set the errno to EINTR. +read/readv() and the wait* functions operate in this fashion. To +accommodate this behavior, a function notices when a signal comes in and +then calls the _cygtls function 'call_signal_handler_now'. +'call_signal_handler_now' emulates the behavior of both sigdelayed and +sigreturn. It sets the appropriate masks and calls the handler, +returning true to the caller if SA_RESTART is active. If SA_RESTART is +active, the function will loop. Otherwise it will typically return -1 +and set the errno to EINTR. Phew. So, now we turn to the case where cygwin needs to interrupt the program when it is not executing a cygwin function. In this scenario, @@ -142,12 +144,15 @@ suspend a process executing a win32 call can cause disastrous results, especially on Win9x. If the process is executing in an unsafe location then setup_handler -will return false as in the case above. Otherwise, the current location -of the thread is pushed on the thread's signal stack and the thread is -redirected to the sigdelayed function via the win32 "SetThreadContext" -call. Then the thread is restarted using the win32 "ResumeThread" call -and things proceed as per the sigdelayed discussion above. +will (quickly!) return false as in the case above. Otherwise, the +current location of the thread is pushed on the thread's signal stack +and the thread is redirected to the sigdelayed function via the win32 +"SetThreadContext" call. Then the thread is restarted using the win32 +"ResumeThread" call and things proceed as per the sigdelayed discussion +above. This leads us to the sig_send function. This is the "client side" part of the signal manipulation process. sig_send is the low-level function called by a high level process like kill() or pthread_kill(). + +** More to come **