]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/how-signals-work.txt
* environ.cc (environ_init): Avoid a compiler warning.
[newlib-cygwin.git] / winsup / cygwin / how-signals-work.txt
1 Copyright 2001 Red Hat Inc., Christopher Faylor
2
3 How do signals work?
4
5 On process startup, cygwin starts a secondary thread that deals with signals.
6 This thread contains a loop which blocks waiting for one of three events:
7
8 1) sigcatch_main - a semaphore which, when incremented, indicates that a
9 signal may be available for the main thread. The caller waits for the
10 signal to be delivered before returning.
11
12 2) sigcatch_nonmain - a semaphore which , when incremented, indicates that
13 a signal is available for a non-main thread (currently this is not truly
14 implemented). The caller waits for the signal to be delivered before
15 returning.
16
17 3) sigcatch_nosync - a semaphore which, when incremented, indicates that
18 a signal may be available for the main thread. The caller does not wait
19 for the delivery of the signal before returning.
20
21 So, the signal handler blocks waiting for one of these three semaphores.
22
23 If one of these is activated, then the the signal handler inspects an
24 array of integers looking for a non-zero value. The array corresponds
25 to the normal UNIX signals + two extra locations for internal usage.
26 This array is located in the 'sigtodo' array in the procinfo class.
27
28 The signal thread uses the InterlockedDecrement function to atomically
29 inspect elements of the array. If one one of the elements of the array
30 is non-zero, then cygwin checks to see if the user has blocked the
31 signal by inspecting the process signal mask. If the signal is blocked,
32 then the current array element is reincremented and the next element is
33 checked.
34
35 If the signal is not blocked, then the function "sig_handle" is called
36 with the signal number as an argument. This is a fairly straightforward
37 function. It first checks to see if the signal is special in any way.
38
39 A special signal is something like SIGKILL or SIGSTOP. The user has no
40 control over how those signals affect a UNIX process. If a SIGKILL is
41 received then sig_handle calls exit_sig to exit the process. If SIGSTOP
42 is called then sig_handle calls the regular signal dispatch function
43 with a special function argument "sig_handle_tty_stop". The signal
44 dispatch function is described below.
45
46 An uncaught signal like SIGTERM or SIGHUP will cause the process to exit
47 with the standard UNIX exit values. Uncaught signals like SIGUSR1 are
48 ignored, as on UNIX.
49
50 If the signal has an associated signal handler, then the setup_handler
51 function is eventually called. It is passed the signal, the address of
52 the handler, and a standard UNIX sigaction structure. The meat of
53 signal processing is in setup_handler.
54
55 setup_handler has a "simple" task. It tries to stop the appropriate
56 thread and redirect its execution to the signal handler function.
57 Currently, the "appropriate thread" is only the main thread. Someday
58 we'll have to change this to allow cygwin to interrupt other user
59 threads.
60
61 To accomplish its task, setup_handler first inspects the static sigsave
62 structure. This structure contains information on any not-yet-handled
63 signals that may have been set up by a previous call to setup_handler
64 but not yet dispatched in the main thread. If the sigsave structure
65 seems to be "active", then a "pending" flag is set (see below) and the
66 function returns. Otherwise processing continues.
67
68 After determining that sigsave is available, setup_handler will take one
69 of two routes, depending on whether the main thread is executing in the
70 cygwin DLL or is currently in "user" code. We'll discuss the cygwin DLL
71 case first.
72
73 If sigsave seems to be available, then the frame information for the
74 main thread is inspected. This information is set by any cygwin
75 function that is known to block (such as _read()), usually by calling
76 'sigframe thisframe (mainthread)' in the cygwin function. This call
77 sets up information about the current stack frame of an executing cygwin
78 process. Any function which uses 'sigframe thisframe' should be signal
79 aware. It should detect when a signal has arrived and return
80 immediately. This method is also used throughout the DLL to ensure
81 accurate frame info for the executing function. So, you'll see it
82 sprinkled liberally throughout the DLL, usually at places where
83 empirical tests have indicated problems finding this address via the
84 brute force method stack walking method employed in setup_handler.
85
86 So, if mainframe is active, that means that we have good information
87 about the state of the main thread. Cygwin uses the stack frame info
88 from this structure to insert a call to the assembly language function
89 'sigdelayed' in place of the main thread's normal return address. So,
90 when a call to (e.g.) _read returns after detecting a signal, it does
91 not return to its caller. Rather, it returns to sigdelayed.
92
93 The sigdelayed function saves a lot of state on the stack and sets the
94 signal mask as appropriate for POSIX. It uses information from the
95 sigsave structure which has been filled in by interrupt_on_return, as
96 called by setup_handler. sigdelayed pushes a "call" to the function
97 "sigreturn" on the stack. This will be the return address seen by the
98 signal handler. After setting up the return value, modifying the signal
99 mask, and saving other information on the stack, sigreturn clears the
100 sigsave structure (so that setup_handler can use it) and jumps to the
101 signal handler function. And, so a UNIX signal handler function is
102 emulated.
103
104 The signal handler function operates as normal for UNIX but, upon
105 return, it does not go directly back to the return address of the
106 original cygwin function. Instead it returns to the previously
107 mentioned 'sigreturn' assembly language function.
108
109 sigreturn resets the process mask to its state prior to calling the
110 signal handler. It checks to see if any new signals have come in and
111 calls the handler for them now, ensuring that the order of signal
112 arrival is more or less maintained. It checks to see if a cygwin
113 routine has set a special "restore this errno on returning from a
114 signal" value and sets errno to this, if so. Finally, it restores all
115 of the register values that were in effect when sigdelayed was called.
116
117 Ok, you thought I had forgotten about the 'pending' stuff didn't you?
118 Well, if you can rewind up to the discussion of sig_handle, we'll return
119 to the situation where sigsave was currently active. In this case,
120 setup_handler will set a "pending" flag, will reincrement the appropriate
121 element of the above signal array, and will return 0 to indicate that
122 the interrupt did not occur. Otherwise setup_handler returns 1.
123
124 For pending signals, the theory is that the signal handler thread will
125 be forced to be rerun by having some strategic cygwin function call
126 sig_send with a __SIGFLUSH "argument" to it. This causes the signal
127 handler to rescan the signal array looking for pending signals.
128
129 This leads us to the sig_send function. This is the "client side" part
130 of the signal manipulation process. sig_send is the low-level function
131 called by a high level process like kill(). You would use sig_send
132 to send a __SIGFLUSH to the signal thread.
This page took 0.041033 seconds and 5 git commands to generate.