Commit | Line | Data |
---|---|---|
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 | ||
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. */ | |
22759c72 KH |
323 | |
324 | /* From callproc.c */ | |
325 | extern int synch_process_alive; | |
326 | extern int synch_process_retcode; | |
327 | ||
6cdfb6e6 RS |
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 | 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. */ | |
423 | char 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. */ | |
427 | int | |
428 | win32_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 */ | |
551 | extern HANDLE keyboard_handle; | |
552 | /* From process.c */ | |
553 | extern int proc_buffered_char[]; | |
554 | ||
555 | int | |
22759c72 KH |
556 | sys_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 | */ | |
736 | int | |
737 | win32_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. */ | |
787 | int | |
788 | read_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 | } |