]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* sigproc.cc: inter/intra signal and sub process handler |
2 | ||
68f62c98 | 3 | Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, |
0e1f0840 | 4 | 2006, 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc. |
1fd5e000 CF |
5 | |
6 | This file is part of Cygwin. | |
7 | ||
8 | This software is a copyrighted work licensed under the terms of the | |
9 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
10 | details. */ | |
11 | ||
4c8d72de | 12 | #include "winsup.h" |
ade47a34 | 13 | #include "miscfuncs.h" |
1fd5e000 | 14 | #include <stdlib.h> |
f0338f54 | 15 | #include <sys/cygwin.h> |
9e2baf8d | 16 | #include "cygerrno.h" |
0e1f0840 | 17 | #include "sigproc.h" |
47063f00 | 18 | #include "path.h" |
7ac61736 | 19 | #include "fhandler.h" |
0381fec6 | 20 | #include "dtable.h" |
8dec7b03 | 21 | #include "cygheap.h" |
77f4a250 | 22 | #include "child_info_magic.h" |
29ac7f89 | 23 | #include "shared_info.h" |
62e070d7 | 24 | #include "cygtls.h" |
93d606f6 | 25 | #include "ntdll.h" |
e52a43f1 | 26 | #include "exception.h" |
1fd5e000 CF |
27 | |
28 | /* | |
29 | * Convenience defines | |
30 | */ | |
b50fe821 CF |
31 | #define WSSC 60000 // Wait for signal completion |
32 | #define WPSP 40000 // Wait for proc_subproc mutex | |
33 | ||
6c6eb02b | 34 | #define no_signals_available(x) (!my_sendsig || ((x) && myself->exitcode & EXITCODE_SET) || (&_my_tls == _sig_tls)) |
1fd5e000 CF |
35 | |
36 | /* | |
37 | * Global variables | |
38 | */ | |
474048c2 CF |
39 | struct sigaction *global_sigs; |
40 | ||
1fd5e000 CF |
41 | const char *__sp_fn ; |
42 | int __sp_ln; | |
43 | ||
44 | char NO_COPY myself_nowait_dummy[1] = {'0'};// Flag to sig_send that signal goes to | |
45 | // current process but no wait is required | |
1fd5e000 | 46 | |
edc4f86a | 47 | #define Static static NO_COPY |
1fd5e000 | 48 | |
0428827b | 49 | HANDLE NO_COPY sigCONT; // Used to "STOP" a process |
1fd5e000 | 50 | |
e8bf2329 | 51 | Static bool sigheld; // True if holding signals |
1fd5e000 | 52 | |
8cb359d9 | 53 | Static int nprocs; // Number of deceased children |
37d5841f CF |
54 | Static char cprocs[(NPROCS + 1) * sizeof (pinfo)];// All my children info |
55 | #define procs ((pinfo *) cprocs) // All this just to avoid expensive | |
56 | // constructor operation at DLL startup | |
6b838263 | 57 | Static waitq waitq_head; // Start of queue for wait'ing threads |
1fd5e000 | 58 | |
e8bf2329 | 59 | Static muto sync_proc_subproc; // Control access to subproc stuff |
f02f1f14 | 60 | |
a611ae50 | 61 | _cygtls NO_COPY *_sig_tls; |
1fd5e000 | 62 | |
81010d21 | 63 | Static HANDLE my_sendsig; |
4ab568c6 | 64 | Static HANDLE my_readsig; |
81010d21 | 65 | |
474048c2 | 66 | /* Function declarations */ |
99a8fab5 | 67 | static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1))); |
2e008fb9 | 68 | static __inline__ bool get_proc_lock (DWORD, DWORD); |
8cb359d9 CF |
69 | static bool __stdcall remove_proc (int); |
70 | static bool __stdcall stopped_or_terminated (waitq *, _pinfo *); | |
b9874a0c | 71 | static void WINAPI wait_sig (VOID *arg); |
1fd5e000 | 72 | |
474048c2 CF |
73 | /* wait_sig bookkeeping */ |
74 | ||
75 | class pending_signals | |
76 | { | |
77 | sigpacket sigs[NSIG + 1]; | |
78 | sigpacket start; | |
79 | sigpacket *end; | |
80 | sigpacket *prev; | |
81 | sigpacket *curr; | |
82 | public: | |
83 | void reset () {curr = &start; prev = &start;} | |
84 | void add (sigpacket&); | |
85 | void del (); | |
dc3dc498 | 86 | bool pending () const {return !!start.next;} |
474048c2 CF |
87 | sigpacket *next (); |
88 | sigpacket *save () const {return curr;} | |
89 | void restore (sigpacket *saved) {curr = saved;} | |
90 | friend void __stdcall sig_dispatch_pending (bool); | |
b9874a0c | 91 | friend void WINAPI wait_sig (VOID *arg); |
474048c2 CF |
92 | }; |
93 | ||
e8bf2329 | 94 | Static pending_signals sigq; |
474048c2 CF |
95 | |
96 | /* Functions */ | |
edc4f86a CF |
97 | void __stdcall |
98 | sigalloc () | |
99 | { | |
100 | cygheap->sigs = global_sigs = | |
ee4388c4 | 101 | (struct sigaction *) ccalloc_abort (HEAP_SIGS, NSIG, sizeof (struct sigaction)); |
bbca1e4c | 102 | global_sigs[SIGSTOP].sa_flags = SA_RESTART | SA_NODEFER; |
edc4f86a CF |
103 | } |
104 | ||
105 | void __stdcall | |
106 | signal_fixup_after_exec () | |
107 | { | |
108 | global_sigs = cygheap->sigs; | |
109 | /* Set up child's signal handlers */ | |
110 | for (int i = 0; i < NSIG; i++) | |
111 | { | |
112 | global_sigs[i].sa_mask = 0; | |
113 | if (global_sigs[i].sa_handler != SIG_IGN) | |
d5f4ee62 CF |
114 | { |
115 | global_sigs[i].sa_handler = SIG_DFL; | |
116 | global_sigs[i].sa_flags &= ~ SA_SIGINFO; | |
117 | } | |
edc4f86a CF |
118 | } |
119 | } | |
120 | ||
243a041b | 121 | /* Get the sync_proc_subproc muto to control access to |
8cb359d9 | 122 | * children, proc arrays. |
243a041b CF |
123 | * Attempt to handle case where process is exiting as we try to grab |
124 | * the mutex. | |
125 | */ | |
2e008fb9 | 126 | static bool |
243a041b CF |
127 | get_proc_lock (DWORD what, DWORD val) |
128 | { | |
b79b15e9 CF |
129 | if (!cygwin_finished_initializing) |
130 | return true; | |
243a041b CF |
131 | Static int lastwhat = -1; |
132 | if (!sync_proc_subproc) | |
76832a5b | 133 | { |
26bb3098 | 134 | sigproc_printf ("sync_proc_subproc is NULL"); |
76832a5b CF |
135 | return false; |
136 | } | |
322c131f | 137 | if (sync_proc_subproc.acquire (WPSP)) |
243a041b CF |
138 | { |
139 | lastwhat = what; | |
2e008fb9 | 140 | return true; |
243a041b | 141 | } |
26bb3098 CF |
142 | system_printf ("Couldn't acquire %s for(%d,%d), last %d, %E", |
143 | sync_proc_subproc.name, what, val, lastwhat); | |
144 | return false; | |
243a041b CF |
145 | } |
146 | ||
2e008fb9 | 147 | static bool __stdcall |
84c7d409 | 148 | proc_can_be_signalled (_pinfo *p) |
1fd5e000 | 149 | { |
67483cb2 | 150 | if (!(p->exitcode & EXITCODE_SET)) |
1ed95be6 | 151 | { |
8232f2e0 CF |
152 | if (ISSTATE (p, PID_INITIALIZING) || |
153 | (((p)->process_state & (PID_ACTIVE | PID_IN_USE)) == | |
154 | (PID_ACTIVE | PID_IN_USE))) | |
155 | return true; | |
156 | } | |
1ed95be6 CF |
157 | |
158 | set_errno (ESRCH); | |
159 | return false; | |
1fd5e000 CF |
160 | } |
161 | ||
2e008fb9 | 162 | bool __stdcall |
488c7683 | 163 | pid_exists (pid_t pid) |
84c7d409 | 164 | { |
1a9a235a | 165 | return pinfo (pid)->exists (); |
84c7d409 CF |
166 | } |
167 | ||
54dd79bb CF |
168 | /* Return true if this is one of our children, false otherwise. */ |
169 | static inline bool __stdcall | |
0ef78625 CF |
170 | mychild (int pid) |
171 | { | |
54dd79bb CF |
172 | for (int i = 0; i < nprocs; i++) |
173 | if (procs[i]->pid == pid) | |
174 | return true; | |
175 | return false; | |
0ef78625 CF |
176 | } |
177 | ||
1fd5e000 CF |
178 | /* Handle all subprocess requests |
179 | */ | |
1fd5e000 CF |
180 | int __stdcall |
181 | proc_subproc (DWORD what, DWORD val) | |
182 | { | |
183 | int rc = 1; | |
184 | int potential_match; | |
84c7d409 | 185 | _pinfo *child; |
9aa07a8f | 186 | int clearing; |
1fd5e000 CF |
187 | waitq *w; |
188 | ||
189 | #define wval ((waitq *) val) | |
54dd79bb | 190 | #define vchild (*((pinfo *) val)) |
1fd5e000 | 191 | |
a5a965ff | 192 | sigproc_printf ("args: %x, %d", what, val); |
1fd5e000 CF |
193 | |
194 | if (!get_proc_lock (what, val)) // Serialize access to this function | |
195 | { | |
76832a5b | 196 | system_printf ("couldn't get proc lock. what %d, val %d", what, val); |
1fd5e000 CF |
197 | goto out1; |
198 | } | |
199 | ||
200 | switch (what) | |
201 | { | |
202 | /* Add a new subprocess to the children arrays. | |
203 | * (usually called from the main thread) | |
204 | */ | |
205 | case PROC_ADDCHILD: | |
8cb359d9 CF |
206 | /* Filled up process table? */ |
207 | if (nprocs >= NPROCS) | |
cde0c2fb | 208 | { |
8cb359d9 CF |
209 | sigproc_printf ("proc table overflow: hit %d processes, pid %d\n", |
210 | nprocs, vchild->pid); | |
cde0c2fb | 211 | rc = 0; |
54dd79bb | 212 | set_errno (EAGAIN); |
cde0c2fb CF |
213 | break; |
214 | } | |
4ee52924 | 215 | /* fall through intentionally */ |
8cb359d9 | 216 | |
4ee52924 | 217 | case PROC_DETACHED_CHILD: |
54dd79bb CF |
218 | if (vchild != myself) |
219 | { | |
6e3c97b1 | 220 | vchild->ppid = what == PROC_DETACHED_CHILD ? 1 : myself->pid; |
54dd79bb CF |
221 | vchild->uid = myself->uid; |
222 | vchild->gid = myself->gid; | |
223 | vchild->pgid = myself->pgid; | |
224 | vchild->sid = myself->sid; | |
225 | vchild->ctty = myself->ctty; | |
226 | vchild->cygstarted = true; | |
c75b5b2d | 227 | vchild->process_state |= PID_INITIALIZING; |
54dd79bb | 228 | } |
4ee52924 CF |
229 | if (what == PROC_DETACHED_CHILD) |
230 | break; | |
b79b15e9 CF |
231 | /* fall through intentionally */ |
232 | ||
233 | case PROC_REATTACH_CHILD: | |
8cb359d9 CF |
234 | procs[nprocs] = vchild; |
235 | rc = procs[nprocs].wait (); | |
236 | if (rc) | |
3ecfcf57 | 237 | { |
8cb359d9 CF |
238 | sigproc_printf ("added pid %d to proc table, slot %d", vchild->pid, |
239 | nprocs); | |
240 | nprocs++; | |
3ecfcf57 | 241 | } |
9aa07a8f | 242 | break; |
f02f1f14 | 243 | |
164a681c CF |
244 | /* Handle a wait4() operation. Allocates an event for the calling |
245 | * thread which is signaled when the appropriate pid exits or stops. | |
246 | * (usually called from the main thread) | |
247 | */ | |
248 | case PROC_WAIT: | |
249 | wval->ev = NULL; // Don't know event flag yet | |
250 | ||
c6cb7f8f | 251 | if (wval->pid == -1 || !wval->pid) |
164a681c CF |
252 | child = NULL; // Not looking for a specific pid |
253 | else if (!mychild (wval->pid)) | |
254 | goto out; // invalid pid. flag no such child | |
255 | ||
256 | wval->status = 0; // Don't know status yet | |
257 | sigproc_printf ("wval->pid %d, wval->options %d", wval->pid, wval->options); | |
258 | ||
259 | /* If the first time for this thread, create a new event, otherwise | |
260 | * reset the event. | |
261 | */ | |
262 | if ((wval->ev = wval->thread_ev) == NULL) | |
263 | { | |
8cb359d9 CF |
264 | wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE, FALSE, |
265 | NULL); | |
f8a8e7a1 | 266 | ProtectHandle1 (wval->ev, wq_ev); |
164a681c CF |
267 | } |
268 | ||
269 | ResetEvent (wval->ev); | |
270 | w = waitq_head.next; | |
271 | waitq_head.next = wval; /* Add at the beginning. */ | |
272 | wval->next = w; /* Link in rest of the list. */ | |
56a19715 | 273 | clearing = false; |
164a681c CF |
274 | goto scan_wait; |
275 | ||
56a19715 CF |
276 | case PROC_EXEC_CLEANUP: |
277 | while (nprocs) | |
278 | remove_proc (0); | |
279 | for (w = &waitq_head; w->next != NULL; w = w->next) | |
280 | CloseHandle (w->next->ev); | |
281 | break; | |
282 | ||
f02f1f14 | 283 | /* Clear all waiting threads. Called from exceptions.cc prior to |
0670609d CF |
284 | the main thread's dispatch to a signal handler function. |
285 | (called from wait_sig thread) */ | |
f02f1f14 CF |
286 | case PROC_CLEARWAIT: |
287 | /* Clear all "wait"ing threads. */ | |
d3bda1df | 288 | if (val) |
a5a965ff | 289 | sigproc_printf ("clear waiting threads"); |
d3bda1df | 290 | else |
6a53b213 | 291 | sigproc_printf ("looking for processes to reap, nprocs %d", nprocs); |
9aa07a8f | 292 | clearing = val; |
f02f1f14 | 293 | |
1fd5e000 CF |
294 | scan_wait: |
295 | /* Scan the linked list of wait()ing threads. If a wait's parameters | |
e3778517 | 296 | match this pid, then activate it. */ |
1fd5e000 CF |
297 | for (w = &waitq_head; w->next != NULL; w = w->next) |
298 | { | |
299 | if ((potential_match = checkstate (w)) > 0) | |
a5a965ff | 300 | sigproc_printf ("released waiting thread"); |
164a681c | 301 | else if (!clearing && !(w->next->options & WNOHANG) && potential_match < 0) |
a5a965ff | 302 | sigproc_printf ("only found non-terminated children"); |
f02f1f14 | 303 | else if (potential_match <= 0) // nothing matched |
1fd5e000 | 304 | { |
a5a965ff | 305 | sigproc_printf ("waiting thread found no children"); |
1fd5e000 | 306 | HANDLE oldw = w->next->ev; |
164a681c | 307 | w->next->pid = 0; |
f02f1f14 CF |
308 | if (clearing) |
309 | w->next->status = -1; /* flag that a signal was received */ | |
06571ff6 | 310 | else if (!potential_match || !(w->next->options & WNOHANG)) |
71625490 | 311 | w->next->ev = NULL; |
1fd5e000 CF |
312 | if (!SetEvent (oldw)) |
313 | system_printf ("couldn't wake up wait event %p, %E", oldw); | |
314 | w->next = w->next->next; | |
315 | } | |
316 | if (w->next == NULL) | |
317 | break; | |
318 | } | |
319 | ||
f02f1f14 | 320 | if (!clearing) |
a5a965ff | 321 | sigproc_printf ("finished processing terminated/stopped child"); |
f02f1f14 | 322 | else |
1fd5e000 | 323 | { |
f02f1f14 | 324 | waitq_head.next = NULL; |
a5a965ff | 325 | sigproc_printf ("finished clearing"); |
1fd5e000 | 326 | } |
98f56d64 CF |
327 | |
328 | if (global_sigs[SIGCHLD].sa_handler == (void *) SIG_IGN) | |
8cb359d9 CF |
329 | for (int i = 0; i < nprocs; i += remove_proc (i)) |
330 | continue; | |
1fd5e000 CF |
331 | } |
332 | ||
333 | out: | |
322c131f | 334 | sync_proc_subproc.release (); // Release the lock |
1fd5e000 | 335 | out1: |
a5a965ff | 336 | sigproc_printf ("returning %d", rc); |
1fd5e000 | 337 | return rc; |
54dd79bb CF |
338 | #undef wval |
339 | #undef vchild | |
1fd5e000 CF |
340 | } |
341 | ||
f8a8e7a1 CF |
342 | // FIXME: This is inelegant |
343 | void | |
168d7785 | 344 | _cygtls::remove_wq (DWORD wait) |
f8a8e7a1 | 345 | { |
5025bf33 | 346 | if (exit_state < ES_FINAL && waitq_head.next && sync_proc_subproc |
2c8fd406 | 347 | && sync_proc_subproc.acquire (wait)) |
168d7785 CF |
348 | { |
349 | for (waitq *w = &waitq_head; w->next != NULL; w = w->next) | |
350 | if (w->next == &wq) | |
351 | { | |
352 | ForceCloseHandle1 (wq.thread_ev, wq_ev); | |
353 | w->next = wq.next; | |
354 | break; | |
355 | } | |
322c131f | 356 | sync_proc_subproc.release (); |
168d7785 | 357 | } |
f8a8e7a1 CF |
358 | } |
359 | ||
08d944e1 CF |
360 | inline void |
361 | close_my_readsig () | |
362 | { | |
363 | HANDLE h; | |
364 | if ((h = InterlockedExchangePointer (&my_readsig, NULL))) | |
365 | ForceCloseHandle1 (h, my_readsig); | |
366 | } | |
367 | ||
4ab568c6 CF |
368 | /* Cover function to `do_exit' to handle exiting even in presence of more |
369 | exceptions. We used to call exit, but a SIGSEGV shouldn't cause atexit | |
370 | routines to run. */ | |
371 | void | |
372 | _cygtls::signal_exit (int rc) | |
373 | { | |
e35f1d16 | 374 | HANDLE myss = my_sendsig; |
4ab568c6 | 375 | my_sendsig = NULL; /* Make no_signals_allowed return true */ |
8f937028 | 376 | |
e35f1d16 CF |
377 | /* This code used to try to always close my_readsig but it ended up |
378 | blocking for reasons that people in google think make sense. | |
379 | It's possible that it was blocking because ReadFile was still active | |
380 | but it isn't clear why this only caused random hangs rather than | |
381 | consistent hangs. So, for now at least, avoid closing my_readsig | |
382 | unless this is the signal thread. */ | |
383 | if (&_my_tls == _sig_tls) | |
384 | close_my_readsig (); /* Stop any currently executing sig_sends */ | |
385 | else | |
386 | { | |
387 | sigpacket sp = {}; | |
388 | sp.si.si_signo = __SIGEXIT; | |
389 | DWORD len; | |
390 | /* Write a packet to the wait_sig thread which tells it to exit and | |
391 | close my_readsig. */ | |
392 | WriteFile (myss, &sp, sizeof (sp), &len, NULL); | |
393 | } | |
c1dedea6 | 394 | signal_debugger (rc & 0x7f); |
4ab568c6 CF |
395 | |
396 | if (rc == SIGQUIT || rc == SIGABRT) | |
397 | { | |
398 | CONTEXT c; | |
399 | c.ContextFlags = CONTEXT_FULL; | |
400 | GetThreadContext (hMainThread, &c); | |
401 | copy_context (&c); | |
402 | if (cygheap->rlim_core > 0UL) | |
403 | rc |= 0x80; | |
404 | } | |
405 | ||
406 | if (have_execed) | |
407 | { | |
408 | sigproc_printf ("terminating captive process"); | |
409 | TerminateProcess (ch_spawn, sigExeced = rc); | |
410 | } | |
411 | ||
4ab568c6 | 412 | if ((rc & 0x80) && !try_to_debug ()) |
e52a43f1 | 413 | stackdump (thread_context.ebp, true); |
4ab568c6 CF |
414 | |
415 | lock_process until_exit (true); | |
416 | if (have_execed || exit_state > ES_PROCESS_LOCKED) | |
417 | myself.exit (rc); | |
418 | ||
419 | /* Starve other threads in a vain attempt to stop them from doing something | |
420 | stupid. */ | |
421 | SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL); | |
422 | ||
423 | sigproc_printf ("about to call do_exit (%x)", rc); | |
424 | do_exit (rc); | |
425 | } | |
426 | ||
1fd5e000 | 427 | /* Terminate the wait_subproc thread. |
f6f3b1ee CF |
428 | Called on process exit. |
429 | Also called by spawn_guts to disassociate any subprocesses from this | |
430 | process. Subprocesses will then know to clean up after themselves and | |
431 | will not become procs. */ | |
1fd5e000 | 432 | void __stdcall |
a611ae50 | 433 | proc_terminate () |
1fd5e000 | 434 | { |
8cb359d9 | 435 | sigproc_printf ("nprocs %d", nprocs); |
8cb359d9 | 436 | if (nprocs) |
1fd5e000 | 437 | { |
322c131f | 438 | sync_proc_subproc.acquire (WPSP); |
1fd5e000 | 439 | |
0c55f6ed | 440 | proc_subproc (PROC_CLEARWAIT, 1); |
1fd5e000 | 441 | |
8cb359d9 | 442 | /* Clean out proc processes from the pid list. */ |
56a19715 | 443 | for (int i = 0; i < nprocs; i++) |
1fd5e000 | 444 | { |
b79c0094 CF |
445 | /* If we've execed then the execed process will handle setting ppid |
446 | to 1 iff it is a Cygwin process. */ | |
447 | if (!have_execed || !have_execed_cygwin) | |
448 | procs[i]->ppid = 1; | |
f181da27 | 449 | if (procs[i].wait_thread) |
56a19715 | 450 | procs[i].wait_thread->terminate_thread (); |
b79c0094 CF |
451 | /* Release memory associated with this process unless it is 'myself'. |
452 | 'myself' is only in the procs table when we've execed. We reach | |
453 | here when the next process has finished initializing but we still | |
454 | can't free the memory used by 'myself' since it is used later on | |
455 | during cygwin tear down. */ | |
cf22fb91 CF |
456 | if (procs[i] != myself) |
457 | procs[i].release (); | |
1fd5e000 | 458 | } |
8cb359d9 | 459 | nprocs = 0; |
322c131f | 460 | sync_proc_subproc.release (); |
1fd5e000 | 461 | } |
a5a965ff | 462 | sigproc_printf ("leaving"); |
1fd5e000 CF |
463 | } |
464 | ||
7ac61736 | 465 | /* Clear pending signal */ |
1fd5e000 | 466 | void __stdcall |
7ac61736 | 467 | sig_clear (int target_sig) |
1fd5e000 | 468 | { |
a611ae50 | 469 | if (&_my_tls != _sig_tls) |
7ac61736 CF |
470 | sig_send (myself, -target_sig); |
471 | else | |
472 | { | |
f6936c48 | 473 | sigpacket *q; |
ca713cfa CF |
474 | sigpacket *save = sigq.save (); |
475 | sigq.reset (); | |
476 | while ((q = sigq.next ())) | |
f6936c48 | 477 | if (q->si.si_signo == target_sig) |
7ac61736 | 478 | { |
bcb4223c | 479 | q->si.si_signo = __SIGDELETE; |
7ac61736 CF |
480 | break; |
481 | } | |
ca713cfa | 482 | sigq.restore (save); |
7ac61736 | 483 | } |
1fd5e000 CF |
484 | } |
485 | ||
06bb4899 | 486 | extern "C" int |
7ac61736 | 487 | sigpending (sigset_t *mask) |
06bb4899 | 488 | { |
7ac61736 CF |
489 | sigset_t outset = (sigset_t) sig_send (myself, __SIGPENDING); |
490 | if (outset == SIG_BAD_MASK) | |
491 | return -1; | |
492 | *mask = outset; | |
06bb4899 CF |
493 | return 0; |
494 | } | |
495 | ||
7ac61736 | 496 | /* Force the wait_sig thread to wake up and scan for pending signals */ |
9e1ad59d CF |
497 | void __stdcall |
498 | sig_dispatch_pending (bool fast) | |
1fd5e000 | 499 | { |
ad37df48 | 500 | if (exit_state || &_my_tls == _sig_tls) |
29d52c8a CF |
501 | { |
502 | #ifdef DEBUGGING | |
a611ae50 CF |
503 | sigproc_printf ("exit_state %d, cur thread id %p, _sig_tls %p, sigq.start.next %p", |
504 | exit_state, GetCurrentThreadId (), _sig_tls, sigq.start.next); | |
29d52c8a | 505 | #endif |
9e1ad59d | 506 | return; |
29d52c8a | 507 | } |
a0d3c309 | 508 | |
dc3dc498 CF |
509 | /* Non-atomically test for any signals pending and wake up wait_sig if any are |
510 | found. It's ok if there's a race here since the next call to this function | |
511 | should catch it. | |
512 | FIXME: Eventually, wait_sig should wake up on its own to deal with pending | |
513 | signals. */ | |
514 | if (sigq.pending ()) | |
515 | sig_send (myself, fast ? __SIGFLUSHFAST : __SIGFLUSH); | |
1fd5e000 CF |
516 | } |
517 | ||
05726ddd | 518 | /* Signal thread initialization. Called from dll_crt0_1. |
b9874a0c | 519 | This routine starts the signal handling thread. */ |
1fd5e000 CF |
520 | void __stdcall |
521 | sigproc_init () | |
522 | { | |
b9874a0c | 523 | char char_sa_buf[1024]; |
9f65451e CF |
524 | PSECURITY_ATTRIBUTES sa = sec_user_nih ((PSECURITY_ATTRIBUTES) char_sa_buf, cygheap->user.sid()); |
525 | DWORD err = fhandler_pipe::create (sa, &my_readsig, &my_sendsig, | |
28c8ae66 CF |
526 | sizeof (sigpacket), "sigwait", |
527 | PIPE_ADD_PID); | |
9f65451e CF |
528 | if (err) |
529 | { | |
530 | SetLastError (err); | |
b9874a0c | 531 | api_fatal ("couldn't create signal pipe, %E"); |
9f65451e | 532 | } |
b9874a0c CF |
533 | ProtectHandle (my_readsig); |
534 | myself->sendsig = my_sendsig; | |
6a7d80f2 | 535 | /* sync_proc_subproc is used by proc_subproc. It serializes |
bbca1e4c | 536 | access to the children and proc arrays. */ |
322c131f | 537 | sync_proc_subproc.init ("sync_proc_subproc"); |
56a19715 | 538 | new cygthread (wait_sig, cygself, "sig"); |
1fd5e000 CF |
539 | } |
540 | ||
541 | /* Called on process termination to terminate signal and process threads. | |
542 | */ | |
543 | void __stdcall | |
a611ae50 | 544 | sigproc_terminate (exit_states es) |
1fd5e000 | 545 | { |
a611ae50 CF |
546 | exit_states prior_exit_state = exit_state; |
547 | exit_state = es; | |
f8af64be CF |
548 | if (!cygwin_finished_initializing) |
549 | sigproc_printf ("don't worry about signal thread"); | |
550 | else if (prior_exit_state >= ES_FINAL) | |
67483cb2 | 551 | sigproc_printf ("already performed"); |
5ec14fe4 CF |
552 | else |
553 | { | |
554 | sigproc_printf ("entering"); | |
6f96c536 | 555 | sig_send (myself_nowait, __SIGEXIT); |
67483cb2 | 556 | proc_terminate (); // clean up process stuff |
1fd5e000 | 557 | } |
1fd5e000 CF |
558 | } |
559 | ||
f6936c48 CF |
560 | int __stdcall |
561 | sig_send (_pinfo *p, int sig) | |
562 | { | |
ad37df48 CF |
563 | if (sig == __SIGHOLD) |
564 | sigheld = true; | |
565 | else if (!sigheld) | |
566 | /* nothing */; | |
51f90b2f CF |
567 | else if (sig == __SIGFLUSH || sig == __SIGFLUSHFAST) |
568 | return 0; | |
f02400f7 | 569 | else if (sig == __SIGNOHOLD || sig == __SIGEXIT) |
ad37df48 CF |
570 | { |
571 | SetEvent (sigCONT); | |
572 | sigheld = false; | |
573 | } | |
3b69aaa9 | 574 | else if (&_my_tls == _main_tls) |
bbca1e4c CF |
575 | { |
576 | #ifdef DEBUGGING | |
a9396868 | 577 | system_printf ("signal %d sent to %p while signals are on hold", sig, p); |
bbca1e4c CF |
578 | #endif |
579 | return -1; | |
580 | } | |
985d0e68 | 581 | siginfo_t si = {0}; |
f6936c48 CF |
582 | si.si_signo = sig; |
583 | si.si_code = SI_KERNEL; | |
584 | si.si_pid = si.si_uid = si.si_errno = 0; | |
585 | return sig_send (p, si); | |
586 | } | |
587 | ||
1fd5e000 | 588 | /* Send a signal to another process by raising its signal semaphore. |
f6936c48 CF |
589 | If pinfo *p == NULL, send to the current process. |
590 | If sending to this process, wait for notification that a signal has | |
591 | completed before returning. */ | |
1fd5e000 | 592 | int __stdcall |
e431827c | 593 | sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) |
1fd5e000 CF |
594 | { |
595 | int rc = 1; | |
2e008fb9 | 596 | bool its_me; |
7ac61736 | 597 | HANDLE sendsig; |
7759daa9 | 598 | sigpacket pack; |
0730fa07 | 599 | bool communing = si.si_signo == __SIGCOMMUNE; |
1fd5e000 | 600 | |
39d06d71 | 601 | pack.wakeup = NULL; |
9a4d574b | 602 | bool wait_for_completion; |
56a19715 | 603 | if (!(its_me = (!have_execed && (p == NULL || p == myself || p == myself_nowait)))) |
67483cb2 CF |
604 | { |
605 | /* It is possible that the process is not yet ready to receive messages | |
606 | * or that it has exited. Detect this. | |
607 | */ | |
608 | if (!proc_can_be_signalled (p)) /* Is the process accepting messages? */ | |
609 | { | |
610 | sigproc_printf ("invalid pid %d(%x), signal %d", | |
611 | p->pid, p->process_state, si.si_signo); | |
612 | goto out; | |
613 | } | |
614 | wait_for_completion = false; | |
615 | } | |
1fd5e000 CF |
616 | else |
617 | { | |
c529909f | 618 | if (no_signals_available (si.si_signo != __SIGEXIT)) |
d795119c | 619 | { |
2380dfe1 | 620 | set_errno (EAGAIN); |
d795119c CF |
621 | goto out; // Either exiting or not yet initializing |
622 | } | |
5e477e9a | 623 | wait_for_completion = p != myself_nowait && _my_tls.isinitialized () && !exit_state; |
1fd5e000 CF |
624 | p = myself; |
625 | } | |
626 | ||
1fd5e000 | 627 | |
1fd5e000 | 628 | if (its_me) |
67483cb2 | 629 | sendsig = my_sendsig; |
7ac61736 | 630 | else |
99a8fab5 | 631 | { |
54dd79bb CF |
632 | HANDLE dupsig; |
633 | DWORD dwProcessId; | |
634 | for (int i = 0; !p->sendsig && i < 10000; i++) | |
084ea510 | 635 | yield (); |
54dd79bb CF |
636 | if (p->sendsig) |
637 | { | |
638 | dupsig = p->sendsig; | |
639 | dwProcessId = p->dwProcessId; | |
640 | } | |
641 | else | |
642 | { | |
643 | dupsig = p->exec_sendsig; | |
644 | dwProcessId = p->exec_dwProcessId; | |
645 | } | |
646 | if (!dupsig) | |
647 | { | |
648 | set_errno (EAGAIN); | |
649 | sigproc_printf ("sendsig handle never materialized"); | |
650 | goto out; | |
651 | } | |
dcb091ca | 652 | HANDLE hp = OpenProcess (PROCESS_DUP_HANDLE, false, dwProcessId); |
7ac61736 | 653 | if (!hp) |
deb648cc | 654 | { |
7ac61736 | 655 | __seterrno (); |
2380dfe1 | 656 | sigproc_printf ("OpenProcess failed, %E"); |
7ac61736 CF |
657 | goto out; |
658 | } | |
f7239090 | 659 | VerifyHandle (hp); |
b79b15e9 CF |
660 | if (!DuplicateHandle (hp, dupsig, GetCurrentProcess (), &sendsig, 0, |
661 | false, DUPLICATE_SAME_ACCESS) || !sendsig) | |
7ac61736 CF |
662 | { |
663 | __seterrno (); | |
54dd79bb CF |
664 | sigproc_printf ("DuplicateHandle failed, %E"); |
665 | CloseHandle (hp); | |
deb648cc CF |
666 | goto out; |
667 | } | |
f7239090 | 668 | VerifyHandle (sendsig); |
0730fa07 CF |
669 | if (!communing) |
670 | CloseHandle (hp); | |
671 | else | |
672 | { | |
673 | si._si_commune._si_process_handle = hp; | |
674 | ||
675 | HANDLE& tome = si._si_commune._si_write_handle; | |
676 | HANDLE& fromthem = si._si_commune._si_read_handle; | |
f8b8b1be | 677 | if (!CreatePipeOverlapped (&fromthem, &tome, &sec_all_nih)) |
0730fa07 CF |
678 | { |
679 | sigproc_printf ("CreatePipe for __SIGCOMMUNE failed, %E"); | |
680 | __seterrno (); | |
681 | goto out; | |
682 | } | |
b79b15e9 | 683 | if (!DuplicateHandle (GetCurrentProcess (), tome, hp, &tome, 0, false, |
0730fa07 CF |
684 | DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) |
685 | { | |
686 | sigproc_printf ("DuplicateHandle for __SIGCOMMUNE failed, %E"); | |
687 | __seterrno (); | |
688 | goto out; | |
689 | } | |
690 | } | |
99a8fab5 | 691 | } |
1fd5e000 | 692 | |
d795119c CF |
693 | sigproc_printf ("sendsig %p, pid %d, signal %d, its_me %d", sendsig, p->pid, si.si_signo, its_me); |
694 | ||
7759daa9 CF |
695 | sigset_t pending; |
696 | if (!its_me) | |
697 | pack.mask = NULL; | |
f6936c48 | 698 | else if (si.si_signo == __SIGPENDING) |
7759daa9 | 699 | pack.mask = &pending; |
f6936c48 | 700 | else if (si.si_signo == __SIGFLUSH || si.si_signo > 0) |
9feffba7 | 701 | pack.mask = tls ? &tls->sigmask : &_main_tls->sigmask; |
7759daa9 CF |
702 | else |
703 | pack.mask = NULL; | |
704 | ||
f6936c48 CF |
705 | pack.si = si; |
706 | if (!pack.si.si_pid) | |
707 | pack.si.si_pid = myself->pid; | |
708 | if (!pack.si.si_uid) | |
709 | pack.si.si_uid = myself->uid; | |
7759daa9 | 710 | pack.pid = myself->pid; |
9feffba7 | 711 | pack.tls = tls; |
5e477e9a | 712 | if (wait_for_completion) |
39d06d71 CF |
713 | { |
714 | pack.wakeup = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); | |
715 | sigproc_printf ("wakeup %p", pack.wakeup); | |
716 | ProtectHandle (pack.wakeup); | |
717 | } | |
718 | ||
0730fa07 CF |
719 | char *leader; |
720 | size_t packsize; | |
721 | if (!communing || !(si._si_commune._si_code & PICOM_EXTRASTR)) | |
722 | { | |
723 | leader = (char *) &pack; | |
724 | packsize = sizeof (pack); | |
725 | } | |
726 | else | |
727 | { | |
728 | size_t n = strlen (si._si_commune._si_str); | |
4aedb287 CF |
729 | char *p = leader = (char *) alloca (sizeof (pack) + sizeof (n) + n); |
730 | memcpy (p, &pack, sizeof (pack)); p += sizeof (pack); | |
731 | memcpy (p, &n, sizeof (n)); p += sizeof (n); | |
732 | memcpy (p, si._si_commune._si_str, n); p += n; | |
0730fa07 CF |
733 | packsize = p - leader; |
734 | } | |
735 | ||
7ac61736 | 736 | DWORD nb; |
0730fa07 | 737 | if (!WriteFile (sendsig, leader, packsize, &nb, NULL) || nb != packsize) |
1fd5e000 | 738 | { |
7759daa9 | 739 | /* Couldn't send to the pipe. This probably means that the |
e3778517 | 740 | process is exiting. */ |
1fd5e000 | 741 | if (!its_me) |
7ac61736 | 742 | { |
2380dfe1 | 743 | sigproc_printf ("WriteFile for pipe %p failed, %E", sendsig); |
7ac61736 CF |
744 | ForceCloseHandle (sendsig); |
745 | } | |
1fd5e000 CF |
746 | else |
747 | { | |
c529909f | 748 | if (no_signals_available (true)) |
a5a965ff | 749 | sigproc_printf ("I'm going away now"); |
fdd857a1 | 750 | else if (!p->exec_sendsig) |
7ac61736 | 751 | system_printf ("error sending signal %d to pid %d, pipe handle %p, %E", |
fdd857a1 | 752 | si.si_signo, p->pid, sendsig); |
1fd5e000 | 753 | } |
4ab568c6 CF |
754 | if (GetLastError () == ERROR_BROKEN_PIPE) |
755 | set_errno (ESRCH); | |
756 | else | |
757 | __seterrno (); | |
1fd5e000 CF |
758 | goto out; |
759 | } | |
760 | ||
7ac61736 | 761 | |
7759daa9 CF |
762 | /* No need to wait for signal completion unless this was a signal to |
763 | this process. | |
764 | ||
765 | If it was a signal to this process, wait for a dispatched signal. | |
766 | Otherwise just wait for the wait_sig to signal that it has finished | |
767 | processing the signal. */ | |
768 | if (wait_for_completion) | |
7ac61736 | 769 | { |
7759daa9 CF |
770 | sigproc_printf ("Waiting for pack.wakeup %p", pack.wakeup); |
771 | rc = WaitForSingleObject (pack.wakeup, WSSC); | |
255e7e55 | 772 | ForceCloseHandle (pack.wakeup); |
7ac61736 | 773 | } |
7759daa9 | 774 | else |
1fd5e000 | 775 | { |
68997e88 | 776 | rc = WAIT_OBJECT_0; |
f6936c48 CF |
777 | sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", |
778 | its_me, si.si_signo); | |
68997e88 | 779 | if (!its_me) |
7ac61736 | 780 | ForceCloseHandle (sendsig); |
1fd5e000 | 781 | } |
1fd5e000 | 782 | |
255e7e55 | 783 | pack.wakeup = NULL; |
1fd5e000 CF |
784 | if (rc == WAIT_OBJECT_0) |
785 | rc = 0; // Successful exit | |
786 | else | |
787 | { | |
882dfbf7 | 788 | if (!no_signals_available (true)) |
f6111483 | 789 | system_printf ("wait for sig_complete event failed, signal %d, rc %d, %E", |
f6936c48 | 790 | si.si_signo, rc); |
1fd5e000 CF |
791 | set_errno (ENOSYS); |
792 | rc = -1; | |
793 | } | |
794 | ||
9e1ad59d | 795 | if (wait_for_completion && si.si_signo != __SIGFLUSHFAST) |
e431827c | 796 | _my_tls.call_signal_handler (); |
0730fa07 | 797 | goto out; |
0670609d | 798 | |
1fd5e000 | 799 | out: |
0730fa07 CF |
800 | if (communing && rc) |
801 | { | |
802 | if (si._si_commune._si_process_handle) | |
803 | CloseHandle (si._si_commune._si_process_handle); | |
804 | if (si._si_commune._si_read_handle) | |
805 | CloseHandle (si._si_commune._si_read_handle); | |
806 | } | |
39d06d71 CF |
807 | if (pack.wakeup) |
808 | ForceCloseHandle (pack.wakeup); | |
f6936c48 | 809 | if (si.si_signo != __SIGPENDING) |
7ac61736 CF |
810 | /* nothing */; |
811 | else if (!rc) | |
812 | rc = (int) pending; | |
813 | else | |
814 | rc = SIG_BAD_MASK; | |
f6936c48 | 815 | sigproc_printf ("returning %p from sending signal %d", rc, si.si_signo); |
1fd5e000 CF |
816 | return rc; |
817 | } | |
818 | ||
c9241c26 | 819 | int child_info::retry_count = 0; |
56a19715 | 820 | |
1fd5e000 CF |
821 | /* Initialize some of the memory block passed to child processes |
822 | by fork/spawn/exec. */ | |
56a19715 | 823 | child_info::child_info (unsigned in_cb, child_info_types chtype, |
5f38ec46 CF |
824 | bool need_subproc_ready): |
825 | cb (in_cb), intro (PROC_MAGIC_GENERIC), magic (CHILD_INFO_MAGIC), | |
826 | type (chtype), cygheap (::cygheap), cygheap_max (::cygheap_max), | |
1fb6667f CF |
827 | flag (0), retry (child_info::retry_count), rd_proc_pipe (NULL), |
828 | wr_proc_pipe (NULL) | |
1fd5e000 | 829 | { |
7dfad3a0 CF |
830 | /* It appears that when running under WOW64 on Vista 64, the first DWORD |
831 | value in the datastructure lpReserved2 is pointing to (msv_count in | |
832 | Cygwin), has to reflect the size of that datastructure as used in the | |
833 | Microsoft C runtime (a count value, counting the number of elements in | |
834 | two subsequent arrays, BYTE[count and HANDLE[count]), even though the C | |
835 | runtime isn't used. Otherwise, if msv_count is 0 or too small, the | |
836 | datastructure gets overwritten. | |
837 | ||
838 | This seems to be a bug in Vista's WOW64, which apparently copies the | |
839 | lpReserved2 datastructure not using the cbReserved2 size information, | |
840 | but using the information given in the first DWORD within lpReserved2 | |
841 | instead. 32 bit Windows and former WOW64 don't care if msv_count is 0 | |
842 | or a sensible non-0 count value. However, it's not clear if a non-0 | |
843 | count doesn't result in trying to evaluate the content, so we do this | |
844 | really only for Vista 64 for now. | |
845 | ||
62d172bb CV |
846 | Note: It turns out that a non-zero value *does* harm operation on |
847 | XP 64 and 2K3 64 (Crash in CreateProcess call). | |
7dfad3a0 CF |
848 | |
849 | The value is sizeof (child_info_*) / 5 which results in a count which | |
850 | covers the full datastructure, plus not more than 4 extra bytes. This | |
851 | is ok as long as the child_info structure is cosily stored within a bigger | |
852 | datastructure. */ | |
62d172bb | 853 | msv_count = wincap.needs_count_in_si_lpres2 () ? in_cb / 5 : 0; |
c16548b2 | 854 | |
54dd79bb CF |
855 | fhandler_union_cb = sizeof (fhandler_union); |
856 | user_h = cygwin_user_h; | |
ef8bff85 | 857 | if (strace.active ()) |
76ef40d6 | 858 | flag |= _CI_STRACED; |
e8454a34 | 859 | if (need_subproc_ready) |
76ef40d6 CF |
860 | { |
861 | subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL); | |
862 | flag |= _CI_ISCYGWIN; | |
863 | } | |
54dd79bb | 864 | sigproc_printf ("subproc_ready %p", subproc_ready); |
ce95c640 CF |
865 | /* Create an inheritable handle to pass to the child process. This will |
866 | allow the child to duplicate handles from the parent to itself. */ | |
867 | parent = NULL; | |
f16706de | 868 | if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (), |
b79b15e9 | 869 | GetCurrentProcess (), &parent, 0, true, |
ce95c640 CF |
870 | DUPLICATE_SAME_ACCESS)) |
871 | system_printf ("couldn't create handle to myself for child, %E"); | |
54dd79bb CF |
872 | } |
873 | ||
874 | child_info::~child_info () | |
875 | { | |
1fb6667f | 876 | cleanup (); |
54dd79bb CF |
877 | } |
878 | ||
879 | child_info_fork::child_info_fork () : | |
1fb6667f CF |
880 | child_info (sizeof *this, _CH_FORK, true), |
881 | forker_finished (NULL) | |
54dd79bb CF |
882 | { |
883 | } | |
884 | ||
e8454a34 CF |
885 | child_info_spawn::child_info_spawn (child_info_types chtype, bool need_subproc_ready) : |
886 | child_info (sizeof *this, chtype, need_subproc_ready) | |
54dd79bb | 887 | { |
56a19715 CF |
888 | if (type == _CH_EXEC) |
889 | { | |
890 | hExeced = NULL; | |
1fb6667f | 891 | if (my_wr_proc_pipe) |
56a19715 CF |
892 | ev = NULL; |
893 | else if (!(ev = CreateEvent (&sec_none_nih, false, false, NULL))) | |
894 | api_fatal ("couldn't create signalling event for exec, %E"); | |
895 | ||
896 | get_proc_lock (PROC_EXECING, 0); | |
897 | lock = &sync_proc_subproc; | |
898 | /* exit with lock held */ | |
899 | } | |
900 | } | |
901 | ||
7b2740dd CF |
902 | cygheap_exec_info * |
903 | cygheap_exec_info::alloc () | |
904 | { | |
905 | return (cygheap_exec_info *) ccalloc_abort (HEAP_1_EXEC, 1, | |
906 | sizeof (cygheap_exec_info) | |
907 | + (nprocs * sizeof (children[0]))); | |
908 | } | |
909 | ||
6daf4afb CF |
910 | void |
911 | child_info_spawn::wait_for_myself () | |
912 | { | |
b7d95b5b | 913 | postfork (myself); |
6daf4afb CF |
914 | myself.remember (false); |
915 | WaitForSingleObject (ev, INFINITE); | |
916 | } | |
917 | ||
1fb6667f CF |
918 | void |
919 | child_info::cleanup () | |
920 | { | |
921 | if (subproc_ready) | |
922 | { | |
923 | CloseHandle (subproc_ready); | |
924 | subproc_ready = NULL; | |
925 | } | |
926 | if (parent) | |
927 | { | |
928 | CloseHandle (parent); | |
929 | parent = NULL; | |
930 | } | |
931 | if (rd_proc_pipe) | |
932 | { | |
933 | ForceCloseHandle (rd_proc_pipe); | |
934 | rd_proc_pipe = NULL; | |
935 | } | |
936 | if (wr_proc_pipe) | |
937 | { | |
938 | ForceCloseHandle (wr_proc_pipe); | |
939 | wr_proc_pipe = NULL; | |
940 | } | |
941 | } | |
942 | ||
56a19715 CF |
943 | void |
944 | child_info_spawn::cleanup () | |
945 | { | |
946 | if (moreinfo) | |
947 | { | |
948 | if (moreinfo->envp) | |
949 | { | |
950 | for (char **e = moreinfo->envp; *e; e++) | |
951 | cfree (*e); | |
952 | cfree (moreinfo->envp); | |
953 | } | |
954 | if (type != _CH_SPAWN && moreinfo->myself_pinfo) | |
955 | CloseHandle (moreinfo->myself_pinfo); | |
956 | cfree (moreinfo); | |
957 | } | |
958 | moreinfo = NULL; | |
56a19715 CF |
959 | if (ev) |
960 | { | |
961 | CloseHandle (ev); | |
962 | ev = NULL; | |
963 | } | |
56a19715 CF |
964 | if (type == _CH_EXEC) |
965 | { | |
966 | if (iscygwin () && hExeced) | |
56a19715 | 967 | proc_subproc (PROC_EXEC_CLEANUP, 0); |
56a19715 CF |
968 | sync_proc_subproc.release (); |
969 | } | |
970 | type = _CH_NADA; | |
1fb6667f | 971 | child_info::cleanup (); |
54dd79bb CF |
972 | } |
973 | ||
b79b15e9 CF |
974 | /* Record any non-reaped subprocesses to be passed to about-to-be-execed |
975 | process. FIXME: There is a race here if the process exits while we | |
976 | are recording it. */ | |
7b2740dd CF |
977 | inline void |
978 | cygheap_exec_info::record_children () | |
979 | { | |
980 | for (nchildren = 0; nchildren < nprocs; nchildren++) | |
981 | { | |
982 | children[nchildren].pid = procs[nchildren]->pid; | |
983 | children[nchildren].p = procs[nchildren]; | |
984 | } | |
985 | } | |
986 | ||
b79b15e9 CF |
987 | void |
988 | child_info_spawn::record_children () | |
989 | { | |
56a19715 | 990 | if (type == _CH_EXEC && iscygwin ()) |
7b2740dd | 991 | moreinfo->record_children (); |
b79b15e9 CF |
992 | } |
993 | ||
994 | /* Reattach non-reaped subprocesses passed in from the cygwin process | |
995 | which previously operated under this pid. FIXME: Is there a race here | |
996 | if the process exits during cygwin's exec handoff? */ | |
7b2740dd CF |
997 | inline void |
998 | cygheap_exec_info::reattach_children (HANDLE parent) | |
b79b15e9 CF |
999 | { |
1000 | for (int i = 0; i < nchildren; i++) | |
1001 | { | |
56a19715 | 1002 | pinfo p (parent, children[i].p, children[i].pid); |
277753c8 | 1003 | if (!p) |
56a19715 | 1004 | debug_only_printf ("couldn't reattach child %d from previous process", children[i].pid); |
26601df4 | 1005 | else if (!p.reattach ()) |
56a19715 CF |
1006 | debug_only_printf ("attach of child process %d failed", children[i].pid); |
1007 | else | |
1008 | debug_only_printf ("reattached pid %d<%u>, process handle %p, rd_proc_pipe %p->%p", | |
1009 | p->pid, p->dwProcessId, p.hProcess, | |
1010 | children[i].p.rd_proc_pipe, p.rd_proc_pipe); | |
b79b15e9 CF |
1011 | } |
1012 | } | |
1013 | ||
7b2740dd CF |
1014 | void |
1015 | child_info_spawn::reattach_children () | |
1016 | { | |
1017 | moreinfo->reattach_children (parent); | |
1018 | } | |
1019 | ||
54dd79bb CF |
1020 | void |
1021 | child_info::ready (bool execed) | |
1022 | { | |
1023 | if (!subproc_ready) | |
1024 | { | |
1025 | sigproc_printf ("subproc_ready not set"); | |
1026 | return; | |
1027 | } | |
1028 | ||
d3b593aa CF |
1029 | if (dynamically_loaded) |
1030 | sigproc_printf ("not really ready"); | |
1031 | else if (!SetEvent (subproc_ready)) | |
56a19715 | 1032 | api_fatal ("SetEvent failed, %E"); |
54dd79bb CF |
1033 | else |
1034 | sigproc_printf ("signalled %p that I was ready", subproc_ready); | |
1035 | ||
1036 | if (execed) | |
1037 | { | |
1038 | CloseHandle (subproc_ready); | |
1039 | subproc_ready = NULL; | |
1040 | } | |
1041 | } | |
1042 | ||
1043 | bool | |
267e201d | 1044 | child_info::sync (pid_t pid, HANDLE& hProcess, DWORD howlong) |
54dd79bb | 1045 | { |
267e201d | 1046 | bool res; |
0cdcb234 CF |
1047 | HANDLE w4[2]; |
1048 | unsigned n = 0; | |
1049 | unsigned nsubproc_ready; | |
1050 | ||
1051 | if (!subproc_ready) | |
1052 | nsubproc_ready = WAIT_OBJECT_0 + 3; | |
267e201d | 1053 | else |
54dd79bb | 1054 | { |
0cdcb234 CF |
1055 | w4[n++] = subproc_ready; |
1056 | nsubproc_ready = 0; | |
1057 | } | |
1058 | w4[n++] = hProcess; | |
54dd79bb | 1059 | |
0cdcb234 CF |
1060 | sigproc_printf ("n %d, waiting for subproc_ready(%p) and child process(%p)", n, w4[0], w4[1]); |
1061 | DWORD x = WaitForMultipleObjects (n, w4, FALSE, howlong); | |
1062 | x -= WAIT_OBJECT_0; | |
1063 | if (x >= n) | |
1064 | { | |
84d38174 | 1065 | system_printf ("wait failed, pid %u, %E", pid); |
0cdcb234 CF |
1066 | res = false; |
1067 | } | |
1068 | else | |
1069 | { | |
84d38174 | 1070 | if (x != nsubproc_ready) |
a9396868 CF |
1071 | { |
1072 | res = false; | |
1073 | GetExitCodeProcess (hProcess, &exit_code); | |
1074 | } | |
84d38174 | 1075 | else |
267e201d | 1076 | { |
a9396868 CF |
1077 | res = true; |
1078 | exit_code = STILL_ACTIVE; | |
1fb6667f | 1079 | if (type == _CH_EXEC && my_wr_proc_pipe) |
84d38174 CF |
1080 | { |
1081 | ForceCloseHandle1 (hProcess, childhProc); | |
1082 | hProcess = NULL; | |
1083 | } | |
267e201d | 1084 | } |
f4bb53c4 CF |
1085 | sigproc_printf ("pid %u, WFMO returned %d, exit_code %p, res %d", pid, x, |
1086 | exit_code, res); | |
54dd79bb CF |
1087 | } |
1088 | return res; | |
1fd5e000 CF |
1089 | } |
1090 | ||
a9396868 CF |
1091 | DWORD |
1092 | child_info::proc_retry (HANDLE h) | |
1093 | { | |
3b69aaa9 CF |
1094 | if (!exit_code) |
1095 | return EXITCODE_OK; | |
f4bb53c4 | 1096 | sigproc_printf ("exit_code %p", exit_code); |
a9396868 CF |
1097 | switch (exit_code) |
1098 | { | |
1099 | case STILL_ACTIVE: /* shouldn't happen */ | |
1100 | sigproc_printf ("STILL_ACTIVE? How'd we get here?"); | |
1101 | break; | |
93d606f6 | 1102 | case STATUS_DLL_NOT_FOUND: |
f4bb53c4 | 1103 | case STATUS_ACCESS_VIOLATION: |
f6ba9446 | 1104 | case STATUS_ILLEGAL_INSTRUCTION: |
dc4e4aab CW |
1105 | case STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION: /* pseudo-reloc.c specific */ |
1106 | return exit_code; | |
a9396868 | 1107 | case STATUS_CONTROL_C_EXIT: |
6813f009 CF |
1108 | if (saw_ctrl_c ()) |
1109 | return EXITCODE_OK; | |
1110 | /* fall through intentionally */ | |
a9396868 CF |
1111 | case STATUS_DLL_INIT_FAILED: |
1112 | case STATUS_DLL_INIT_FAILED_LOGOFF: | |
1113 | case EXITCODE_RETRY: | |
1114 | if (retry-- > 0) | |
1115 | exit_code = 0; | |
1116 | break; | |
85510878 CF |
1117 | case EXITCODE_FORK_FAILED: /* windows prevented us from forking */ |
1118 | break; | |
b86f999a | 1119 | |
a9396868 CF |
1120 | /* Count down non-recognized exit codes more quickly since they aren't |
1121 | due to known conditions. */ | |
1122 | default: | |
eb285e11 | 1123 | if (!iscygwin () && (exit_code & 0xffff0000) != 0xc0000000) |
a9396868 CF |
1124 | break; |
1125 | if ((retry -= 2) < 0) | |
1126 | retry = 0; | |
1127 | else | |
1128 | exit_code = 0; | |
1129 | } | |
1130 | if (!exit_code) | |
1131 | ForceCloseHandle1 (h, childhProc); | |
1132 | return exit_code; | |
1133 | } | |
1134 | ||
1135 | bool | |
44d2fc0a | 1136 | child_info_fork::abort (const char *fmt, ...) |
a9396868 | 1137 | { |
44d2fc0a CF |
1138 | if (fmt) |
1139 | { | |
1140 | va_list ap; | |
1141 | va_start (ap, fmt); | |
29649132 | 1142 | strace_vprintf (SYSTEM, fmt, ap); |
bb2b641c | 1143 | TerminateProcess (GetCurrentProcess (), EXITCODE_FORK_FAILED); |
44d2fc0a | 1144 | } |
a9396868 | 1145 | if (retry > 0) |
bb2b641c | 1146 | TerminateProcess (GetCurrentProcess (), EXITCODE_RETRY); |
44d2fc0a | 1147 | return false; |
a9396868 CF |
1148 | } |
1149 | ||
1fd5e000 CF |
1150 | /* Check the state of all of our children to see if any are stopped or |
1151 | * terminated. | |
1152 | */ | |
1153 | static int __stdcall | |
164a681c | 1154 | checkstate (waitq *parent_w) |
1fd5e000 | 1155 | { |
164a681c | 1156 | int potential_match = 0; |
1fd5e000 | 1157 | |
8cb359d9 | 1158 | sigproc_printf ("nprocs %d", nprocs); |
1fd5e000 CF |
1159 | |
1160 | /* Check already dead processes first to see if they match the criteria | |
8cb359d9 CF |
1161 | * given in w->next. */ |
1162 | int res; | |
1163 | for (int i = 0; i < nprocs; i++) | |
1164 | if ((res = stopped_or_terminated (parent_w, procs[i]))) | |
1fd5e000 | 1165 | { |
8cb359d9 | 1166 | remove_proc (i); |
1fd5e000 CF |
1167 | potential_match = 1; |
1168 | goto out; | |
1169 | } | |
1170 | ||
8cb359d9 CF |
1171 | sigproc_printf ("no matching terminated children found"); |
1172 | potential_match = -!!nprocs; | |
1fd5e000 CF |
1173 | |
1174 | out: | |
a5a965ff | 1175 | sigproc_printf ("returning %d", potential_match); |
1fd5e000 CF |
1176 | return potential_match; |
1177 | } | |
1178 | ||
8cb359d9 CF |
1179 | /* Remove a proc from procs by swapping it with the last child in the list. |
1180 | Also releases shared memory of exited processes. */ | |
1181 | static bool __stdcall | |
1182 | remove_proc (int ci) | |
1fd5e000 | 1183 | { |
56a19715 | 1184 | if (have_execed) |
480b13a3 CF |
1185 | { |
1186 | if (_my_tls._ctinfo != procs[ci].wait_thread) | |
1187 | procs[ci].wait_thread->terminate_thread (); | |
1188 | } | |
56a19715 | 1189 | else if (procs[ci]->exists ()) |
8cb359d9 | 1190 | return true; |
84c7d409 | 1191 | |
8cb359d9 CF |
1192 | sigproc_printf ("removing procs[%d], pid %d, nprocs %d", ci, procs[ci]->pid, |
1193 | nprocs); | |
1194 | if (procs[ci] != myself) | |
56a19715 | 1195 | procs[ci].release (); |
8cb359d9 | 1196 | if (ci < --nprocs) |
37d5841f CF |
1197 | { |
1198 | /* Wait for proc_waiter thread to make a copy of this element before | |
1199 | moving it or it may become confused. The chances are very high that | |
1200 | the proc_waiter thread has already done this by the time we | |
1201 | get here. */ | |
cc07096c | 1202 | if (!have_execed && !exit_state) |
15660c23 CF |
1203 | while (!procs[nprocs].waiter_ready) |
1204 | yield (); | |
37d5841f CF |
1205 | procs[ci] = procs[nprocs]; |
1206 | } | |
8cb359d9 | 1207 | return 0; |
1fd5e000 CF |
1208 | } |
1209 | ||
1210 | /* Check status of child process vs. waitq member. | |
264f41f0 | 1211 | |
8cb359d9 CF |
1212 | parent_w is the pointer to the parent of the waitq member in question. |
1213 | child is the subprocess being considered. | |
264f41f0 | 1214 | |
8cb359d9 CF |
1215 | Returns non-zero if waiting thread released. */ |
1216 | static bool __stdcall | |
84c7d409 | 1217 | stopped_or_terminated (waitq *parent_w, _pinfo *child) |
1fd5e000 | 1218 | { |
8cb359d9 | 1219 | int might_match; |
1fd5e000 CF |
1220 | waitq *w = parent_w->next; |
1221 | ||
962f9a2c | 1222 | sigproc_printf ("considering pid %d, pgid %d, w->pid %d", child->pid, child->pgid, w->pid); |
1fd5e000 | 1223 | if (w->pid == -1) |
8cb359d9 | 1224 | might_match = 1; |
1fd5e000 | 1225 | else if (w->pid == 0) |
8cb359d9 | 1226 | might_match = child->pgid == myself->pgid; |
1fd5e000 | 1227 | else if (w->pid < 0) |
8cb359d9 | 1228 | might_match = child->pgid == -w->pid; |
1fd5e000 | 1229 | else |
8cb359d9 | 1230 | might_match = (w->pid == child->pid); |
1fd5e000 | 1231 | |
8cb359d9 | 1232 | if (!might_match) |
6a712635 | 1233 | return false; |
1fd5e000 | 1234 | |
8cb359d9 | 1235 | int terminated; |
1fd5e000 | 1236 | |
b66dba56 | 1237 | if (!((terminated = (child->process_state == PID_EXITED)) |
ff7b364c CF |
1238 | || ((w->options & WCONTINUED) && child->stopsig == SIGCONT) |
1239 | || ((w->options & WUNTRACED) && child->stopsig && child->stopsig != SIGCONT))) | |
6a712635 | 1240 | return false; |
1fd5e000 | 1241 | |
8cb359d9 CF |
1242 | parent_w->next = w->next; /* successful wait. remove from wait queue */ |
1243 | w->pid = child->pid; | |
1fd5e000 | 1244 | |
8cb359d9 CF |
1245 | if (!terminated) |
1246 | { | |
56a19715 | 1247 | sigproc_printf ("stopped child, stop signal %d", child->stopsig); |
acced2ce CF |
1248 | if (child->stopsig == SIGCONT) |
1249 | w->status = __W_CONTINUED; | |
1250 | else | |
1251 | w->status = (child->stopsig << 8) | 0x7f; | |
8cb359d9 CF |
1252 | child->stopsig = 0; |
1253 | } | |
85b3fb96 | 1254 | else |
8cb359d9 | 1255 | { |
5069a2b0 | 1256 | child->process_state = PID_REAPED; |
85b3fb96 | 1257 | w->status = (__uint16_t) child->exitcode; |
1fd5e000 | 1258 | |
8cb359d9 CF |
1259 | add_rusage (&myself->rusage_children, &child->rusage_children); |
1260 | add_rusage (&myself->rusage_children, &child->rusage_self); | |
1fd5e000 | 1261 | |
8cb359d9 CF |
1262 | if (w->rusage) |
1263 | { | |
1264 | add_rusage ((struct rusage *) w->rusage, &child->rusage_children); | |
1265 | add_rusage ((struct rusage *) w->rusage, &child->rusage_self); | |
1266 | } | |
1fd5e000 CF |
1267 | } |
1268 | ||
8cb359d9 CF |
1269 | if (!SetEvent (w->ev)) /* wake up wait4 () immediately */ |
1270 | system_printf ("couldn't wake up wait event %p, %E", w->ev); | |
1271 | return true; | |
1fd5e000 CF |
1272 | } |
1273 | ||
831d6fa5 | 1274 | static void |
81010d21 | 1275 | talktome (siginfo_t *si) |
831d6fa5 | 1276 | { |
267e201d CF |
1277 | unsigned size = sizeof (*si); |
1278 | sigproc_printf ("pid %d wants some information", si->si_pid); | |
1279 | if (si->_si_commune._si_code & PICOM_EXTRASTR) | |
0730fa07 CF |
1280 | { |
1281 | size_t n; | |
1282 | DWORD nb; | |
81010d21 | 1283 | if (!ReadFile (my_readsig, &n, sizeof (n), &nb, NULL) || nb != sizeof (n)) |
0730fa07 | 1284 | return; |
267e201d CF |
1285 | siginfo_t *newsi = (siginfo_t *) alloca (size += n + 1); |
1286 | *newsi = *si; | |
1287 | newsi->_si_commune._si_str = (char *) (newsi + 1); | |
81010d21 | 1288 | if (!ReadFile (my_readsig, newsi->_si_commune._si_str, n, &nb, NULL) || nb != n) |
0730fa07 | 1289 | return; |
267e201d CF |
1290 | newsi->_si_commune._si_str[n] = '\0'; |
1291 | si = newsi; | |
0730fa07 | 1292 | } |
267e201d CF |
1293 | |
1294 | pinfo pi (si->si_pid); | |
0730fa07 | 1295 | if (pi) |
b9aa8149 | 1296 | new cygthread (commune_process, size, si, "commune"); |
831d6fa5 CF |
1297 | } |
1298 | ||
7ac61736 | 1299 | void |
f6936c48 | 1300 | pending_signals::add (sigpacket& pack) |
7ac61736 | 1301 | { |
f6936c48 | 1302 | sigpacket *se; |
474048c2 CF |
1303 | if (sigs[pack.si.si_signo].si.si_signo) |
1304 | return; | |
1305 | se = sigs + pack.si.si_signo; | |
f6936c48 | 1306 | *se = pack; |
70300fdb | 1307 | se->mask = &pack.tls->sigmask; |
7ac61736 CF |
1308 | se->next = NULL; |
1309 | if (end) | |
1310 | end->next = se; | |
1311 | end = se; | |
1312 | if (!start.next) | |
1313 | start.next = se; | |
7ac61736 CF |
1314 | } |
1315 | ||
1316 | void | |
1317 | pending_signals::del () | |
1318 | { | |
f6936c48 | 1319 | sigpacket *next = curr->next; |
7ac61736 | 1320 | prev->next = next; |
f6936c48 | 1321 | curr->si.si_signo = 0; |
7ac61736 CF |
1322 | #ifdef DEBUGGING |
1323 | curr->next = NULL; | |
1324 | #endif | |
1325 | if (end == curr) | |
1326 | end = prev; | |
7ac61736 CF |
1327 | curr = next; |
1328 | } | |
1329 | ||
f6936c48 | 1330 | sigpacket * |
7ac61736 CF |
1331 | pending_signals::next () |
1332 | { | |
f6936c48 | 1333 | sigpacket *res; |
7ac61736 CF |
1334 | prev = curr; |
1335 | if (!curr || !(curr = curr->next)) | |
9a4d574b | 1336 | res = NULL; |
7ac61736 | 1337 | else |
9a4d574b CF |
1338 | res = curr; |
1339 | return res; | |
7ac61736 CF |
1340 | } |
1341 | ||
1342 | /* Process signals by waiting for signal data to arrive in a pipe. | |
1343 | Set a completion event if one was specified. */ | |
b9874a0c | 1344 | static void WINAPI |
529649f9 | 1345 | wait_sig (VOID *) |
1fd5e000 | 1346 | { |
b9874a0c | 1347 | _sig_tls = &_my_tls; |
e5aa298d | 1348 | sigCONT = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); |
1fd5e000 | 1349 | |
12b33712 CF |
1350 | sigproc_printf ("entering ReadFile loop, my_readsig %p, my_sendsig %p", |
1351 | my_readsig, my_sendsig); | |
2d1d1eb1 | 1352 | |
936e4018 | 1353 | sigpacket pack; |
43c23d4b | 1354 | pack.si.si_signo = 0; |
0d675c5d | 1355 | for (;;) |
1fd5e000 | 1356 | { |
51f90b2f CF |
1357 | if (pack.si.si_signo == __SIGHOLD) |
1358 | WaitForSingleObject (sigCONT, INFINITE); | |
7ac61736 | 1359 | DWORD nb; |
936e4018 | 1360 | pack.tls = NULL; |
81010d21 | 1361 | if (!ReadFile (my_readsig, &pack, sizeof (pack), &nb, NULL)) |
7ac61736 | 1362 | break; |
1fd5e000 | 1363 | |
7759daa9 | 1364 | if (nb != sizeof (pack)) |
018a91fa | 1365 | { |
7759daa9 CF |
1366 | system_printf ("short read from signal pipe: %d != %d", nb, |
1367 | sizeof (pack)); | |
7ac61736 | 1368 | continue; |
018a91fa | 1369 | } |
1fd5e000 | 1370 | |
f6936c48 | 1371 | if (!pack.si.si_signo) |
9a4d574b CF |
1372 | { |
1373 | #ifdef DEBUGGING | |
1374 | system_printf ("zero signal?"); | |
1375 | #endif | |
1376 | continue; | |
1377 | } | |
7ac61736 | 1378 | |
7759daa9 CF |
1379 | sigset_t dummy_mask; |
1380 | if (!pack.mask) | |
1fd5e000 | 1381 | { |
70300fdb | 1382 | dummy_mask = _main_tls->sigmask; |
7759daa9 | 1383 | pack.mask = &dummy_mask; |
1fd5e000 CF |
1384 | } |
1385 | ||
f6936c48 | 1386 | sigpacket *q; |
a5eb75d6 | 1387 | bool clearwait = false; |
f6936c48 | 1388 | switch (pack.si.si_signo) |
90f4768b | 1389 | { |
7ac61736 | 1390 | case __SIGCOMMUNE: |
81010d21 | 1391 | talktome (&pack.si); |
9a4d574b | 1392 | break; |
7ac61736 | 1393 | case __SIGSTRACE: |
8942ed09 | 1394 | strace.activate (false); |
9a4d574b | 1395 | break; |
7ac61736 | 1396 | case __SIGPENDING: |
7759daa9 | 1397 | *pack.mask = 0; |
7ac61736 | 1398 | unsigned bit; |
ca713cfa CF |
1399 | sigq.reset (); |
1400 | while ((q = sigq.next ())) | |
70300fdb | 1401 | if (pack.tls->sigmask & (bit = SIGTOMASK (q->si.si_signo))) |
7759daa9 | 1402 | *pack.mask |= bit; |
7ac61736 | 1403 | break; |
d584454c | 1404 | case __SIGHOLD: |
ede284de | 1405 | goto loop; |
d584454c CF |
1406 | break; |
1407 | case __SIGNOHOLD: | |
a5eb75d6 CF |
1408 | case __SIGFLUSH: |
1409 | case __SIGFLUSHFAST: | |
1410 | sigq.reset (); | |
1411 | while ((q = sigq.next ())) | |
1412 | { | |
1413 | int sig = q->si.si_signo; | |
1414 | if (sig == __SIGDELETE || q->process () > 0) | |
1415 | sigq.del (); | |
1416 | if (sig == __SIGNOHOLD && q->si.si_signo == SIGCHLD) | |
1417 | clearwait = true; | |
1418 | } | |
d584454c | 1419 | break; |
a611ae50 | 1420 | case __SIGEXIT: |
b9874a0c | 1421 | my_sendsig = NULL; |
a611ae50 CF |
1422 | sigproc_printf ("saw __SIGEXIT"); |
1423 | break; /* handle below */ | |
852908e8 CV |
1424 | case __SIGSETPGRP: |
1425 | init_console_handler (true); | |
1426 | break; | |
7ac61736 | 1427 | default: |
f6936c48 CF |
1428 | if (pack.si.si_signo < 0) |
1429 | sig_clear (-pack.si.si_signo); | |
27ec638b | 1430 | else |
90f4768b | 1431 | { |
9e1ad59d | 1432 | int sig = pack.si.si_signo; |
b9ebff64 CF |
1433 | // FIXME: REALLY not right when taking threads into consideration. |
1434 | // We need a per-thread queue since each thread can have its own | |
1435 | // list of blocked signals. CGF 2005-08-24 | |
1436 | if (sigq.sigs[sig].si.si_signo && sigq.sigs[sig].tls == pack.tls) | |
56a19715 | 1437 | sigproc_printf ("signal %d already queued", pack.si.si_signo); |
85427a94 | 1438 | else |
29d52c8a | 1439 | { |
85427a94 CF |
1440 | int sigres = pack.process (); |
1441 | if (sigres <= 0) | |
1442 | { | |
76832a5b | 1443 | #ifdef DEBUGGING2 |
85427a94 | 1444 | if (!sigres) |
fa0b926a | 1445 | system_printf ("Failed to arm signal %d from pid %d", pack.si.si_signo, pack.pid); |
29d52c8a | 1446 | #endif |
85427a94 CF |
1447 | sigq.add (pack); // FIXME: Shouldn't add this in !sh condition |
1448 | } | |
29d52c8a | 1449 | } |
9e1ad59d | 1450 | if (sig == SIGCHLD) |
a5eb75d6 | 1451 | clearwait = true; |
90f4768b | 1452 | } |
7ac61736 | 1453 | break; |
d688945c | 1454 | } |
a5eb75d6 CF |
1455 | if (clearwait) |
1456 | proc_subproc (PROC_CLEARWAIT, 0); | |
ede284de | 1457 | loop: |
7759daa9 | 1458 | if (pack.wakeup) |
39d06d71 | 1459 | { |
f02b22dc | 1460 | sigproc_printf ("signalling pack.wakeup %p", pack.wakeup); |
39d06d71 | 1461 | SetEvent (pack.wakeup); |
39d06d71 | 1462 | } |
a611ae50 CF |
1463 | if (pack.si.si_signo == __SIGEXIT) |
1464 | break; | |
1fd5e000 CF |
1465 | } |
1466 | ||
08d944e1 | 1467 | close_my_readsig (); |
5e477e9a CF |
1468 | sigproc_printf ("signal thread exiting"); |
1469 | ExitThread (0); | |
1fd5e000 | 1470 | } |