(sigchld_handler): Change XSETFASTINT to XSETINT.
[bpt/emacs.git] / src / w32proc.c
CommitLineData
6cdfb6e6 1/* Process support for Windows NT port of GNU EMACS.
22759c72 2 Copyright (C) 1992, 1995 Free Software Foundation, Inc.
6cdfb6e6
RS
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
6816efce
GV
24#include <config.h>
25
6cdfb6e6
RS
26#include <stdio.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <io.h>
30#include <signal.h>
31
6cdfb6e6
RS
32#include <windows.h>
33
34#include "lisp.h"
35#include "nt.h"
36#include "systime.h"
37
38/* #define FULL_DEBUG */
39
40typedef void (_CALLBACK_ *signal_handler)(int);
41
42/* Defined in process.h which conflicts with the local copy */
43#define _P_NOWAIT 1
44
45typedef 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
60void _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. */
74static int child_proc_count = 0;
75static child_process child_procs[MAX_CHILDREN];
76static 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. */
82static signal_handler sig_handlers[NSIG];
83
84/* Fake signal implementation to record the SIGCHLD handler. */
85signal_handler
86win32_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. */
101static child_process *
102new_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. */
116static child_process *
117find_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. */
128static child_process *
129find_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. */
145DWORD WINAPI
146reader_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
198static BOOL
199create_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. */
265void
266register_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. */
296static void
297remove_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. */
22759c72
KH
323
324/* From callproc.c */
325extern int synch_process_alive;
326extern int synch_process_retcode;
327
6cdfb6e6
RS
328int
329win32_wait (int *status)
330{
331 DWORD active, retval;
332 int nh;
333 child_process *cp, *cps[MAX_CHILDREN];
334 HANDLE wait_hnd[MAX_CHILDREN];
335
336 nh = 0;
337 if (dead_child != NULL)
338 {
339 /* We want to wait for a specific child */
340 wait_hnd[nh] = dead_child->process;
341 cps[nh] = dead_child;
342 nh++;
343 }
344 else
345 {
346 for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--)
347 if (CHILD_ACTIVE (cp))
348 {
349 wait_hnd[nh] = cp->process;
350 cps[nh] = cp;
351 nh++;
352 }
353 }
354
355 if (nh == 0)
356 {
357 /* Nothing to wait on, so fail */
358 errno = ECHILD;
359 return -1;
360 }
361
362 active = WaitForMultipleObjects (nh, wait_hnd, FALSE, INFINITE);
363 if (active == WAIT_FAILED)
364 {
365 errno = EBADF;
366 return -1;
367 }
368 else if (active == WAIT_TIMEOUT)
369 {
370 /* Should never happen */
371 errno = EINVAL;
372 return -1;
373 }
374 else if (active >= WAIT_OBJECT_0 &&
375 active < WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS)
376 {
377 active -= WAIT_OBJECT_0;
378 }
379 else if (active >= WAIT_ABANDONED_0 &&
380 active < WAIT_ABANDONED_0+MAXIMUM_WAIT_OBJECTS)
381 {
382 active -= WAIT_ABANDONED_0;
383 }
384
385 if (!GetExitCodeProcess (wait_hnd[active], &retval))
386 {
387 DebPrint (("Wait.GetExitCodeProcess failed with %lu\n",
388 GetLastError ()));
389 retval = 1;
390 }
391 if (retval == STILL_ACTIVE)
392 {
393 /* Should never happen */
394 DebPrint (("Wait.WaitForMultipleObjects returned an active process\n"));
395 errno = EINVAL;
396 return -1;
397 }
398
399 cp = cps[active];
22759c72 400
6cdfb6e6
RS
401 if (status)
402 {
22759c72
KH
403 *status = retval;
404 }
405 else if (synch_process_alive)
406 {
407 synch_process_alive = 0;
408 synch_process_retcode = retval;
409
410 TerminateThread (cp->thrd, 0);
411 CloseHandle (cp->thrd);
412 CloseHandle (cp->char_consumed);
413 CloseHandle (cp->char_avail);
414 CloseHandle (cp->process);
415 DEACTIVATE_CHILD (cp);
6cdfb6e6
RS
416 }
417
418 return cp->pid;
419}
420
421/* We pass our process ID to our children by setting up an environment
422 variable in their environment. */
423char ppid_env_var_buffer[64];
424
425/* When a new child process is created we need to register it in our list,
426 so intercept spawn requests. */
427int
428win32_spawnve (int mode, char *cmdname, char **argv, char **envp)
429{
0a4de642 430 Lisp_Object program, full;
6cdfb6e6
RS
431 char *cmdline, *env, *parg, **targ;
432 int arglen;
433 PROCESS_INFORMATION pi;
0a4de642
RS
434
435 /* Handle executable names without an executable suffix. */
436 program = make_string (cmdname, strlen (cmdname));
437 if (NILP (Ffile_executable_p (program)))
438 {
439 struct gcpro gcpro1;
440
441 full = Qnil;
442 GCPRO1 (program);
443 openp (Vexec_path, program, EXEC_SUFFIXES, &full, 1);
444 UNGCPRO;
445 if (NILP (full))
446 {
447 errno = EINVAL;
448 return -1;
449 }
450 cmdname = XSTRING (full)->data;
451 argv[0] = cmdname;
452 }
453
6cdfb6e6
RS
454 if (child_proc_count == MAX_CHILDREN)
455 {
456 errno = EAGAIN;
457 return -1;
458 }
459
460 /* We don't care about the other modes */
461 if (mode != _P_NOWAIT)
462 {
463 errno = EINVAL;
464 return -1;
465 }
466
467 /* we have to do some conjuring here to put argv and envp into the
468 form CreateProcess wants... argv needs to be a space separated/null
469 terminated list of parameters, and envp is a null
470 separated/double-null terminated list of parameters.
471
472 Since I have no idea how large argv and envp are likely to be
473 we figure out list lengths on the fly and allocate them. */
474
475 /* do argv... */
476 arglen = 0;
477 targ = argv;
478 while (*targ)
479 {
480 arglen += strlen (*targ++) + 1;
481 }
482 cmdline = malloc (arglen);
483 if (cmdline == NULL)
484 {
485 errno = ENOMEM;
486 goto EH_Fail;
487 }
488 targ = argv;
489 parg = cmdline;
490 while (*targ)
491 {
492 strcpy (parg, *targ);
493 parg += strlen (*targ++);
494 *parg++ = ' ';
495 }
496 *--parg = '\0';
497
498 /* and envp... */
499 arglen = 1;
500 targ = envp;
501 while (*targ)
502 {
503 arglen += strlen (*targ++) + 1;
504 }
505 sprintf (ppid_env_var_buffer, "__PARENT_PROCESS_ID=%d",
506 GetCurrentProcessId ());
507 arglen += strlen (ppid_env_var_buffer) + 1;
508
509 env = malloc (arglen);
510 if (env == NULL)
511 {
512 errno = ENOMEM;
513 goto EH_cmdline;
514 }
515 targ = envp;
516 parg = env;
517 while (*targ)
518 {
519 strcpy (parg, *targ);
520 parg += strlen (*targ++);
521 *parg++ = '\0';
522 }
523 strcpy (parg, ppid_env_var_buffer);
524 parg += strlen (ppid_env_var_buffer);
525 *parg++ = '\0';
526 *parg = '\0';
527
528 /* Now create the process. */
529 if (!create_child (cmdname, cmdline, env, &pi))
530 {
531 errno = ENOEXEC;
532 goto EH_env;
533 }
534
535 return pi.dwProcessId;
536
537 EH_env:
538 free (env);
539 EH_cmdline:
540 free (cmdline);
541 EH_Fail:
542 return -1;
543}
544
545/* Emulate the select call
546 Wait for available input on any of the given rfds, or timeout if
547 a timeout is given and no input is detected
548 wfds and efds are not supported and must be NULL. */
549
550/* From ntterm.c */
551extern HANDLE keyboard_handle;
552/* From process.c */
553extern int proc_buffered_char[];
554
555int
22759c72
KH
556sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
557 EMACS_TIME *timeout)
6cdfb6e6
RS
558{
559 SELECT_TYPE orfds;
560 DWORD timeout_ms;
561 int i, nh, nr;
562 DWORD active;
563 child_process *cp, *cps[MAX_CHILDREN];
564 HANDLE wait_hnd[MAX_CHILDREN];
565
566 /* If the descriptor sets are NULL but timeout isn't, then just Sleep. */
567 if (rfds == NULL && wfds == NULL && efds == NULL && timeout != NULL)
568 {
22759c72
KH
569#ifdef HAVE_TIMEVAL
570 Sleep (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
571#else
6cdfb6e6 572 Sleep ((*timeout) * 1000);
22759c72 573#endif
6cdfb6e6
RS
574 return 0;
575 }
576
577 /* Otherwise, we only handle rfds, so fail otherwise. */
578 if (rfds == NULL || wfds != NULL || efds != NULL)
579 {
580 errno = EINVAL;
581 return -1;
582 }
583
584 orfds = *rfds;
585 FD_ZERO (rfds);
586 nr = 0;
587
588 /* Build a list of handles to wait on. */
589 nh = 0;
590 for (i = 0; i < nfds; i++)
591 if (FD_ISSET (i, &orfds))
592 {
593 if (i == 0)
594 {
595 /* Handle stdin specially */
596 wait_hnd[nh] = keyboard_handle;
597 cps[nh] = NULL;
598 nh++;
599
600 /* Check for any emacs-generated input in the queue since
601 it won't be detected in the wait */
602 if (detect_input_pending ())
603 {
604 FD_SET (i, rfds);
605 nr++;
606 }
607 }
608 else
609 {
610 /* Child process input */
611 cp = find_child_fd (i);
612 if (cp)
613 {
614#ifdef FULL_DEBUG
615 DebPrint (("select waiting on child %d fd %d\n",
616 cp-child_procs, i));
617#endif
618 wait_hnd[nh] = cp->char_avail;
619 cps[nh] = cp;
620 nh++;
621 }
622 else
623 {
624 /* Unable to find something to wait on for this fd, fail */
625 DebPrint (("select unable to find child process "
626 "for fd %ld\n", i));
627 nh = 0;
628 break;
629 }
630 }
631 }
632
633 /* Nothing to look for, so we didn't find anything */
634 if (nh == 0)
635 {
22759c72
KH
636 if (timeout)
637#ifdef HAVE_TIMEVAL
638 Sleep (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
639#else
640 Sleep ((*timeout) * 1000);
641#endif
6cdfb6e6
RS
642 return 0;
643 }
644
645 /* Check for immediate return without waiting */
646 if (nr > 0)
647 return nr;
648
649 /*
650 Wait for input
651 If a child process dies while this is waiting, its pipe will break
652 so the reader thread will signal an error condition, thus, the wait
653 will wake up
654 */
22759c72
KH
655#ifdef HAVE_TIMEVAL
656 timeout_ms = timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFINITE;
657#else
6cdfb6e6 658 timeout_ms = timeout ? *timeout*1000 : INFINITE;
22759c72 659#endif
6cdfb6e6
RS
660 active = WaitForMultipleObjects (nh, wait_hnd, FALSE, timeout_ms);
661 if (active == WAIT_FAILED)
662 {
663 DebPrint (("select.WaitForMultipleObjects (%d, %lu) failed with %lu\n",
664 nh, timeout_ms, GetLastError ()));
665 /* Is there a better error? */
666 errno = EBADF;
667 return -1;
668 }
669 else if (active == WAIT_TIMEOUT)
670 {
671 return 0;
672 }
673 else if (active >= WAIT_OBJECT_0 &&
674 active < WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS)
675 {
676 active -= WAIT_OBJECT_0;
677 }
678 else if (active >= WAIT_ABANDONED_0 &&
679 active < WAIT_ABANDONED_0+MAXIMUM_WAIT_OBJECTS)
680 {
681 active -= WAIT_ABANDONED_0;
682 }
683
684 if (cps[active] == NULL)
685 {
686 /* Keyboard input available */
687 FD_SET (0, rfds);
688 nr++;
689
690 /* This shouldn't be necessary, but apparently just setting the input
691 fd is not good enough for emacs */
692 read_input_waiting ();
693 }
694 else
695 {
696 /* Child process */
697 cp = cps[active];
698
699 /* If status is FALSE the read failed so don't report input */
700 if (cp->status)
701 {
702 FD_SET (cp->fd, rfds);
703 proc_buffered_char[cp->fd] = cp->chr;
704 nr++;
705 }
706 else
707 {
708 /* The SIGCHLD handler will do a Wait so we know it won't
709 return until the process is dead
710 We force Wait to only wait for this process to avoid it
711 picking up other children that happen to be dead but that
712 we haven't noticed yet
713 SIG_DFL for SIGCHLD is ignore? */
714 if (sig_handlers[SIGCHLD] != SIG_DFL &&
715 sig_handlers[SIGCHLD] != SIG_IGN)
716 {
717#ifdef FULL_DEBUG
718 DebPrint (("select calling SIGCHLD handler for pid %d\n",
719 cp->pid));
720#endif
721 dead_child = cp;
722 sig_handlers[SIGCHLD](SIGCHLD);
723 dead_child = NULL;
724 }
725
726 /* Clean up the child process entry in the table */
727 remove_child (cp);
728 }
729 }
730 return nr;
731}
732
733/*
734 Substitute for certain kill () operations
735 */
736int
737win32_kill_process (int pid, int sig)
738{
739 child_process *cp;
740
741 /* Only handle signals that will result in the process dying */
742 if (sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP)
743 {
744 errno = EINVAL;
745 return -1;
746 }
747
748 cp = find_child_pid (pid);
749 if (cp == NULL)
750 {
751 DebPrint (("win32_kill_process didn't find a child with pid %lu\n", pid));
752 errno = ECHILD;
753 return -1;
754 }
755
756 if (sig == SIGINT)
757 {
758 /* Fake Ctrl-Break. */
759 if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid))
760 {
761 DebPrint (("win32_kill_process.GenerateConsoleCtrlEvent return %d "
762 "for pid %lu\n", GetLastError (), pid));
763 errno = EINVAL;
764 return -1;
765 }
766 }
767 else
768 {
769 /* Kill the process. On Win32 this doesn't kill child processes
770 so it doesn't work very well for shells which is why it's
771 not used in every case. */
772 if (!TerminateProcess (cp->process, 0xff))
773 {
774 DebPrint (("win32_kill_process.TerminateProcess returned %d "
775 "for pid %lu\n", GetLastError (), pid));
776 errno = EINVAL;
777 return -1;
778 }
779 }
780 return 0;
781}
782
783/* If the channel is a pipe this read might block since we don't
784 know how many characters are available, so check and read only
785 what's there
786 We also need to wake up the reader thread once we've read our data. */
787int
788read_child_output (int fd, char *buf, int max)
789{
790 HANDLE h;
791 int to_read, nchars;
792 DWORD waiting;
793 child_process *cp;
794
795 h = (HANDLE)_get_osfhandle (fd);
796 if (GetFileType (h) == FILE_TYPE_PIPE)
797 {
798 PeekNamedPipe (h, NULL, 0, NULL, &waiting, NULL);
799 to_read = min (waiting, (DWORD)max);
800 }
801 else
802 to_read = max;
803
804 /* Use read to get CRLF translation */
805 nchars = read (fd, buf, to_read);
806
807 if (GetFileType (h) == FILE_TYPE_PIPE)
808 {
809 /* Wake up the reader thread
810 for this process */
811 cp = find_child_fd (fd);
812 if (cp)
813 {
814 if (!SetEvent (cp->char_consumed))
815 DebPrint (("read_child_output.SetEvent failed with "
816 "%lu for fd %ld\n", GetLastError (), fd));
817 }
818 else
819 DebPrint (("read_child_output couldn't find a child with fd %d\n",
820 fd));
821 }
822
823 return nchars;
824}