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