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