Mercurial > emacs
annotate src/w32proc.c @ 13043:2072d3ab4119
Moved stuff to other files.
author | Edward M. Reingold <reingold@emr.cs.iit.edu> |
---|---|
date | Thu, 21 Sep 1995 02:45:33 +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 } |