Commit | Line | Data |
---|---|---|
6cdfb6e6 RS |
1 | /* Process support for Windows NT port of GNU EMACS. |
2 | Copyright (C) 1992 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GNU Emacs. | |
5 | ||
6 | GNU Emacs is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU General Public License as published by the | |
8 | Free Software Foundation; either version 2, or (at your option) any later | |
9 | version. | |
10 | ||
11 | GNU Emacs is distributed in the hope that it will be useful, but WITHOUT | |
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License along | |
17 | with GNU Emacs; see the file COPYING. If not, write to the Free Software | |
18 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | ||
20 | Drew Bliss Oct 14, 1993 | |
21 | Adapted from alarm.c by Tim Fleehart | |
22 | */ | |
23 | ||
24 | #include <stdio.h> | |
25 | #include <stdlib.h> | |
26 | #include <errno.h> | |
27 | #include <io.h> | |
28 | #include <signal.h> | |
29 | ||
30 | #include "config.h" | |
31 | ||
32 | #include <windows.h> | |
33 | ||
34 | #include "lisp.h" | |
35 | #include "nt.h" | |
36 | #include "systime.h" | |
37 | ||
38 | /* #define FULL_DEBUG */ | |
39 | ||
40 | typedef void (_CALLBACK_ *signal_handler)(int); | |
41 | ||
42 | /* Defined in process.h which conflicts with the local copy */ | |
43 | #define _P_NOWAIT 1 | |
44 | ||
45 | typedef struct _child_process | |
46 | { | |
47 | int fd; | |
48 | HANDLE char_avail; | |
49 | HANDLE char_consumed; | |
50 | char chr; | |
51 | BOOL status; | |
52 | HANDLE process; | |
53 | DWORD pid; | |
54 | HANDLE thrd; | |
55 | } child_process; | |
56 | ||
57 | #define MAX_CHILDREN MAXDESC | |
58 | ||
59 | #ifdef EMACSDEBUG | |
60 | void _CRTAPI1 | |
61 | _DebPrint (char *fmt, ...) | |
62 | { | |
63 | char buf[256]; | |
64 | va_list args; | |
65 | ||
66 | va_start (args, fmt); | |
67 | vsprintf (buf, fmt, args); | |
68 | va_end (args); | |
69 | OutputDebugString (buf); | |
70 | } | |
71 | #endif | |
72 | ||
73 | /* Child process management list. */ | |
74 | static int child_proc_count = 0; | |
75 | static child_process child_procs[MAX_CHILDREN]; | |
76 | static child_process *dead_child = NULL; | |
77 | ||
78 | #define CHILD_ACTIVE(cp) ((cp)->process != NULL) | |
79 | #define DEACTIVATE_CHILD(cp) ((cp)->process = NULL) | |
80 | ||
81 | /* Signal handlers...SIG_DFL == 0 so this is initialized correctly. */ | |
82 | static signal_handler sig_handlers[NSIG]; | |
83 | ||
84 | /* Fake signal implementation to record the SIGCHLD handler. */ | |
85 | signal_handler | |
86 | win32_signal (int sig, signal_handler handler) | |
87 | { | |
88 | signal_handler old; | |
89 | ||
90 | if (sig != SIGCHLD) | |
91 | { | |
92 | errno = EINVAL; | |
93 | return SIG_ERR; | |
94 | } | |
95 | old = sig_handlers[sig]; | |
96 | sig_handlers[sig] = handler; | |
97 | return old; | |
98 | } | |
99 | ||
100 | /* Find an unused process slot. */ | |
101 | static child_process * | |
102 | new_child (void) | |
103 | { | |
104 | child_process *cp; | |
105 | ||
106 | if (child_proc_count == MAX_CHILDREN) | |
107 | return NULL; | |
108 | ||
109 | for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--) | |
110 | if (!CHILD_ACTIVE (cp)) | |
111 | return cp; | |
112 | return &child_procs[child_proc_count++]; | |
113 | } | |
114 | ||
115 | /* Find a child by pid. */ | |
116 | static child_process * | |
117 | find_child_pid (DWORD pid) | |
118 | { | |
119 | child_process *cp; | |
120 | ||
121 | for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--) | |
122 | if (CHILD_ACTIVE (cp) && pid == cp->pid) | |
123 | return cp; | |
124 | return NULL; | |
125 | } | |
126 | ||
127 | /* Find a child by fd. */ | |
128 | static child_process * | |
129 | find_child_fd (int fd) | |
130 | { | |
131 | child_process *cp; | |
132 | ||
133 | for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--) | |
134 | if (CHILD_ACTIVE (cp) && fd == cp->fd) | |
135 | return cp; | |
136 | return NULL; | |
137 | } | |
138 | ||
139 | /* Thread proc for child process reader threads | |
140 | The threads just sit in a loop waiting for input | |
141 | When they detect input, they signal the char_avail input to | |
142 | wake up the select emulator | |
143 | When the select emulator processes their input, it pulses | |
144 | char_consumed so that the reader thread goes back to reading. */ | |
145 | DWORD WINAPI | |
146 | reader_thread (void *arg) | |
147 | { | |
148 | child_process *cp; | |
149 | ||
150 | /* Our identity */ | |
151 | cp = (child_process *)arg; | |
152 | ||
153 | /* We have to wait for the go-ahead before we can start */ | |
154 | if (WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0) | |
155 | return 0; | |
156 | /* If something went wrong, quit */ | |
157 | if (!cp->status) | |
158 | return 0; | |
159 | ||
160 | for (;;) | |
161 | { | |
162 | /* Use read to get CRLF translation */ | |
163 | if (read (cp->fd, &cp->chr, sizeof (char)) == sizeof (char)) | |
164 | { | |
165 | cp->status = TRUE; | |
166 | } | |
167 | else | |
168 | { | |
169 | #ifdef FULL_DEBUG | |
170 | DebPrint (("reader_thread.read failed with %lu for fd %ld\n", | |
171 | GetLastError (), cp->fd)); | |
172 | #endif | |
173 | cp->status = FALSE; | |
174 | } | |
175 | ||
176 | if (!SetEvent (cp->char_avail)) | |
177 | { | |
178 | DebPrint (("reader_thread.SetEvent failed with %lu for fd %ld\n", | |
179 | GetLastError (), cp->fd)); | |
180 | break; | |
181 | } | |
182 | ||
183 | /* If the read died, the child has died so let the thread die */ | |
184 | if (!cp->status) | |
185 | break; | |
186 | ||
187 | /* Wait until our input is acknowledged before reading again */ | |
188 | if (WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0) | |
189 | { | |
190 | DebPrint (("reader_thread.WaitForSingleObject failed with " | |
191 | "%lu for fd %ld\n", GetLastError (), cp->fd)); | |
192 | break; | |
193 | } | |
194 | } | |
195 | return 0; | |
196 | } | |
197 | ||
198 | static BOOL | |
199 | create_child (char *exe, char *cmdline, char *env, | |
200 | PROCESS_INFORMATION *info) | |
201 | { | |
202 | child_process *cp; | |
203 | DWORD id; | |
204 | STARTUPINFO start; | |
205 | SECURITY_ATTRIBUTES sec_attrs; | |
206 | SECURITY_DESCRIPTOR sec_desc; | |
207 | ||
208 | cp = new_child (); | |
209 | if (cp == NULL) | |
210 | goto EH_Fail; | |
211 | ||
212 | cp->fd = -1; | |
213 | ||
214 | cp->char_avail = CreateEvent (NULL, FALSE, FALSE, NULL); | |
215 | if (cp->char_avail == NULL) | |
216 | goto EH_Fail; | |
217 | ||
218 | cp->char_consumed = CreateEvent (NULL, FALSE, FALSE, NULL); | |
219 | if (cp->char_consumed == NULL) | |
220 | goto EH_char_avail; | |
221 | ||
222 | cp->thrd = CreateThread (NULL, 1024, reader_thread, cp, 0, &id); | |
223 | if (cp->thrd == NULL) | |
224 | goto EH_char_consumed; | |
225 | ||
226 | memset (&start, 0, sizeof (start)); | |
227 | start.cb = sizeof (start); | |
228 | ||
229 | /* Explicitly specify no security */ | |
230 | if (!InitializeSecurityDescriptor (&sec_desc, SECURITY_DESCRIPTOR_REVISION)) | |
231 | goto EH_thrd; | |
232 | if (!SetSecurityDescriptorDacl (&sec_desc, TRUE, NULL, FALSE)) | |
233 | goto EH_thrd; | |
234 | sec_attrs.nLength = sizeof (sec_attrs); | |
235 | sec_attrs.lpSecurityDescriptor = &sec_desc; | |
236 | sec_attrs.bInheritHandle = FALSE; | |
237 | ||
238 | if (!CreateProcess (exe, cmdline, &sec_attrs, NULL, TRUE, | |
239 | CREATE_NEW_PROCESS_GROUP, env, NULL, | |
240 | &start, info)) | |
241 | goto EH_thrd; | |
242 | cp->process = info->hProcess; | |
243 | cp->pid = info->dwProcessId; | |
244 | ||
245 | return TRUE; | |
246 | ||
247 | EH_thrd: | |
248 | id = GetLastError (); | |
249 | ||
250 | cp->status = FALSE; | |
251 | SetEvent (cp->char_consumed); | |
252 | EH_char_consumed: | |
253 | CloseHandle (cp->char_consumed); | |
254 | EH_char_avail: | |
255 | CloseHandle (cp->char_avail); | |
256 | EH_Fail: | |
257 | return FALSE; | |
258 | } | |
259 | ||
260 | /* create_child doesn't know what emacs' file handle will be for waiting | |
261 | on output from the child, so we need to make this additional call | |
262 | to register the handle with the process | |
263 | This way the select emulator knows how to match file handles with | |
264 | entries in child_procs. */ | |
265 | void | |
266 | register_child (int pid, int fd) | |
267 | { | |
268 | child_process *cp; | |
269 | ||
270 | cp = find_child_pid (pid); | |
271 | if (cp == NULL) | |
272 | { | |
273 | DebPrint (("register_child unable to find pid %lu\n", pid)); | |
274 | return; | |
275 | } | |
276 | ||
277 | #ifdef FULL_DEBUG | |
278 | DebPrint (("register_child registered fd %d with pid %lu\n", fd, pid)); | |
279 | #endif | |
280 | ||
281 | cp->fd = fd; | |
282 | cp->status = TRUE; | |
283 | ||
284 | /* Tell the reader thread to start */ | |
285 | if (!SetEvent (cp->char_consumed)) | |
286 | { | |
287 | DebPrint (("register_child.SetEvent failed with %lu for fd %ld\n", | |
288 | GetLastError (), cp->fd)); | |
289 | } | |
290 | } | |
291 | ||
292 | /* When a process dies its pipe will break so the reader thread will | |
293 | signal failure to the select emulator. | |
294 | The select emulator then calls this routine to clean up. | |
295 | Since the thread signaled failure we can assume it is exiting. */ | |
296 | static void | |
297 | remove_child (child_process *cp) | |
298 | { | |
299 | /* Reap the thread */ | |
300 | if (WaitForSingleObject (cp->thrd, INFINITE) != WAIT_OBJECT_0) | |
301 | { | |
302 | DebPrint (("remove_child.WaitForSingleObject (thread) failed " | |
303 | "with %lu for fd %ld\n", GetLastError (), cp->fd)); | |
304 | } | |
305 | CloseHandle (cp->thrd); | |
306 | CloseHandle (cp->char_consumed); | |
307 | CloseHandle (cp->char_avail); | |
308 | ||
309 | /* Reap the process */ | |
310 | if (WaitForSingleObject (cp->process, INFINITE) != WAIT_OBJECT_0) | |
311 | { | |
312 | DebPrint (("remove_child.WaitForSingleObject (process) failed " | |
313 | "with %lu for fd %ld\n", GetLastError (), cp->fd)); | |
314 | } | |
315 | CloseHandle (cp->process); | |
316 | ||
317 | DEACTIVATE_CHILD (cp); | |
318 | } | |
319 | ||
320 | /* Wait for any of our existing child processes to die | |
321 | When it does, close its handle | |
322 | Return the pid and fill in the status if non-NULL. */ | |
323 | int | |
324 | win32_wait (int *status) | |
325 | { | |
326 | DWORD active, retval; | |
327 | int nh; | |
328 | child_process *cp, *cps[MAX_CHILDREN]; | |
329 | HANDLE wait_hnd[MAX_CHILDREN]; | |
330 | ||
331 | nh = 0; | |
332 | if (dead_child != NULL) | |
333 | { | |
334 | /* We want to wait for a specific child */ | |
335 | wait_hnd[nh] = dead_child->process; | |
336 | cps[nh] = dead_child; | |
337 | nh++; | |
338 | } | |
339 | else | |
340 | { | |
341 | for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--) | |
342 | if (CHILD_ACTIVE (cp)) | |
343 | { | |
344 | wait_hnd[nh] = cp->process; | |
345 | cps[nh] = cp; | |
346 | nh++; | |
347 | } | |
348 | } | |
349 | ||
350 | if (nh == 0) | |
351 | { | |
352 | /* Nothing to wait on, so fail */ | |
353 | errno = ECHILD; | |
354 | return -1; | |
355 | } | |
356 | ||
357 | active = WaitForMultipleObjects (nh, wait_hnd, FALSE, INFINITE); | |
358 | if (active == WAIT_FAILED) | |
359 | { | |
360 | errno = EBADF; | |
361 | return -1; | |
362 | } | |
363 | else if (active == WAIT_TIMEOUT) | |
364 | { | |
365 | /* Should never happen */ | |
366 | errno = EINVAL; | |
367 | return -1; | |
368 | } | |
369 | else if (active >= WAIT_OBJECT_0 && | |
370 | active < WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS) | |
371 | { | |
372 | active -= WAIT_OBJECT_0; | |
373 | } | |
374 | else if (active >= WAIT_ABANDONED_0 && | |
375 | active < WAIT_ABANDONED_0+MAXIMUM_WAIT_OBJECTS) | |
376 | { | |
377 | active -= WAIT_ABANDONED_0; | |
378 | } | |
379 | ||
380 | if (!GetExitCodeProcess (wait_hnd[active], &retval)) | |
381 | { | |
382 | DebPrint (("Wait.GetExitCodeProcess failed with %lu\n", | |
383 | GetLastError ())); | |
384 | retval = 1; | |
385 | } | |
386 | if (retval == STILL_ACTIVE) | |
387 | { | |
388 | /* Should never happen */ | |
389 | DebPrint (("Wait.WaitForMultipleObjects returned an active process\n")); | |
390 | errno = EINVAL; | |
391 | return -1; | |
392 | } | |
393 | ||
394 | cp = cps[active]; | |
395 | #ifdef FULL_DEBUG | |
396 | DebPrint (("Wait signaled with process pid %d\n", cp->pid)); | |
397 | #endif | |
398 | ||
399 | if (status) | |
400 | { | |
401 | /* In process.c the default WAITTYPE is defined. | |
402 | Since we can't determine anything about why a process died | |
403 | we can only return a code that looks like WIFEXITED */ | |
404 | *status = (retval & 0x7fffff) << 8; | |
405 | } | |
406 | ||
407 | return cp->pid; | |
408 | } | |
409 | ||
410 | /* We pass our process ID to our children by setting up an environment | |
411 | variable in their environment. */ | |
412 | char ppid_env_var_buffer[64]; | |
413 | ||
414 | /* When a new child process is created we need to register it in our list, | |
415 | so intercept spawn requests. */ | |
416 | int | |
417 | win32_spawnve (int mode, char *cmdname, char **argv, char **envp) | |
418 | { | |
419 | char *cmdline, *env, *parg, **targ; | |
420 | int arglen; | |
421 | PROCESS_INFORMATION pi; | |
422 | ||
423 | if (child_proc_count == MAX_CHILDREN) | |
424 | { | |
425 | errno = EAGAIN; | |
426 | return -1; | |
427 | } | |
428 | ||
429 | /* We don't care about the other modes */ | |
430 | if (mode != _P_NOWAIT) | |
431 | { | |
432 | errno = EINVAL; | |
433 | return -1; | |
434 | } | |
435 | ||
436 | /* we have to do some conjuring here to put argv and envp into the | |
437 | form CreateProcess wants... argv needs to be a space separated/null | |
438 | terminated list of parameters, and envp is a null | |
439 | separated/double-null terminated list of parameters. | |
440 | ||
441 | Since I have no idea how large argv and envp are likely to be | |
442 | we figure out list lengths on the fly and allocate them. */ | |
443 | ||
444 | /* do argv... */ | |
445 | arglen = 0; | |
446 | targ = argv; | |
447 | while (*targ) | |
448 | { | |
449 | arglen += strlen (*targ++) + 1; | |
450 | } | |
451 | cmdline = malloc (arglen); | |
452 | if (cmdline == NULL) | |
453 | { | |
454 | errno = ENOMEM; | |
455 | goto EH_Fail; | |
456 | } | |
457 | targ = argv; | |
458 | parg = cmdline; | |
459 | while (*targ) | |
460 | { | |
461 | strcpy (parg, *targ); | |
462 | parg += strlen (*targ++); | |
463 | *parg++ = ' '; | |
464 | } | |
465 | *--parg = '\0'; | |
466 | ||
467 | /* and envp... */ | |
468 | arglen = 1; | |
469 | targ = envp; | |
470 | while (*targ) | |
471 | { | |
472 | arglen += strlen (*targ++) + 1; | |
473 | } | |
474 | sprintf (ppid_env_var_buffer, "__PARENT_PROCESS_ID=%d", | |
475 | GetCurrentProcessId ()); | |
476 | arglen += strlen (ppid_env_var_buffer) + 1; | |
477 | ||
478 | env = malloc (arglen); | |
479 | if (env == NULL) | |
480 | { | |
481 | errno = ENOMEM; | |
482 | goto EH_cmdline; | |
483 | } | |
484 | targ = envp; | |
485 | parg = env; | |
486 | while (*targ) | |
487 | { | |
488 | strcpy (parg, *targ); | |
489 | parg += strlen (*targ++); | |
490 | *parg++ = '\0'; | |
491 | } | |
492 | strcpy (parg, ppid_env_var_buffer); | |
493 | parg += strlen (ppid_env_var_buffer); | |
494 | *parg++ = '\0'; | |
495 | *parg = '\0'; | |
496 | ||
497 | /* Now create the process. */ | |
498 | if (!create_child (cmdname, cmdline, env, &pi)) | |
499 | { | |
500 | errno = ENOEXEC; | |
501 | goto EH_env; | |
502 | } | |
503 | ||
504 | return pi.dwProcessId; | |
505 | ||
506 | EH_env: | |
507 | free (env); | |
508 | EH_cmdline: | |
509 | free (cmdline); | |
510 | EH_Fail: | |
511 | return -1; | |
512 | } | |
513 | ||
514 | /* Emulate the select call | |
515 | Wait for available input on any of the given rfds, or timeout if | |
516 | a timeout is given and no input is detected | |
517 | wfds and efds are not supported and must be NULL. */ | |
518 | ||
519 | /* From ntterm.c */ | |
520 | extern HANDLE keyboard_handle; | |
521 | /* From process.c */ | |
522 | extern int proc_buffered_char[]; | |
523 | ||
524 | int | |
525 | select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, | |
526 | EMACS_TIME *timeout) | |
527 | { | |
528 | SELECT_TYPE orfds; | |
529 | DWORD timeout_ms; | |
530 | int i, nh, nr; | |
531 | DWORD active; | |
532 | child_process *cp, *cps[MAX_CHILDREN]; | |
533 | HANDLE wait_hnd[MAX_CHILDREN]; | |
534 | ||
535 | /* If the descriptor sets are NULL but timeout isn't, then just Sleep. */ | |
536 | if (rfds == NULL && wfds == NULL && efds == NULL && timeout != NULL) | |
537 | { | |
538 | Sleep ((*timeout) * 1000); | |
539 | return 0; | |
540 | } | |
541 | ||
542 | /* Otherwise, we only handle rfds, so fail otherwise. */ | |
543 | if (rfds == NULL || wfds != NULL || efds != NULL) | |
544 | { | |
545 | errno = EINVAL; | |
546 | return -1; | |
547 | } | |
548 | ||
549 | orfds = *rfds; | |
550 | FD_ZERO (rfds); | |
551 | nr = 0; | |
552 | ||
553 | /* Build a list of handles to wait on. */ | |
554 | nh = 0; | |
555 | for (i = 0; i < nfds; i++) | |
556 | if (FD_ISSET (i, &orfds)) | |
557 | { | |
558 | if (i == 0) | |
559 | { | |
560 | /* Handle stdin specially */ | |
561 | wait_hnd[nh] = keyboard_handle; | |
562 | cps[nh] = NULL; | |
563 | nh++; | |
564 | ||
565 | /* Check for any emacs-generated input in the queue since | |
566 | it won't be detected in the wait */ | |
567 | if (detect_input_pending ()) | |
568 | { | |
569 | FD_SET (i, rfds); | |
570 | nr++; | |
571 | } | |
572 | } | |
573 | else | |
574 | { | |
575 | /* Child process input */ | |
576 | cp = find_child_fd (i); | |
577 | if (cp) | |
578 | { | |
579 | #ifdef FULL_DEBUG | |
580 | DebPrint (("select waiting on child %d fd %d\n", | |
581 | cp-child_procs, i)); | |
582 | #endif | |
583 | wait_hnd[nh] = cp->char_avail; | |
584 | cps[nh] = cp; | |
585 | nh++; | |
586 | } | |
587 | else | |
588 | { | |
589 | /* Unable to find something to wait on for this fd, fail */ | |
590 | DebPrint (("select unable to find child process " | |
591 | "for fd %ld\n", i)); | |
592 | nh = 0; | |
593 | break; | |
594 | } | |
595 | } | |
596 | } | |
597 | ||
598 | /* Nothing to look for, so we didn't find anything */ | |
599 | if (nh == 0) | |
600 | { | |
601 | Sleep ((*timeout) * 1000); | |
602 | return 0; | |
603 | } | |
604 | ||
605 | /* Check for immediate return without waiting */ | |
606 | if (nr > 0) | |
607 | return nr; | |
608 | ||
609 | /* | |
610 | Wait for input | |
611 | If a child process dies while this is waiting, its pipe will break | |
612 | so the reader thread will signal an error condition, thus, the wait | |
613 | will wake up | |
614 | */ | |
615 | timeout_ms = timeout ? *timeout*1000 : INFINITE; | |
616 | active = WaitForMultipleObjects (nh, wait_hnd, FALSE, timeout_ms); | |
617 | if (active == WAIT_FAILED) | |
618 | { | |
619 | DebPrint (("select.WaitForMultipleObjects (%d, %lu) failed with %lu\n", | |
620 | nh, timeout_ms, GetLastError ())); | |
621 | /* Is there a better error? */ | |
622 | errno = EBADF; | |
623 | return -1; | |
624 | } | |
625 | else if (active == WAIT_TIMEOUT) | |
626 | { | |
627 | return 0; | |
628 | } | |
629 | else if (active >= WAIT_OBJECT_0 && | |
630 | active < WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS) | |
631 | { | |
632 | active -= WAIT_OBJECT_0; | |
633 | } | |
634 | else if (active >= WAIT_ABANDONED_0 && | |
635 | active < WAIT_ABANDONED_0+MAXIMUM_WAIT_OBJECTS) | |
636 | { | |
637 | active -= WAIT_ABANDONED_0; | |
638 | } | |
639 | ||
640 | if (cps[active] == NULL) | |
641 | { | |
642 | /* Keyboard input available */ | |
643 | FD_SET (0, rfds); | |
644 | nr++; | |
645 | ||
646 | /* This shouldn't be necessary, but apparently just setting the input | |
647 | fd is not good enough for emacs */ | |
648 | read_input_waiting (); | |
649 | } | |
650 | else | |
651 | { | |
652 | /* Child process */ | |
653 | cp = cps[active]; | |
654 | ||
655 | /* If status is FALSE the read failed so don't report input */ | |
656 | if (cp->status) | |
657 | { | |
658 | FD_SET (cp->fd, rfds); | |
659 | proc_buffered_char[cp->fd] = cp->chr; | |
660 | nr++; | |
661 | } | |
662 | else | |
663 | { | |
664 | /* The SIGCHLD handler will do a Wait so we know it won't | |
665 | return until the process is dead | |
666 | We force Wait to only wait for this process to avoid it | |
667 | picking up other children that happen to be dead but that | |
668 | we haven't noticed yet | |
669 | SIG_DFL for SIGCHLD is ignore? */ | |
670 | if (sig_handlers[SIGCHLD] != SIG_DFL && | |
671 | sig_handlers[SIGCHLD] != SIG_IGN) | |
672 | { | |
673 | #ifdef FULL_DEBUG | |
674 | DebPrint (("select calling SIGCHLD handler for pid %d\n", | |
675 | cp->pid)); | |
676 | #endif | |
677 | dead_child = cp; | |
678 | sig_handlers[SIGCHLD](SIGCHLD); | |
679 | dead_child = NULL; | |
680 | } | |
681 | ||
682 | /* Clean up the child process entry in the table */ | |
683 | remove_child (cp); | |
684 | } | |
685 | } | |
686 | return nr; | |
687 | } | |
688 | ||
689 | /* | |
690 | Substitute for certain kill () operations | |
691 | */ | |
692 | int | |
693 | win32_kill_process (int pid, int sig) | |
694 | { | |
695 | child_process *cp; | |
696 | ||
697 | /* Only handle signals that will result in the process dying */ | |
698 | if (sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP) | |
699 | { | |
700 | errno = EINVAL; | |
701 | return -1; | |
702 | } | |
703 | ||
704 | cp = find_child_pid (pid); | |
705 | if (cp == NULL) | |
706 | { | |
707 | DebPrint (("win32_kill_process didn't find a child with pid %lu\n", pid)); | |
708 | errno = ECHILD; | |
709 | return -1; | |
710 | } | |
711 | ||
712 | if (sig == SIGINT) | |
713 | { | |
714 | /* Fake Ctrl-Break. */ | |
715 | if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid)) | |
716 | { | |
717 | DebPrint (("win32_kill_process.GenerateConsoleCtrlEvent return %d " | |
718 | "for pid %lu\n", GetLastError (), pid)); | |
719 | errno = EINVAL; | |
720 | return -1; | |
721 | } | |
722 | } | |
723 | else | |
724 | { | |
725 | /* Kill the process. On Win32 this doesn't kill child processes | |
726 | so it doesn't work very well for shells which is why it's | |
727 | not used in every case. */ | |
728 | if (!TerminateProcess (cp->process, 0xff)) | |
729 | { | |
730 | DebPrint (("win32_kill_process.TerminateProcess returned %d " | |
731 | "for pid %lu\n", GetLastError (), pid)); | |
732 | errno = EINVAL; | |
733 | return -1; | |
734 | } | |
735 | } | |
736 | return 0; | |
737 | } | |
738 | ||
739 | /* If the channel is a pipe this read might block since we don't | |
740 | know how many characters are available, so check and read only | |
741 | what's there | |
742 | We also need to wake up the reader thread once we've read our data. */ | |
743 | int | |
744 | read_child_output (int fd, char *buf, int max) | |
745 | { | |
746 | HANDLE h; | |
747 | int to_read, nchars; | |
748 | DWORD waiting; | |
749 | child_process *cp; | |
750 | ||
751 | h = (HANDLE)_get_osfhandle (fd); | |
752 | if (GetFileType (h) == FILE_TYPE_PIPE) | |
753 | { | |
754 | PeekNamedPipe (h, NULL, 0, NULL, &waiting, NULL); | |
755 | to_read = min (waiting, (DWORD)max); | |
756 | } | |
757 | else | |
758 | to_read = max; | |
759 | ||
760 | /* Use read to get CRLF translation */ | |
761 | nchars = read (fd, buf, to_read); | |
762 | ||
763 | if (GetFileType (h) == FILE_TYPE_PIPE) | |
764 | { | |
765 | /* Wake up the reader thread | |
766 | for this process */ | |
767 | cp = find_child_fd (fd); | |
768 | if (cp) | |
769 | { | |
770 | if (!SetEvent (cp->char_consumed)) | |
771 | DebPrint (("read_child_output.SetEvent failed with " | |
772 | "%lu for fd %ld\n", GetLastError (), fd)); | |
773 | } | |
774 | else | |
775 | DebPrint (("read_child_output couldn't find a child with fd %d\n", | |
776 | fd)); | |
777 | } | |
778 | ||
779 | return nchars; | |
780 | } |