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