]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* sigproc.cc: inter/intra signal and sub process handler |
2 | ||
33ad2bf9 | 3 | Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
1fd5e000 CF |
4 | |
5 | Written by Christopher Faylor <cgf@cygnus.com> | |
6 | ||
7 | This file is part of Cygwin. | |
8 | ||
9 | This software is a copyrighted work licensed under the terms of the | |
10 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
11 | details. */ | |
12 | ||
4c8d72de | 13 | #include "winsup.h" |
1fd5e000 CF |
14 | #include <stdlib.h> |
15 | #include <time.h> | |
16 | #include <sys/wait.h> | |
1fd5e000 | 17 | #include <stdlib.h> |
f0338f54 | 18 | #include <sys/cygwin.h> |
3cb62bd6 | 19 | #include <assert.h> |
c0a9bffd | 20 | #include <sys/signal.h> |
9e2baf8d | 21 | #include "cygerrno.h" |
bccd5e0d CF |
22 | #include "sync.h" |
23 | #include "sigproc.h" | |
24 | #include "pinfo.h" | |
6b91b8d5 | 25 | #include "security.h" |
0381fec6 | 26 | #include "fhandler.h" |
47063f00 | 27 | #include "path.h" |
0381fec6 | 28 | #include "dtable.h" |
8dec7b03 | 29 | #include "cygheap.h" |
77f4a250 | 30 | #include "child_info_magic.h" |
9661a0c8 | 31 | #define NEED_VFORK |
bccd5e0d | 32 | #include "perthread.h" |
29ac7f89 | 33 | #include "shared_info.h" |
b6bd7037 | 34 | #include "cygthread.h" |
1fd5e000 CF |
35 | |
36 | /* | |
37 | * Convenience defines | |
38 | */ | |
39 | #define WSSC 60000 // Wait for signal completion | |
40 | #define WPSP 40000 // Wait for proc_subproc mutex | |
41 | #define WSPX 20000 // Wait for wait_sig to terminate | |
42 | #define WWSP 20000 // Wait for wait_subproc to terminate | |
43 | ||
1fd5e000 CF |
44 | #define TOTSIGS (NSIG + __SIGOFFSET) |
45 | ||
1fd5e000 CF |
46 | #define wake_wait_subproc() SetEvent (events[0]) |
47 | ||
48 | #define no_signals_available() (!hwait_sig || !sig_loop_wait) | |
49 | ||
6409b03b | 50 | #define NZOMBIES 256 |
161edfaa | 51 | |
c0a9bffd CF |
52 | static LONG local_sigtodo[TOTSIGS]; |
53 | struct sigaction *global_sigs; | |
54 | ||
55 | inline LONG * | |
56 | getlocal_sigtodo (int sig) | |
06bb4899 CF |
57 | { |
58 | return local_sigtodo + __SIGOFFSET + sig; | |
59 | } | |
60 | ||
c0a9bffd CF |
61 | void __stdcall |
62 | sigalloc () | |
63 | { | |
64 | cygheap->sigs = global_sigs = | |
65 | (struct sigaction *) ccalloc (HEAP_SIGS, NSIG, sizeof (struct sigaction)); | |
66 | } | |
67 | ||
68 | void __stdcall | |
69 | signal_fixup_after_exec () | |
70 | { | |
71 | global_sigs = cygheap->sigs; | |
72 | /* Set up child's signal handlers */ | |
73 | for (int i = 0; i < NSIG; i++) | |
74 | { | |
75 | myself->getsig (i).sa_mask = 0; | |
76 | if (myself->getsig (i).sa_handler != SIG_IGN) | |
77 | myself->getsig (i).sa_handler = SIG_DFL; | |
78 | } | |
79 | } | |
80 | ||
1fd5e000 CF |
81 | /* |
82 | * Global variables | |
83 | */ | |
84 | const char *__sp_fn ; | |
85 | int __sp_ln; | |
86 | ||
87 | char NO_COPY myself_nowait_dummy[1] = {'0'};// Flag to sig_send that signal goes to | |
88 | // current process but no wait is required | |
89 | char NO_COPY myself_nowait_nonmain_dummy[1] = {'1'};// Flag to sig_send that signal goes to | |
90 | // current process but no wait is required | |
91 | // if this is not the main thread. | |
92 | ||
93 | HANDLE NO_COPY signal_arrived; // Event signaled when a signal has | |
94 | // resulted in a user-specified | |
95 | // function call | |
96 | /* | |
97 | * Common variables | |
98 | */ | |
99 | ||
100 | ||
101 | /* How long to wait for message/signals. Normally this is infinite. | |
102 | * On termination, however, these are set to zero as a flag to exit. | |
103 | */ | |
104 | ||
105 | #define Static static NO_COPY | |
106 | ||
5ac73dfe CF |
107 | Static DWORD proc_loop_wait = 1000; // Wait for subprocesses to exit |
108 | Static DWORD sig_loop_wait = INFINITE; // Wait for signals to arrive | |
1fd5e000 | 109 | |
0428827b | 110 | Static HANDLE sigcatch_nonmain; // The semaphore signaled when |
1fd5e000 CF |
111 | // signals are available for |
112 | // processing from non-main thread | |
0428827b | 113 | Static HANDLE sigcatch_main; // Signalled when main thread sends a |
1fd5e000 | 114 | // signal |
0428827b | 115 | Static HANDLE sigcatch_nosync; // Signal wait_sig to scan sigtodo |
1fd5e000 CF |
116 | // but not to bother with any |
117 | // synchronization | |
0428827b | 118 | Static HANDLE sigcomplete_main; // Event signaled when a signal has |
1fd5e000 CF |
119 | // finished processing for the main |
120 | // thread | |
0428827b | 121 | Static HANDLE sigcomplete_nonmain; // Semaphore raised for non-main |
1fd5e000 CF |
122 | // threads when a signal has finished |
123 | // processing | |
0428827b | 124 | HANDLE NO_COPY sigCONT; // Used to "STOP" a process |
b6bd7037 CF |
125 | Static cygthread *hwait_sig; // Handle of wait_sig thread |
126 | Static cygthread *hwait_subproc; // Handle of sig_subproc thread | |
1fd5e000 | 127 | |
0428827b | 128 | Static HANDLE wait_sig_inited; // Control synchronization of |
1fd5e000 | 129 | // message queue startup |
1fd5e000 CF |
130 | |
131 | /* Used by WaitForMultipleObjects. These are handles to child processes. | |
132 | */ | |
0428827b | 133 | Static HANDLE events[PSIZE + 1]; // All my children's handles++ |
1fd5e000 | 134 | #define hchildren (events + 1) // Where the children handles begin |
cecb74ae | 135 | Static char cpchildren[PSIZE * sizeof (pinfo)]; // All my children info |
0428827b | 136 | Static int nchildren; // Number of active children |
3bacc423 | 137 | Static char czombies[(NZOMBIES + 1) * sizeof (pinfo)]; // All my deceased children info |
0428827b | 138 | Static int nzombies; // Number of deceased children |
1fd5e000 | 139 | |
cecb74ae CF |
140 | #define pchildren ((pinfo *) cpchildren) |
141 | #define zombies ((pinfo *) czombies) | |
142 | ||
5ac73dfe | 143 | Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads |
1fd5e000 CF |
144 | Static waitq waitq_main; // Storage for main thread |
145 | ||
5ac73dfe | 146 | muto NO_COPY *sync_proc_subproc = NULL; // Control access to subproc stuff |
f02f1f14 | 147 | |
5ac73dfe | 148 | DWORD NO_COPY sigtid = 0; // ID of the signal thread |
1fd5e000 | 149 | |
75119e99 | 150 | bool NO_COPY pending_signals = false; // true if signals pending |
1fd5e000 CF |
151 | |
152 | /* Functions | |
153 | */ | |
99a8fab5 | 154 | static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1))); |
9cec3d45 | 155 | static __inline__ BOOL get_proc_lock (DWORD, DWORD); |
99a8fab5 | 156 | static HANDLE __stdcall getevent (_pinfo *, const char *) __attribute__ ((regparm (2))); |
1fd5e000 CF |
157 | static void __stdcall remove_zombie (int); |
158 | static DWORD WINAPI wait_sig (VOID *arg); | |
84c7d409 | 159 | static int __stdcall stopped_or_terminated (waitq *, _pinfo *); |
1fd5e000 CF |
160 | static DWORD WINAPI wait_subproc (VOID *); |
161 | ||
162 | /* Determine if the parent process is alive. | |
163 | */ | |
164 | ||
165 | BOOL __stdcall | |
166 | my_parent_is_alive () | |
167 | { | |
168 | DWORD res; | |
84aeff41 | 169 | if (!myself->ppid_handle) |
1fd5e000 | 170 | { |
84aeff41 | 171 | debug_printf ("No myself->ppid_handle"); |
1fd5e000 CF |
172 | res = FALSE; |
173 | } | |
174 | else | |
175 | for (int i = 0; i < 2; i++) | |
84aeff41 | 176 | switch (res = WaitForSingleObject (myself->ppid_handle, 0)) |
1fd5e000 CF |
177 | { |
178 | case WAIT_OBJECT_0: | |
179 | debug_printf ("parent dead."); | |
180 | res = FALSE; | |
181 | goto out; | |
182 | case WAIT_TIMEOUT: | |
183 | debug_printf ("parent still alive"); | |
184 | res = TRUE; | |
185 | goto out; | |
186 | case WAIT_FAILED: | |
187 | DWORD werr = GetLastError (); | |
188 | if (werr == ERROR_INVALID_HANDLE && i == 0) | |
189 | continue; | |
84aeff41 CF |
190 | system_printf ("WFSO for myself->ppid_handle(%p) failed, error %d", |
191 | myself->ppid_handle, werr); | |
1fd5e000 CF |
192 | res = FALSE; |
193 | goto out; | |
194 | } | |
195 | out: | |
196 | return res; | |
197 | } | |
198 | ||
3cb62bd6 CF |
199 | void __stdcall |
200 | wait_for_sigthread () | |
1fd5e000 | 201 | { |
5cd82412 CF |
202 | sigproc_printf ("wait_sig_inited %p", wait_sig_inited); |
203 | HANDLE hsig_inited = wait_sig_inited; | |
204 | assert (hsig_inited); | |
205 | (void) WaitForSingleObject (hsig_inited, INFINITE); | |
3cb62bd6 | 206 | wait_sig_inited = NULL; |
5cd82412 | 207 | (void) ForceCloseHandle1 (hsig_inited, wait_sig_inited); |
1fd5e000 CF |
208 | } |
209 | ||
243a041b CF |
210 | /* Get the sync_proc_subproc muto to control access to |
211 | * children, zombie arrays. | |
212 | * Attempt to handle case where process is exiting as we try to grab | |
213 | * the mutex. | |
214 | */ | |
215 | static BOOL | |
216 | get_proc_lock (DWORD what, DWORD val) | |
217 | { | |
218 | Static int lastwhat = -1; | |
219 | if (!sync_proc_subproc) | |
220 | return FALSE; | |
221 | if (sync_proc_subproc->acquire (WPSP)) | |
222 | { | |
223 | lastwhat = what; | |
224 | return TRUE; | |
225 | } | |
226 | if (!sync_proc_subproc) | |
227 | return FALSE; | |
228 | system_printf ("Couldn't aquire sync_proc_subproc for(%d,%d), %E, last %d", | |
229 | what, val, lastwhat); | |
230 | return TRUE; | |
231 | } | |
232 | ||
1fd5e000 | 233 | static BOOL __stdcall |
84c7d409 | 234 | proc_can_be_signalled (_pinfo *p) |
1fd5e000 CF |
235 | { |
236 | if (p == myself_nowait || p == myself_nowait_nonmain || p == myself) | |
237 | { | |
3cb62bd6 | 238 | assert (!wait_sig_inited); |
1fd5e000 CF |
239 | return 1; |
240 | } | |
241 | ||
242 | return ISSTATE (p, PID_INITIALIZING) || | |
243 | (((p)->process_state & (PID_ACTIVE | PID_IN_USE)) == | |
244 | (PID_ACTIVE | PID_IN_USE)); | |
245 | } | |
246 | ||
84c7d409 | 247 | BOOL __stdcall |
488c7683 | 248 | pid_exists (pid_t pid) |
84c7d409 CF |
249 | { |
250 | pinfo p (pid); | |
251 | return proc_exists (p); | |
252 | } | |
253 | ||
1dc16fc7 | 254 | /* Test to determine if a process really exists and is processing signals. |
1fd5e000 CF |
255 | */ |
256 | BOOL __stdcall | |
84c7d409 | 257 | proc_exists (_pinfo *p) |
1fd5e000 | 258 | { |
994fe87b | 259 | return p && !(p->process_state & PID_EXITED); |
1fd5e000 CF |
260 | } |
261 | ||
0ef78625 CF |
262 | /* Return 1 if this is one of our children, zero otherwise. |
263 | FIXME: This really should be integrated with the rest of the proc_subproc | |
264 | testing. Scanning these lists twice is inefficient. */ | |
265 | int __stdcall | |
266 | mychild (int pid) | |
267 | { | |
268 | for (int i = 0; i < nchildren; i++) | |
269 | if (pchildren[i]->pid == pid) | |
270 | return 1; | |
271 | for (int i = 0; i < nzombies; i++) | |
272 | if (zombies[i]->pid == pid) | |
273 | return 1; | |
274 | return 0; | |
275 | } | |
276 | ||
1fd5e000 CF |
277 | /* Handle all subprocess requests |
278 | */ | |
84c7d409 | 279 | #define vchild (*((pinfo *) val)) |
1fd5e000 CF |
280 | int __stdcall |
281 | proc_subproc (DWORD what, DWORD val) | |
282 | { | |
283 | int rc = 1; | |
284 | int potential_match; | |
84c7d409 | 285 | _pinfo *child; |
9aa07a8f | 286 | int clearing; |
1fd5e000 CF |
287 | waitq *w; |
288 | ||
289 | #define wval ((waitq *) val) | |
290 | ||
a5a965ff | 291 | sigproc_printf ("args: %x, %d", what, val); |
1fd5e000 CF |
292 | |
293 | if (!get_proc_lock (what, val)) // Serialize access to this function | |
294 | { | |
dd11f11f | 295 | system_printf ("couldn't get proc lock. Something is wrong."); |
1fd5e000 CF |
296 | goto out1; |
297 | } | |
298 | ||
299 | switch (what) | |
300 | { | |
301 | /* Add a new subprocess to the children arrays. | |
302 | * (usually called from the main thread) | |
303 | */ | |
304 | case PROC_ADDCHILD: | |
305 | if (nchildren >= PSIZE - 1) | |
cde0c2fb CF |
306 | { |
307 | rc = 0; | |
308 | break; | |
309 | } | |
1fd5e000 CF |
310 | pchildren[nchildren] = vchild; |
311 | hchildren[nchildren] = vchild->hProcess; | |
164a681c | 312 | if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle, |
1dc16fc7 | 313 | 0, 0, DUPLICATE_SAME_ACCESS)) |
164a681c CF |
314 | system_printf ("Couldn't duplicate child handle for pid %d, %E", vchild->pid); |
315 | ProtectHandle1 (vchild->pid_handle, pid_handle); | |
dd11f11f CF |
316 | |
317 | if (!DuplicateHandle (hMainProc, hMainProc, vchild->hProcess, &vchild->ppid_handle, | |
318 | 0, TRUE, DUPLICATE_SAME_ACCESS)) | |
319 | system_printf ("Couldn't duplicate my handle<%p> for pid %d, %E", hMainProc, vchild->pid); | |
320 | vchild->ppid = myself->pid; | |
c0188ae7 | 321 | vchild->uid = myself->uid; |
dd11f11f CF |
322 | vchild->gid = myself->gid; |
323 | vchild->pgid = myself->pgid; | |
324 | vchild->sid = myself->sid; | |
325 | vchild->ctty = myself->ctty; | |
dd11f11f CF |
326 | vchild->process_state |= PID_INITIALIZING | (myself->process_state & PID_USETTY); |
327 | ||
a5a965ff | 328 | sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p", |
1fd5e000 CF |
329 | vchild->pid, nchildren, vchild->dwProcessId, |
330 | vchild->hProcess); | |
1ec4f618 | 331 | nchildren++; |
1fd5e000 | 332 | |
1fd5e000 CF |
333 | wake_wait_subproc (); |
334 | break; | |
335 | ||
1fd5e000 | 336 | /* A child process had terminated. |
7edb836a CF |
337 | Possibly this is just due to an exec(). Cygwin implements an exec() |
338 | as a "handoff" from one windows process to another. If child->hProcess | |
339 | is different from what is recorded in hchildren, then this is an exec(). | |
340 | Otherwise this is a normal child termination event. | |
341 | (called from wait_subproc thread) */ | |
1fd5e000 | 342 | case PROC_CHILDTERMINATED: |
0ef78625 | 343 | if (hchildren[val] != pchildren[val]->hProcess) |
1fd5e000 | 344 | { |
a5a965ff | 345 | sigproc_printf ("pid %d[%d], reparented old hProcess %p, new %p", |
083abe54 CF |
346 | pchildren[val]->pid, val, hchildren[val], pchildren[val]->hProcess); |
347 | HANDLE h = hchildren[val]; | |
84c7d409 | 348 | hchildren[val] = pchildren[val]->hProcess; /* Filled out by child */ |
083abe54 CF |
349 | sync_proc_subproc->release (); // Release the lock ASAP |
350 | ForceCloseHandle1 (h, childhProc); | |
84c7d409 | 351 | ProtectHandle1 (pchildren[val]->hProcess, childhProc); |
3f7bd531 | 352 | rc = 0; |
083abe54 | 353 | goto out; // This was an exec() |
1fd5e000 CF |
354 | } |
355 | ||
a5a965ff | 356 | sigproc_printf ("pid %d[%d] terminated, handle %p, nchildren %d, nzombies %d", |
84c7d409 | 357 | pchildren[val]->pid, val, hchildren[val], nchildren, nzombies); |
3ecfcf57 CF |
358 | |
359 | int thiszombie; | |
360 | thiszombie = nzombies; | |
361 | zombies[nzombies] = pchildren[val]; // Add to zombie array | |
362 | zombies[nzombies++]->process_state = PID_ZOMBIE;// Walking dead | |
363 | ||
12520587 | 364 | sigproc_printf ("zombifying [%d], pid %d, handle %p, nchildren %d", |
e46db834 CF |
365 | val, pchildren[val]->pid, hchildren[val], nchildren); |
366 | if ((int) val < --nchildren) | |
367 | { | |
368 | hchildren[val] = hchildren[nchildren]; | |
369 | pchildren[val] = pchildren[nchildren]; | |
370 | } | |
3ecfcf57 CF |
371 | |
372 | /* See if we should care about the this terminated process. If we've | |
373 | filled up our table or if we're ignoring SIGCHLD, then we immediately | |
374 | remove the process and move on. Otherwise, this process becomes a zombie | |
375 | which must be reaped by a wait() call. */ | |
e2ea684e | 376 | if (nzombies >= NZOMBIES |
3ecfcf57 CF |
377 | || myself->getsig (SIGCHLD).sa_handler == (void *) SIG_IGN) |
378 | { | |
379 | sigproc_printf ("automatically removing zombie %d", thiszombie); | |
380 | remove_zombie (thiszombie); | |
381 | } | |
382 | ||
84aeff41 CF |
383 | /* Don't scan the wait queue yet. Caller will send SIGCHLD to this process. |
384 | This will cause an eventual scan of waiters. */ | |
9aa07a8f | 385 | break; |
f02f1f14 | 386 | |
164a681c CF |
387 | /* Handle a wait4() operation. Allocates an event for the calling |
388 | * thread which is signaled when the appropriate pid exits or stops. | |
389 | * (usually called from the main thread) | |
390 | */ | |
391 | case PROC_WAIT: | |
392 | wval->ev = NULL; // Don't know event flag yet | |
393 | ||
394 | if (wval->pid <= 0) | |
395 | child = NULL; // Not looking for a specific pid | |
396 | else if (!mychild (wval->pid)) | |
397 | goto out; // invalid pid. flag no such child | |
398 | ||
399 | wval->status = 0; // Don't know status yet | |
400 | sigproc_printf ("wval->pid %d, wval->options %d", wval->pid, wval->options); | |
401 | ||
402 | /* If the first time for this thread, create a new event, otherwise | |
403 | * reset the event. | |
404 | */ | |
405 | if ((wval->ev = wval->thread_ev) == NULL) | |
406 | { | |
407 | wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE, | |
408 | FALSE, NULL); | |
409 | ProtectHandle (wval->ev); | |
410 | } | |
411 | ||
412 | ResetEvent (wval->ev); | |
413 | w = waitq_head.next; | |
414 | waitq_head.next = wval; /* Add at the beginning. */ | |
415 | wval->next = w; /* Link in rest of the list. */ | |
416 | clearing = 0; | |
417 | goto scan_wait; | |
418 | ||
f02f1f14 CF |
419 | /* Clear all waiting threads. Called from exceptions.cc prior to |
420 | * the main thread's dispatch to a signal handler function. | |
421 | * (called from wait_sig thread) | |
422 | */ | |
423 | case PROC_CLEARWAIT: | |
424 | /* Clear all "wait"ing threads. */ | |
d3bda1df | 425 | if (val) |
a5a965ff | 426 | sigproc_printf ("clear waiting threads"); |
d3bda1df | 427 | else |
a5a965ff | 428 | sigproc_printf ("looking for processes to reap"); |
9aa07a8f | 429 | clearing = val; |
f02f1f14 | 430 | |
1fd5e000 CF |
431 | scan_wait: |
432 | /* Scan the linked list of wait()ing threads. If a wait's parameters | |
433 | * match this pid, then activate it. | |
434 | */ | |
435 | for (w = &waitq_head; w->next != NULL; w = w->next) | |
436 | { | |
437 | if ((potential_match = checkstate (w)) > 0) | |
a5a965ff | 438 | sigproc_printf ("released waiting thread"); |
164a681c | 439 | else if (!clearing && !(w->next->options & WNOHANG) && potential_match < 0) |
a5a965ff | 440 | sigproc_printf ("only found non-terminated children"); |
f02f1f14 | 441 | else if (potential_match <= 0) // nothing matched |
1fd5e000 | 442 | { |
a5a965ff | 443 | sigproc_printf ("waiting thread found no children"); |
1fd5e000 | 444 | HANDLE oldw = w->next->ev; |
164a681c | 445 | w->next->pid = 0; |
f02f1f14 CF |
446 | if (clearing) |
447 | w->next->status = -1; /* flag that a signal was received */ | |
06571ff6 | 448 | else if (!potential_match || !(w->next->options & WNOHANG)) |
71625490 | 449 | w->next->ev = NULL; |
1fd5e000 CF |
450 | if (!SetEvent (oldw)) |
451 | system_printf ("couldn't wake up wait event %p, %E", oldw); | |
452 | w->next = w->next->next; | |
453 | } | |
454 | if (w->next == NULL) | |
455 | break; | |
456 | } | |
457 | ||
f02f1f14 | 458 | if (!clearing) |
a5a965ff | 459 | sigproc_printf ("finished processing terminated/stopped child"); |
f02f1f14 | 460 | else |
1fd5e000 | 461 | { |
f02f1f14 | 462 | waitq_head.next = NULL; |
a5a965ff | 463 | sigproc_printf ("finished clearing"); |
1fd5e000 | 464 | } |
1fd5e000 | 465 | break; |
1fd5e000 CF |
466 | } |
467 | ||
468 | out: | |
469 | sync_proc_subproc->release (); // Release the lock | |
470 | out1: | |
a5a965ff | 471 | sigproc_printf ("returning %d", rc); |
1fd5e000 CF |
472 | return rc; |
473 | } | |
474 | ||
475 | /* Terminate the wait_subproc thread. | |
476 | * Called on process exit. | |
477 | * Also called by spawn_guts to disassociate any subprocesses from this | |
478 | * process. Subprocesses will then know to clean up after themselves and | |
479 | * will not become zombies. | |
480 | */ | |
481 | void __stdcall | |
482 | proc_terminate (void) | |
483 | { | |
a5a965ff | 484 | sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies); |
1fd5e000 CF |
485 | /* Signal processing is assumed to be blocked in this routine. */ |
486 | if (hwait_subproc) | |
487 | { | |
1fd5e000 | 488 | proc_loop_wait = 0; // Tell wait_subproc thread to exit |
2a3bf3e2 | 489 | sync_proc_subproc->acquire (WPSP); |
1fd5e000 | 490 | wake_wait_subproc (); // Wake wait_subproc loop |
1fd5e000 | 491 | hwait_subproc = NULL; |
1fd5e000 | 492 | |
9aa07a8f | 493 | (void) proc_subproc (PROC_CLEARWAIT, 1); |
1fd5e000 | 494 | |
1fd5e000 CF |
495 | /* Clean out zombie processes from the pid list. */ |
496 | int i; | |
497 | for (i = 0; i < nzombies; i++) | |
498 | { | |
84c7d409 | 499 | if (zombies[i]->hProcess) |
1fd5e000 | 500 | { |
84c7d409 | 501 | ForceCloseHandle1 (zombies[i]->hProcess, childhProc); |
164a681c | 502 | ForceCloseHandle1 (zombies[i]->pid_handle, pid_handle); |
1fd5e000 | 503 | } |
5ec14fe4 | 504 | zombies[i]->ppid = 1; |
1dc16fc7 | 505 | zombies[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */ |
c90e1cf1 | 506 | zombies[i].release (); // FIXME: this breaks older gccs for some reason |
1fd5e000 CF |
507 | } |
508 | ||
509 | /* Disassociate my subprocesses */ | |
510 | for (i = 0; i < nchildren; i++) | |
511 | { | |
84c7d409 | 512 | if (!pchildren[i]->hProcess) |
a5a965ff | 513 | sigproc_printf ("%d(%d) hProcess cleared already?", pchildren[i]->pid, |
84c7d409 | 514 | pchildren[i]->dwProcessId); |
1fd5e000 CF |
515 | else |
516 | { | |
84c7d409 | 517 | ForceCloseHandle1 (pchildren[i]->hProcess, childhProc); |
aece55b9 | 518 | sigproc_printf ("%d(%d) closed child handle", pchildren[i]->pid, |
84c7d409 | 519 | pchildren[i]->dwProcessId); |
aece55b9 CF |
520 | pchildren[i]->ppid = 1; |
521 | if (pchildren[i]->pgid == myself->pid) | |
522 | pchildren[i]->process_state |= PID_ORPHANED; | |
1fd5e000 | 523 | } |
aece55b9 | 524 | pchildren[i].release (); |
1fd5e000 | 525 | } |
1fd5e000 | 526 | nchildren = nzombies = 0; |
239b06b8 CF |
527 | /* Just zero sync_proc_subproc as the delete below seems to cause |
528 | problems for older gccs. */ | |
239b06b8 | 529 | sync_proc_subproc = NULL; |
1fd5e000 | 530 | } |
a5a965ff | 531 | sigproc_printf ("leaving"); |
1fd5e000 CF |
532 | } |
533 | ||
534 | /* Clear pending signal from the sigtodo array | |
535 | */ | |
536 | void __stdcall | |
537 | sig_clear (int sig) | |
538 | { | |
63b61cd1 | 539 | (void) InterlockedExchange (myself->getsigtodo (sig), 0L); |
06bb4899 | 540 | (void) InterlockedExchange (getlocal_sigtodo (sig), 0L); |
1fd5e000 CF |
541 | return; |
542 | } | |
543 | ||
06bb4899 CF |
544 | extern "C" int |
545 | sigpending (sigset_t *set) | |
546 | { | |
547 | unsigned bit; | |
548 | *set = 0; | |
549 | for (int sig = 1; sig < NSIG; sig++) | |
550 | if ((*getlocal_sigtodo (sig) || *myself->getsigtodo (sig)) | |
551 | && (myself->getsigmask () & (bit = SIGTOMASK (sig)))) | |
552 | *set |= bit; | |
553 | return 0; | |
554 | } | |
555 | ||
1fd5e000 CF |
556 | /* Force the wait_sig thread to wake up and scan the sigtodo array. |
557 | */ | |
558 | extern "C" int __stdcall | |
05cb7b17 | 559 | sig_dispatch_pending () |
1fd5e000 | 560 | { |
05cb7b17 | 561 | if (!hwait_sig || GetCurrentThreadId () == sigtid) |
1fd5e000 | 562 | return 0; |
a0d3c309 CF |
563 | |
564 | sigframe thisframe (mainthread); | |
565 | ||
1fd5e000 | 566 | #ifdef DEBUGGING |
f8e2f358 | 567 | sigproc_printf ("pending_signals %d", pending_signals); |
1fd5e000 | 568 | #endif |
05cb7b17 | 569 | |
f8e2f358 | 570 | if (!pending_signals) |
1fd5e000 | 571 | #ifdef DEBUGGING |
a5a965ff | 572 | sigproc_printf ("no need to wake anything up"); |
1fd5e000 CF |
573 | #else |
574 | ; | |
575 | #endif | |
576 | else | |
577 | { | |
05cb7b17 | 578 | (void) sig_send (myself, __SIGFLUSH); |
1fd5e000 | 579 | #ifdef DEBUGGING |
05cb7b17 | 580 | sigproc_printf ("woke up wait_sig"); |
1fd5e000 | 581 | #endif |
1fd5e000 | 582 | } |
05cb7b17 | 583 | |
f8e2f358 | 584 | return thisframe.call_signal_handler (); |
1fd5e000 CF |
585 | } |
586 | ||
587 | /* Message initialization. Called from dll_crt0_1 | |
588 | * | |
589 | * This routine starts the signal handling thread. The wait_sig_inited | |
590 | * event is used to signal that the thread is ready to handle signals. | |
591 | * We don't wait for this during initialization but instead detect it | |
592 | * in sig_send to gain a little concurrency. | |
593 | */ | |
594 | void __stdcall | |
595 | sigproc_init () | |
596 | { | |
837528aa | 597 | wait_sig_inited = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); |
1fd5e000 CF |
598 | ProtectHandle (wait_sig_inited); |
599 | ||
5ec14fe4 CF |
600 | /* sync_proc_subproc is used by proc_subproc. It serialises |
601 | * access to the children and zombie arrays. | |
602 | */ | |
603 | new_muto (sync_proc_subproc); | |
604 | ||
1fd5e000 CF |
605 | /* local event signaled when main thread has been dispatched |
606 | to a signal handler function. */ | |
c90e1cf1 | 607 | signal_arrived = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); |
aece55b9 | 608 | ProtectHandle (signal_arrived); |
1fd5e000 | 609 | |
1524ae42 | 610 | hwait_sig = new cygthread (wait_sig, cygself, "sig"); |
c4ec64d7 | 611 | hwait_sig->zap_h (); |
1fd5e000 | 612 | |
1fd5e000 CF |
613 | /* Initialize waitq structure for main thread. A waitq structure is |
614 | * allocated for each thread that executes a wait to allow multiple threads | |
615 | * to perform waits. Pre-allocate a waitq structure for the main thread. | |
616 | */ | |
617 | waitq *w; | |
618 | if ((w = (waitq *)waitq_storage.get ()) == NULL) | |
619 | { | |
620 | w = &waitq_main; | |
621 | waitq_storage.set (w); | |
622 | } | |
623 | memset (w, 0, sizeof *w); // Just to be safe | |
624 | ||
c3d62298 | 625 | myself->getsig (SIGSTOP).sa_flags = SA_RESTART | SA_NODEFER; |
a5a965ff | 626 | sigproc_printf ("process/signal handling enabled(%x)", myself->process_state); |
1fd5e000 CF |
627 | return; |
628 | } | |
629 | ||
630 | /* Called on process termination to terminate signal and process threads. | |
631 | */ | |
632 | void __stdcall | |
633 | sigproc_terminate (void) | |
634 | { | |
1fd5e000 CF |
635 | hwait_sig = NULL; |
636 | ||
5ec14fe4 | 637 | if (!sig_loop_wait) |
3543669f | 638 | sigproc_printf ("sigproc handling not active"); |
5ec14fe4 CF |
639 | else |
640 | { | |
641 | sigproc_printf ("entering"); | |
642 | sig_loop_wait = 0; // Tell wait_sig to exit when it is | |
643 | // finished with anything it is doing | |
1fd5e000 CF |
644 | ForceCloseHandle (sigcomplete_main); |
645 | for (int i = 0; i < 20; i++) | |
646 | (void) ReleaseSemaphore (sigcomplete_nonmain, 1, NULL); | |
1dc16fc7 CF |
647 | // ForceCloseHandle (sigcomplete_nonmain); |
648 | // ForceCloseHandle (sigcatch_main); | |
649 | // ForceCloseHandle (sigcatch_nonmain); | |
650 | // ForceCloseHandle (sigcatch_nosync); | |
1fd5e000 CF |
651 | } |
652 | proc_terminate (); // Terminate process handling thread | |
653 | ||
1fd5e000 CF |
654 | return; |
655 | } | |
656 | ||
657 | /* Send a signal to another process by raising its signal semaphore. | |
658 | * If pinfo *p == NULL, send to the current process. | |
659 | * If sending to this process, wait for notification that a signal has | |
660 | * completed before returning. | |
661 | */ | |
662 | int __stdcall | |
cba63823 | 663 | sig_send (_pinfo *p, int sig, DWORD ebp, bool exception) |
1fd5e000 CF |
664 | { |
665 | int rc = 1; | |
666 | DWORD tid = GetCurrentThreadId (); | |
667 | BOOL its_me; | |
668 | HANDLE thiscatch = NULL; | |
669 | HANDLE thiscomplete = NULL; | |
670 | BOOL wait_for_completion; | |
6201d15e | 671 | sigframe thisframe; |
1fd5e000 CF |
672 | |
673 | if (p == myself_nowait_nonmain) | |
84c7d409 | 674 | p = (tid == mainthread.id) ? (_pinfo *) myself : myself_nowait; |
1fd5e000 CF |
675 | if (!(its_me = (p == NULL || p == myself || p == myself_nowait))) |
676 | wait_for_completion = FALSE; | |
677 | else | |
678 | { | |
679 | if (no_signals_available ()) | |
680 | goto out; // Either exiting or not yet initializing | |
5cd82412 CF |
681 | if (wait_sig_inited) |
682 | wait_for_sigthread (); | |
1fd5e000 CF |
683 | wait_for_completion = p != myself_nowait; |
684 | p = myself; | |
685 | } | |
686 | ||
687 | /* It is possible that the process is not yet ready to receive messages | |
688 | * or that it has exited. Detect this. | |
689 | */ | |
690 | if (!proc_can_be_signalled (p)) /* Is the process accepting messages? */ | |
691 | { | |
a5a965ff | 692 | sigproc_printf ("invalid pid %d(%x), signal %d", |
1fd5e000 CF |
693 | p->pid, p->process_state, sig); |
694 | set_errno (ESRCH); | |
695 | goto out; | |
696 | } | |
697 | ||
a5a965ff | 698 | sigproc_printf ("pid %d, signal %d, its_me %d", p->pid, sig, its_me); |
1fd5e000 | 699 | |
06bb4899 | 700 | LONG *todo; |
99a8fab5 | 701 | bool issem; |
1fd5e000 CF |
702 | if (its_me) |
703 | { | |
704 | if (!wait_for_completion) | |
d688945c CF |
705 | { |
706 | thiscatch = sigcatch_nosync; | |
707 | todo = myself->getsigtodo (sig); | |
99a8fab5 | 708 | issem = false; |
d688945c | 709 | } |
6201d15e | 710 | else if (tid != mainthread.id) |
1fd5e000 CF |
711 | { |
712 | thiscatch = sigcatch_nonmain; | |
713 | thiscomplete = sigcomplete_nonmain; | |
d688945c | 714 | todo = getlocal_sigtodo (sig); |
99a8fab5 | 715 | issem = true; |
1fd5e000 CF |
716 | } |
717 | else | |
718 | { | |
719 | thiscatch = sigcatch_main; | |
720 | thiscomplete = sigcomplete_main; | |
cba63823 | 721 | thisframe.set (mainthread, ebp, exception); |
d688945c | 722 | todo = getlocal_sigtodo (sig); |
99a8fab5 | 723 | issem = true; |
1fd5e000 CF |
724 | } |
725 | } | |
99a8fab5 CF |
726 | else if ((thiscatch = getevent (p, "sigcatch"))) |
727 | { | |
728 | todo = p->getsigtodo (sig); | |
729 | issem = false; | |
730 | } | |
06bb4899 | 731 | else |
99a8fab5 | 732 | goto out; // Couldn't get the semaphore. getevent issued |
1fd5e000 CF |
733 | // an error, if appropriate. |
734 | ||
735 | #if WHEN_MULTI_THREAD_SIGNALS_WORK | |
736 | signal_dispatch *sd; | |
737 | sd = signal_dispatch_storage.get (); | |
738 | if (sd == NULL) | |
739 | sd = signal_dispatch_storage.create (); | |
740 | #endif | |
68997e88 | 741 | |
1fd5e000 CF |
742 | /* Increment the sigtodo array to signify which signal to assert. |
743 | */ | |
06bb4899 | 744 | (void) InterlockedIncrement (todo); |
1fd5e000 CF |
745 | |
746 | /* Notify the process that a signal has arrived. | |
747 | */ | |
99a8fab5 | 748 | if (issem ? !ReleaseSemaphore (thiscatch, 1, NULL) : !SetEvent (thiscatch)) |
1fd5e000 CF |
749 | { |
750 | /* Couldn't signal the semaphore. This probably means that the | |
751 | * process is exiting. | |
752 | */ | |
753 | if (!its_me) | |
754 | ForceCloseHandle (thiscatch); | |
755 | else | |
756 | { | |
757 | if (no_signals_available ()) | |
a5a965ff | 758 | sigproc_printf ("I'm going away now"); |
1fd5e000 CF |
759 | else if ((int) GetLastError () == -1) |
760 | rc = WaitForSingleObject (thiscomplete, 500); | |
761 | else | |
762 | system_printf ("error sending signal %d to pid %d, semaphore %p, %E", | |
763 | sig, p->pid, thiscatch); | |
764 | } | |
765 | goto out; | |
766 | } | |
767 | ||
768 | /* No need to wait for signal completion unless this was a signal to | |
769 | * this process. | |
770 | * | |
771 | * If it was a signal to this process, wait for a dispatched signal. | |
772 | * Otherwise just wait for the wait_sig to signal that it has finished | |
773 | * processing the signal. | |
774 | */ | |
775 | if (!wait_for_completion) | |
776 | { | |
68997e88 | 777 | rc = WAIT_OBJECT_0; |
f6111483 | 778 | sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", its_me, sig); |
68997e88 CF |
779 | if (!its_me) |
780 | ForceCloseHandle (thiscatch); | |
1fd5e000 CF |
781 | } |
782 | else | |
783 | { | |
a5a965ff | 784 | sigproc_printf ("Waiting for thiscomplete %p", thiscomplete); |
1fd5e000 | 785 | rc = WaitForSingleObject (thiscomplete, WSSC); |
1fd5e000 CF |
786 | } |
787 | ||
788 | if (rc == WAIT_OBJECT_0) | |
789 | rc = 0; // Successful exit | |
790 | else | |
791 | { | |
792 | /* It's an error unless sig_loop_wait == 0 (the process is exiting). */ | |
793 | if (!no_signals_available ()) | |
f6111483 | 794 | system_printf ("wait for sig_complete event failed, signal %d, rc %d, %E", |
1fd5e000 CF |
795 | sig, rc); |
796 | set_errno (ENOSYS); | |
797 | rc = -1; | |
798 | } | |
799 | ||
800 | out: | |
a5a965ff | 801 | sigproc_printf ("returning %d from sending signal %d", rc, sig); |
1fd5e000 CF |
802 | return rc; |
803 | } | |
804 | ||
805 | /* Set pending signal from the sigtodo array | |
806 | */ | |
807 | void __stdcall | |
808 | sig_set_pending (int sig) | |
809 | { | |
06bb4899 | 810 | (void) InterlockedIncrement (getlocal_sigtodo (sig)); |
1fd5e000 CF |
811 | return; |
812 | } | |
813 | ||
814 | /* Initialize the wait_subproc thread. | |
815 | * Called from fork() or spawn() to initialize the handling of subprocesses. | |
816 | */ | |
817 | void __stdcall | |
818 | subproc_init (void) | |
819 | { | |
820 | if (hwait_subproc) | |
821 | return; | |
822 | ||
823 | /* A "wakeup" handle which can be toggled to make wait_subproc reexamine | |
824 | * the hchildren array. | |
825 | */ | |
826 | events[0] = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); | |
b6bd7037 | 827 | hwait_subproc = new cygthread (wait_subproc, NULL, "proc"); |
969203ce | 828 | hwait_subproc->zap_h (); |
1fd5e000 | 829 | ProtectHandle (events[0]); |
969203ce | 830 | sigproc_printf ("started wait_subproc thread"); |
1fd5e000 CF |
831 | } |
832 | ||
833 | /* Initialize some of the memory block passed to child processes | |
834 | by fork/spawn/exec. */ | |
835 | ||
836 | void __stdcall | |
84c7d409 | 837 | init_child_info (DWORD chtype, child_info *ch, pid_t pid, HANDLE subproc_ready) |
1fd5e000 | 838 | { |
1fd5e000 | 839 | memset (ch, 0, sizeof *ch); |
aaf219f0 | 840 | ch->cb = chtype == PROC_FORK ? sizeof (child_info_fork) : sizeof (child_info); |
77f4a250 CF |
841 | ch->intro = PROC_MAGIC_GENERIC; |
842 | ch->magic = CHILD_INFO_MAGIC; | |
1fd5e000 CF |
843 | ch->type = chtype; |
844 | ch->cygpid = pid; | |
1fd5e000 | 845 | ch->subproc_ready = subproc_ready; |
dd11f11f | 846 | ch->pppid_handle = myself->ppid_handle; |
aaf219f0 | 847 | ch->fhandler_union_cb = sizeof (fhandler_union); |
115a0885 | 848 | ch->mount_h = cygwin_mount_h; |
1fd5e000 CF |
849 | } |
850 | ||
851 | /* Check the state of all of our children to see if any are stopped or | |
852 | * terminated. | |
853 | */ | |
854 | static int __stdcall | |
164a681c | 855 | checkstate (waitq *parent_w) |
1fd5e000 | 856 | { |
164a681c | 857 | int potential_match = 0; |
1fd5e000 | 858 | |
a5a965ff | 859 | sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies); |
1fd5e000 CF |
860 | |
861 | /* Check already dead processes first to see if they match the criteria | |
862 | * given in w->next. | |
863 | */ | |
164a681c CF |
864 | for (int i = 0; i < nzombies; i++) |
865 | switch (stopped_or_terminated (parent_w, zombies[i])) | |
1fd5e000 | 866 | { |
164a681c CF |
867 | case -1: |
868 | potential_match = -1; | |
869 | break; | |
870 | case 1: | |
1fd5e000 CF |
871 | remove_zombie (i); |
872 | potential_match = 1; | |
873 | goto out; | |
874 | } | |
875 | ||
a5a965ff | 876 | sigproc_printf ("checking alive children"); |
1fd5e000 CF |
877 | |
878 | /* No dead terminated children matched. Check for stopped children. */ | |
164a681c CF |
879 | for (int i = 0; i < nchildren; i++) |
880 | switch (stopped_or_terminated (parent_w, pchildren[i])) | |
1fd5e000 | 881 | { |
164a681c CF |
882 | case -1: |
883 | potential_match = -1; | |
1fd5e000 | 884 | break; |
164a681c CF |
885 | case 1: |
886 | potential_match = 1; | |
887 | goto out; | |
1fd5e000 CF |
888 | } |
889 | ||
890 | out: | |
a5a965ff | 891 | sigproc_printf ("returning %d", potential_match); |
1fd5e000 CF |
892 | return potential_match; |
893 | } | |
894 | ||
895 | /* Get or create a process specific semaphore used in message passing. | |
896 | */ | |
897 | static HANDLE __stdcall | |
99a8fab5 | 898 | getevent (_pinfo *p, const char *str) |
1fd5e000 CF |
899 | { |
900 | HANDLE h; | |
5c768c97 | 901 | char sem_name[MAX_PATH]; |
1fd5e000 CF |
902 | |
903 | if (p != NULL) | |
904 | { | |
905 | if (!proc_can_be_signalled (p)) | |
906 | { | |
907 | set_errno (ESRCH); | |
908 | return NULL; | |
909 | } | |
1229d4f4 | 910 | int wait = 1000; |
4a08cbfe | 911 | /* Wait for new process to generate its semaphores. */ |
a5a965ff | 912 | sigproc_printf ("pid %d, ppid %d, wait %d, initializing %x", p->pid, p->ppid, wait, |
1fd5e000 CF |
913 | ISSTATE (p, PID_INITIALIZING)); |
914 | for (int i = 0; ISSTATE (p, PID_INITIALIZING) && i < wait; i++) | |
c0a02a4b | 915 | low_priority_sleep (1); |
1fd5e000 CF |
916 | } |
917 | ||
1fd5e000 CF |
918 | if (p == NULL) |
919 | { | |
920 | char sa_buf[1024]; | |
921 | ||
922 | DWORD winpid = GetCurrentProcessId (); | |
99a8fab5 | 923 | #if 0 |
cecb74ae | 924 | h = CreateSemaphore (sec_user_nih (sa_buf), init, max, |
5c768c97 | 925 | str = shared_name (sem_name, str, winpid)); |
99a8fab5 CF |
926 | #else |
927 | h = CreateEvent (sec_user_nih (sa_buf), FALSE, FALSE, | |
928 | str = shared_name (sem_name, str, winpid)); | |
929 | #endif | |
1fd5e000 | 930 | p = myself; |
4a08cbfe CF |
931 | if (!h) |
932 | { | |
a2e12d0c | 933 | system_printf ("can't create semaphore %s, %E", str); |
4a08cbfe CF |
934 | __seterrno (); |
935 | } | |
1fd5e000 CF |
936 | } |
937 | else | |
938 | { | |
99a8fab5 | 939 | #if 0 |
1fd5e000 | 940 | h = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE, |
5c768c97 | 941 | shared_name (sem_name, str, p->dwProcessId)); |
99a8fab5 CF |
942 | #else |
943 | h = OpenEvent (EVENT_ALL_ACCESS, FALSE, | |
944 | shared_name (sem_name, str, p->dwProcessId)); | |
945 | #endif | |
1fd5e000 | 946 | |
4a08cbfe | 947 | if (!h) |
1fd5e000 CF |
948 | { |
949 | if (GetLastError () == ERROR_FILE_NOT_FOUND && !proc_exists (p)) | |
4a08cbfe | 950 | set_errno (ESRCH); /* No such process */ |
1fd5e000 | 951 | else |
4a08cbfe CF |
952 | set_errno (EPERM); /* Couldn't access the semaphore -- |
953 | different cygwin DLL maybe? */ | |
1fd5e000 CF |
954 | } |
955 | } | |
956 | ||
1fd5e000 CF |
957 | return h; |
958 | } | |
959 | ||
1fd5e000 CF |
960 | /* Remove a zombie from zombies by swapping it with the last child in the list. |
961 | */ | |
962 | static void __stdcall | |
963 | remove_zombie (int ci) | |
964 | { | |
a5a965ff | 965 | sigproc_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid, |
164a681c | 966 | nzombies); |
84c7d409 CF |
967 | |
968 | if (zombies[ci]) | |
164a681c CF |
969 | { |
970 | ForceCloseHandle1 (zombies[ci]->hProcess, childhProc); | |
971 | ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle); | |
164a681c CF |
972 | zombies[ci].release (); |
973 | } | |
84c7d409 | 974 | |
1fd5e000 CF |
975 | if (ci < --nzombies) |
976 | zombies[ci] = zombies[nzombies]; | |
977 | ||
978 | return; | |
979 | } | |
980 | ||
981 | /* Check status of child process vs. waitq member. | |
982 | * | |
983 | * parent_w is the pointer to the parent of the waitq member in question. | |
984 | * child is the subprocess being considered. | |
985 | * | |
986 | * Returns | |
987 | * 1 if stopped or terminated child matches parent_w->next criteria | |
988 | * -1 if a non-stopped/terminated child matches parent_w->next criteria | |
989 | * 0 if child does not match parent_w->next criteria | |
990 | */ | |
991 | static int __stdcall | |
84c7d409 | 992 | stopped_or_terminated (waitq *parent_w, _pinfo *child) |
1fd5e000 CF |
993 | { |
994 | int potential_match; | |
995 | waitq *w = parent_w->next; | |
996 | ||
a5a965ff | 997 | sigproc_printf ("considering pid %d", child->pid); |
1fd5e000 CF |
998 | if (w->pid == -1) |
999 | potential_match = 1; | |
1000 | else if (w->pid == 0) | |
1001 | potential_match = child->pgid == myself->pgid; | |
1002 | else if (w->pid < 0) | |
1003 | potential_match = child->pgid == -w->pid; | |
1004 | else | |
1005 | potential_match = (w->pid == child->pid); | |
1006 | ||
1007 | if (!potential_match) | |
1008 | return 0; | |
1009 | ||
1010 | BOOL terminated; | |
1011 | ||
1012 | if ((terminated = child->process_state == PID_ZOMBIE) || | |
f80cdaee | 1013 | ((w->options & WUNTRACED) && child->stopsig)) |
1fd5e000 CF |
1014 | { |
1015 | parent_w->next = w->next; /* successful wait. remove from wait queue */ | |
1016 | w->pid = child->pid; | |
1017 | ||
1018 | if (!terminated) | |
1019 | { | |
a5a965ff | 1020 | sigproc_printf ("stopped child"); |
1fd5e000 CF |
1021 | w->status = (child->stopsig << 8) | 0x7f; |
1022 | child->stopsig = 0; | |
1023 | } | |
84c7d409 | 1024 | else /* Should only get here when child has been moved to the zombies array */ |
1fd5e000 CF |
1025 | { |
1026 | DWORD status; | |
1027 | if (!GetExitCodeProcess (child->hProcess, &status)) | |
1028 | status = 0xffff; | |
1029 | if (status & EXIT_SIGNAL) | |
1030 | w->status = (status >> 8) & 0xff; /* exited due to signal */ | |
1031 | else | |
1032 | w->status = (status & 0xff) << 8; /* exited via "exit ()" */ | |
1033 | ||
1034 | add_rusage (&myself->rusage_children, &child->rusage_children); | |
1035 | add_rusage (&myself->rusage_children, &child->rusage_self); | |
1036 | ||
1037 | if (w->rusage) | |
1038 | { | |
1039 | add_rusage ((struct rusage *) w->rusage, &child->rusage_children); | |
1040 | add_rusage ((struct rusage *) w->rusage, &child->rusage_self); | |
1041 | } | |
1fd5e000 CF |
1042 | } |
1043 | ||
1044 | if (!SetEvent (w->ev)) /* wake up wait4 () immediately */ | |
1045 | system_printf ("couldn't wake up wait event %p, %E", w->ev); | |
1046 | return 1; | |
1047 | } | |
1048 | ||
1049 | return -potential_match; | |
1050 | } | |
1051 | ||
831d6fa5 CF |
1052 | static void |
1053 | talktome () | |
1054 | { | |
1055 | winpids pids; | |
1056 | for (unsigned i = 0; i < pids.npids; i++) | |
1057 | if (pids[i]->hello_pid == myself->pid) | |
1058 | pids[i]->commune_recv (); | |
1059 | } | |
1060 | ||
5f31e0f3 CF |
1061 | #define RC_MAIN 0 |
1062 | #define RC_NONMAIN 1 | |
1063 | #define RC_NOSYNC 2 | |
1fd5e000 CF |
1064 | /* Process signals by waiting for a semaphore to become signaled. |
1065 | * Then scan an in-memory array representing queued signals. | |
1066 | * Executes in a separate thread. | |
1067 | * | |
1068 | * Signals sent from this process are sent a completion signal so | |
1069 | * that returns from kill/raise do not occur until the signal has | |
1070 | * has been handled, as per POSIX. | |
1071 | */ | |
1072 | static DWORD WINAPI | |
1524ae42 | 1073 | wait_sig (VOID *self) |
1fd5e000 | 1074 | { |
06bb4899 | 1075 | LONG *todos[] = {getlocal_sigtodo (0), myself->getsigtodo (0)}; |
1fd5e000 | 1076 | /* Initialization */ |
c4ec64d7 | 1077 | (void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY); |
1fd5e000 CF |
1078 | |
1079 | /* sigcatch_nosync - semaphore incremented by sig_dispatch_pending and | |
1080 | * by foreign processes to force an examination of | |
1081 | * the sigtodo array. | |
1082 | * sigcatch_main - ditto for local main thread. | |
1083 | * sigcatch_nonmain - ditto for local non-main threads. | |
1084 | * | |
1085 | * sigcomplete_main - event used to signal main thread on signal | |
1086 | * completion | |
1087 | * sigcomplete_nonmain - semaphore signaled for non-main thread on signal | |
1088 | * completion | |
1089 | */ | |
99a8fab5 | 1090 | sigcatch_nosync = getevent (NULL, "sigcatch"); |
1fd5e000 CF |
1091 | sigcatch_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); |
1092 | sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); | |
1093 | sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); | |
af1dc7cc | 1094 | sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); |
1ec4f618 | 1095 | sigproc_printf ("sigcatch_nonmain %p, sigcatch_main %p", sigcatch_nonmain, sigcatch_main); |
0428827b | 1096 | sigCONT = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); |
1fd5e000 CF |
1097 | |
1098 | /* Setting dwProcessId flags that this process is now capable of receiving | |
1099 | * signals. Prior to this, dwProcessId was set to the windows pid of | |
1100 | * of the original windows process which spawned us unless this was a | |
1101 | * "toplevel" process. | |
1102 | */ | |
1103 | myself->dwProcessId = GetCurrentProcessId (); | |
1104 | myself->process_state |= PID_ACTIVE; | |
1105 | myself->process_state &= ~PID_INITIALIZING; | |
1106 | ||
1107 | ProtectHandle (sigcatch_nosync); | |
1108 | ProtectHandle (sigcatch_nonmain); | |
1109 | ProtectHandle (sigcatch_main); | |
1110 | ProtectHandle (sigcomplete_nonmain); | |
1111 | ProtectHandle (sigcomplete_main); | |
1112 | ||
1113 | /* If we've been execed, then there is still a stub left in the previous | |
1114 | * windows process waiting to see if it's started a cygwin process or not. | |
1115 | * Signalling subproc_ready indicates that we are a cygwin process. | |
1116 | */ | |
5457dfcb | 1117 | if (child_proc_info && child_proc_info->type == PROC_EXEC) |
1fd5e000 CF |
1118 | { |
1119 | debug_printf ("subproc_ready %p", child_proc_info->subproc_ready); | |
1120 | if (!SetEvent (child_proc_info->subproc_ready)) | |
1121 | system_printf ("SetEvent (subproc_ready) failed, %E"); | |
0301bfd0 | 1122 | ForceCloseHandle1 (child_proc_info->subproc_ready, subproc_ready); |
3c2c3745 CF |
1123 | /* Initialize an "indirect" pid block so that if someone looks up this |
1124 | process via its Windows PID it will be redirected to the appropriate | |
1125 | Cygwin PID shared memory block. */ | |
1126 | static pinfo NO_COPY myself_identity; | |
1127 | myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED); | |
1fd5e000 CF |
1128 | } |
1129 | ||
1130 | SetEvent (wait_sig_inited); | |
1131 | sigtid = GetCurrentThreadId (); | |
1132 | ||
1fd5e000 CF |
1133 | HANDLE catchem[] = {sigcatch_main, sigcatch_nonmain, sigcatch_nosync}; |
1134 | sigproc_printf ("Ready. dwProcessid %d", myself->dwProcessId); | |
6f6d673c CF |
1135 | DWORD rc = RC_NOSYNC; |
1136 | bool flush = false; | |
0d675c5d | 1137 | for (;;) |
1fd5e000 | 1138 | { |
6f6d673c CF |
1139 | DWORD i; |
1140 | if (rc == RC_MAIN || rc == RC_NONMAIN) | |
1141 | i = RC_NOSYNC; | |
1142 | else | |
1143 | i = RC_MAIN; | |
1144 | rc = WaitForSingleObject (catchem[i], 0); | |
1145 | if (rc != WAIT_OBJECT_0) | |
1146 | rc = WaitForMultipleObjects (3, catchem, FALSE, sig_loop_wait); | |
1147 | else | |
1148 | rc = i + WAIT_OBJECT_0; | |
6597785d | 1149 | (void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY); |
1fd5e000 CF |
1150 | |
1151 | /* sigproc_terminate sets sig_loop_wait to zero to indicate that | |
90f4768b | 1152 | this thread should terminate. */ |
1fd5e000 | 1153 | if (rc == WAIT_TIMEOUT) |
018a91fa CF |
1154 | { |
1155 | if (!sig_loop_wait) | |
1156 | break; // Exiting | |
1157 | else | |
1158 | continue; | |
1159 | } | |
1fd5e000 CF |
1160 | |
1161 | if (rc == WAIT_FAILED) | |
1162 | { | |
1163 | if (sig_loop_wait != 0) | |
1164 | system_printf ("WFMO failed, %E"); | |
1165 | break; | |
1166 | } | |
1167 | ||
1168 | rc -= WAIT_OBJECT_0; | |
06bb4899 | 1169 | sigproc_printf ("awake, rc %d", rc); |
d688945c CF |
1170 | LONG *todo; |
1171 | if (rc != RC_NOSYNC) | |
5e8355c7 | 1172 | todo = todos[0]; |
d688945c CF |
1173 | else |
1174 | todo = todos[1]; | |
06bb4899 | 1175 | |
1fd5e000 | 1176 | /* A sigcatch semaphore has been signaled. Scan the sigtodo |
90f4768b | 1177 | array looking for any unprocessed signals. */ |
d688945c | 1178 | pending_signals = false; |
90f4768b | 1179 | unsigned more_signals = 0; |
a9f77544 | 1180 | bool saw_failed_interrupt = false; |
d688945c | 1181 | do |
90f4768b CF |
1182 | { |
1183 | more_signals = 0; | |
1184 | for (int sig = -__SIGOFFSET; sig < NSIG; sig++) | |
1185 | { | |
1186 | LONG x = InterlockedDecrement (todo + sig); | |
1187 | if (x < 0) | |
1188 | InterlockedIncrement (todo + sig); | |
1189 | else if (x >= 0) | |
1190 | { | |
1191 | /* If x > 0, we have to deal with a signal at some later point */ | |
1192 | if (rc != RC_NOSYNC && x > 0) | |
75119e99 | 1193 | /*pending_signals = true*/; // There should be an armed semaphore, in this case |
90f4768b CF |
1194 | |
1195 | if (sig > 0 && sig != SIGKILL && sig != SIGSTOP && | |
1196 | (sigismember (&myself->getsigmask (), sig) || | |
1197 | main_vfork->pid || | |
1198 | (sig != SIGCONT && ISSTATE (myself, PID_STOPPED)))) | |
1199 | { | |
1200 | sigproc_printf ("signal %d blocked", sig); | |
1201 | x = InterlockedIncrement (myself->getsigtodo (sig)); | |
75119e99 | 1202 | /* pending_signals = true;*/ // will be set by set_process_mask |
90f4768b CF |
1203 | } |
1204 | else | |
1205 | { | |
1206 | sigproc_printf ("processing signal %d", sig); | |
1207 | switch (sig) | |
1208 | { | |
1209 | case __SIGFLUSH: | |
1210 | if (rc == RC_MAIN) | |
1211 | { | |
1212 | flush = true; | |
99a8fab5 | 1213 | SetEvent (sigcatch_nosync); |
90f4768b CF |
1214 | goto out1; |
1215 | } | |
1216 | break; | |
1217 | ||
1218 | /* Internal signal to turn on stracing. */ | |
1219 | case __SIGSTRACE: | |
1220 | strace.hello (); | |
1221 | break; | |
1222 | ||
1223 | case __SIGCOMMUNE: | |
1224 | talktome (); | |
1225 | break; | |
1226 | ||
1227 | /* A normal UNIX signal */ | |
1228 | default: | |
1229 | sigproc_printf ("Got signal %d", sig); | |
1230 | if (!sig_handle (sig)) | |
1231 | { | |
75119e99 | 1232 | pending_signals = true; |
90f4768b | 1233 | saw_failed_interrupt = true; |
90f4768b | 1234 | x = InterlockedIncrement (myself->getsigtodo (sig)); |
90f4768b CF |
1235 | } |
1236 | } | |
1237 | if (rc == RC_NOSYNC && x > 0) | |
1238 | more_signals++; | |
1239 | } | |
1240 | ||
1241 | if (sig == SIGCHLD) | |
1242 | proc_subproc (PROC_CLEARWAIT, 0); | |
1243 | ||
1244 | /* Need to take special action if an interrupt failed due to main thread not | |
1245 | getting around to calling handler yet. */ | |
1246 | if (saw_failed_interrupt || rc != RC_NOSYNC) | |
1247 | goto out; | |
1248 | } | |
1249 | } | |
1250 | #ifdef DEBUGGING | |
1251 | if (more_signals > 100) | |
1252 | system_printf ("hmm. infinite loop? more_signals %u\n", more_signals); | |
1253 | #endif | |
1254 | } | |
1255 | while (more_signals && sig_loop_wait); | |
1fd5e000 | 1256 | |
5f31e0f3 | 1257 | out: |
1fd5e000 | 1258 | /* Signal completion of signal handling depending on which semaphore |
5f31e0f3 | 1259 | woke up the WaitForMultipleObjects above. */ |
6f6d673c CF |
1260 | if (rc == RC_NONMAIN) // FIXME: This is broken |
1261 | ReleaseSemaphore (sigcomplete_nonmain, 1, NULL); | |
1262 | else if (rc == RC_MAIN || flush) | |
1fd5e000 | 1263 | { |
1fd5e000 | 1264 | SetEvent (sigcomplete_main); |
7cf3b655 | 1265 | sigproc_printf ("set main thread completion event"); |
6f6d673c | 1266 | flush = false; |
1fd5e000 | 1267 | } |
90f4768b | 1268 | |
6f6d673c | 1269 | out1: |
5f31e0f3 | 1270 | if (saw_failed_interrupt) |
d688945c | 1271 | { |
99a8fab5 | 1272 | SetEvent (sigcatch_nosync); |
d688945c CF |
1273 | low_priority_sleep (0); /* Hopefully, other thread will be waking up soon. */ |
1274 | } | |
a5a965ff | 1275 | sigproc_printf ("looping"); |
1fd5e000 CF |
1276 | } |
1277 | ||
a5a965ff | 1278 | sigproc_printf ("done"); |
c4ec64d7 | 1279 | ExitThread (0); |
1fd5e000 CF |
1280 | } |
1281 | ||
1282 | /* Wait for subprocesses to terminate. Executes in a separate thread. */ | |
1283 | static DWORD WINAPI | |
9cec3d45 | 1284 | wait_subproc (VOID *) |
1fd5e000 | 1285 | { |
a5a965ff | 1286 | sigproc_printf ("starting"); |
1fd5e000 CF |
1287 | int errloop = 0; |
1288 | ||
1289 | for (;;) | |
1290 | { | |
1291 | DWORD rc = WaitForMultipleObjects (nchildren + 1, events, FALSE, | |
1292 | proc_loop_wait); | |
1293 | if (rc == WAIT_TIMEOUT) | |
1294 | if (!proc_loop_wait) | |
1295 | break; // Exiting | |
1296 | else | |
1297 | continue; | |
1298 | ||
1299 | if (rc == WAIT_FAILED) | |
1300 | { | |
1301 | if (!proc_loop_wait) | |
1302 | break; | |
1303 | ||
1304 | /* It's ok to get an ERROR_INVALID_HANDLE since another thread may have | |
1305 | closed a handle in the children[] array. So, we try looping a couple | |
1306 | of times to stabilize. FIXME - this is not foolproof. Probably, this | |
1307 | thread should be responsible for closing the children. */ | |
e46db834 CF |
1308 | if (!errloop++) |
1309 | proc_subproc (PROC_NOTHING, 0); // Just synchronize and continue | |
1310 | if (errloop < 10) | |
1fd5e000 CF |
1311 | continue; |
1312 | ||
1313 | system_printf ("wait failed. nchildren %d, wait %d, %E", | |
1314 | nchildren, proc_loop_wait); | |
1315 | ||
1ae469ad | 1316 | for (int i = 0; i <= nchildren; i++) |
1fd5e000 CF |
1317 | if ((rc = WaitForSingleObject (events[i], 0)) == WAIT_OBJECT_0 || |
1318 | rc == WAIT_TIMEOUT) | |
1319 | continue; | |
95101076 CF |
1320 | else if (i == 0) |
1321 | system_printf ("nchildren %d, event[%d] %p, %E", nchildren, i, events[i]); | |
1fd5e000 | 1322 | else |
c2445f2a | 1323 | { |
1ae469ad | 1324 | system_printf ("nchildren %d, event[%d] %p, pchildren[%d] %p, events[0] %p, %E", |
914f7bf5 | 1325 | nchildren, i, events[i], i - 1, (_pinfo *) pchildren[i - 1], events[0]); |
95101076 | 1326 | system_printf ("pid %d, dwProcessId %u, hProcess %p, progname '%s'", |
914f7bf5 | 1327 | pchildren[i - 1]->pid, pchildren[i - 1]->dwProcessId, |
95101076 | 1328 | pchildren[i - 1]->hProcess, pchildren[i - 1]->progname); |
c2445f2a | 1329 | } |
1fd5e000 CF |
1330 | break; |
1331 | } | |
1332 | ||
1333 | errloop = 0; | |
1334 | rc -= WAIT_OBJECT_0; | |
1335 | if (rc-- != 0) | |
1dc16fc7 | 1336 | { |
3f7bd531 | 1337 | rc = proc_subproc (PROC_CHILDTERMINATED, rc); |
1dc16fc7 CF |
1338 | if (!proc_loop_wait) // Don't bother if wait_subproc is |
1339 | break; // exiting | |
1340 | ||
3f7bd531 CF |
1341 | /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc |
1342 | to avoid the proc_subproc lock since the signal thread will eventually | |
1343 | be calling proc_subproc and could unnecessarily block. */ | |
1344 | if (rc) | |
1345 | sig_send (myself_nowait, SIGCHLD); | |
1dc16fc7 | 1346 | } |
a5a965ff | 1347 | sigproc_printf ("looping"); |
1fd5e000 CF |
1348 | } |
1349 | ||
1350 | ForceCloseHandle (events[0]); | |
1351 | events[0] = NULL; | |
a5a965ff | 1352 | sigproc_printf ("done"); |
c4ec64d7 | 1353 | ExitThread (0); |
1fd5e000 | 1354 | } |
6201d15e CF |
1355 | |
1356 | extern "C" { | |
1357 | /* Provide a stack frame when calling WaitFor* functions */ | |
1358 | ||
1359 | #undef WaitForSingleObject | |
1360 | ||
1361 | DWORD __stdcall | |
1362 | WFSO (HANDLE hHandle, DWORD dwMilliseconds) | |
1363 | { | |
1364 | DWORD ret; | |
1365 | sigframe thisframe (mainthread); | |
1366 | ret = WaitForSingleObject (hHandle, dwMilliseconds); | |
1367 | return ret; | |
1368 | } | |
1369 | ||
1370 | #undef WaitForMultipleObjects | |
1371 | ||
1372 | DWORD __stdcall | |
1373 | WFMO (DWORD nCount, CONST HANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds) | |
1374 | { | |
1375 | DWORD ret; | |
1376 | sigframe thisframe (mainthread); | |
1377 | ret = WaitForMultipleObjects (nCount, lpHandles, fWaitAll, dwMilliseconds); | |
1378 | return ret; | |
1379 | } | |
1380 | } |