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