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