comparison src/process-nt.c @ 371:cc15677e0335 r21-2b1

Import from CVS: tag r21-2b1
author cvs
date Mon, 13 Aug 2007 11:03:08 +0200
parents 972bbb6d6ca2
children 6240c7796c7a
comparison
equal deleted inserted replaced
370:bd866891f083 371:cc15677e0335
36 #include <shellapi.h> 36 #include <shellapi.h>
37 #include <signal.h> 37 #include <signal.h>
38 #ifdef HAVE_SOCKETS 38 #ifdef HAVE_SOCKETS
39 #include <winsock.h> 39 #include <winsock.h>
40 #endif 40 #endif
41
42 /* Arbitrary size limit for code fragments passed to run_in_other_process */
43 #define FRAGMENT_CODE_SIZE 32
44 41
45 /* Bound by winnt.el */ 42 /* Bound by winnt.el */
46 Lisp_Object Qnt_quote_process_args; 43 Lisp_Object Qnt_quote_process_args;
47 44
48 /* Implemenation-specific data. Pointed to by Lisp_Process->process_data */ 45 /* Implemenation-specific data. Pointed to by Lisp_Process->process_data */
144 ResumeThread (pmc->h_thread); 141 ResumeThread (pmc->h_thread);
145 } 142 }
146 143
147 /* 144 /*
148 * Run ROUTINE in the context of process determined by H_PROCESS. The 145 * Run ROUTINE in the context of process determined by H_PROCESS. The
149 * routine is passed the address of DATA as parameter. The ROUTINE must 146 * routine is passed the address of DATA as parameter. CODE_END is the
150 * not be longer than ROUTINE_CODE_SIZE bytes. DATA_SIZE is the size of 147 * address immediately after ROUTINE's code. DATA_SIZE is the size of
151 * DATA structure. 148 * DATA structure.
152 * 149 *
153 * Note that the code must be positionally independent, and compiled 150 * Note that the code must be positionally independent, and compiled
154 * without stack checks (they cause implicit calls into CRT so will 151 * without stack checks (they cause implicit calls into CRT so will
155 * fail). DATA should not refer any data in calling process, as both 152 * fail). DATA should not refer any data in calling process, as both
158 * 155 *
159 * Return the value returned by ROUTINE, or (DWORD)-1 if call failed. 156 * Return the value returned by ROUTINE, or (DWORD)-1 if call failed.
160 */ 157 */
161 static DWORD 158 static DWORD
162 run_in_other_process (HANDLE h_process, 159 run_in_other_process (HANDLE h_process,
163 LPTHREAD_START_ROUTINE routine, 160 LPTHREAD_START_ROUTINE routine, LPVOID code_end,
164 LPVOID data, size_t data_size) 161 LPVOID data, size_t data_size)
165 { 162 {
166 process_memory pm; 163 process_memory pm;
167 CONST size_t code_size = FRAGMENT_CODE_SIZE; 164 size_t code_size = (LPBYTE)code_end - (LPBYTE)routine;
168 /* Need at most 3 extra bytes of memory, for data alignment */ 165 /* Need at most 3 extra bytes of memory, for data alignment */
169 size_t total_size = code_size + data_size + 3; 166 size_t total_size = code_size + data_size + 3;
170 LPVOID remote_data; 167 LPVOID remote_data;
171 HANDLE h_thread; 168 HANDLE h_thread;
172 DWORD dw_unused; 169 DWORD dw_unused;
224 * We handle the following signals: 221 * We handle the following signals:
225 * 222 *
226 * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess 223 * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess
227 * executed by the remote process 224 * executed by the remote process
228 * SIGINT - The remote process is sent CTRL_BREAK_EVENT 225 * SIGINT - The remote process is sent CTRL_BREAK_EVENT
229 *
230 * The MSVC5.0 compiler feels free to re-order functions within a
231 * compilation unit, so we have no way of finding out the size of the
232 * following functions. Therefore these functions must not be larger than
233 * FRAGMENT_CODE_SIZE.
234 */ 226 */
235 227
236 /* 228 /*
237 * Sending SIGKILL 229 * Sending SIGKILL
238 */ 230 */
244 static DWORD WINAPI 236 static DWORD WINAPI
245 sigkill_proc (sigkill_data* data) 237 sigkill_proc (sigkill_data* data)
246 { 238 {
247 (*data->adr_ExitProcess)(255); 239 (*data->adr_ExitProcess)(255);
248 return 1; 240 return 1;
241 }
242
243 /* Watermark in code space */
244 static void
245 sigkill_code_end (void)
246 {
249 } 247 }
250 248
251 /* 249 /*
252 * Sending break or control c 250 * Sending break or control c
253 */ 251 */
261 sigint_proc (sigint_data* data) 259 sigint_proc (sigint_data* data)
262 { 260 {
263 return (*data->adr_GenerateConsoleCtrlEvent) (data->event, 0); 261 return (*data->adr_GenerateConsoleCtrlEvent) (data->event, 0);
264 } 262 }
265 263
264 /* Watermark in code space */
265 static void
266 sigint_code_end (void)
267 {
268 }
269
266 /* 270 /*
267 * Enabling signals 271 * Enabling signals
268 */ 272 */
269 typedef struct 273 typedef struct
270 { 274 {
274 static DWORD WINAPI 278 static DWORD WINAPI
275 sig_enable_proc (sig_enable_data* data) 279 sig_enable_proc (sig_enable_data* data)
276 { 280 {
277 (*data->adr_SetConsoleCtrlHandler) (NULL, FALSE); 281 (*data->adr_SetConsoleCtrlHandler) (NULL, FALSE);
278 return 1; 282 return 1;
283 }
284
285 /* Watermark in code space */
286 static void
287 sig_enable_code_end (void)
288 {
279 } 289 }
280 290
281 /* 291 /*
282 * Send signal SIGNO to process H_PROCESS. 292 * Send signal SIGNO to process H_PROCESS.
283 * Return nonzero if successful. 293 * Return nonzero if successful.
304 case SIGHUP: 314 case SIGHUP:
305 { 315 {
306 sigkill_data d; 316 sigkill_data d;
307 d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess"); 317 d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess");
308 assert (d.adr_ExitProcess); 318 assert (d.adr_ExitProcess);
309 retval = run_in_other_process (h_process, sigkill_proc, 319 retval = run_in_other_process (h_process,
320 sigkill_proc, sigkill_code_end,
310 &d, sizeof (d)); 321 &d, sizeof (d));
311 break; 322 break;
312 } 323 }
313 case SIGINT: 324 case SIGINT:
314 { 325 {
315 sigint_data d; 326 sigint_data d;
316 d.adr_GenerateConsoleCtrlEvent = 327 d.adr_GenerateConsoleCtrlEvent =
317 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); 328 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent");
318 assert (d.adr_GenerateConsoleCtrlEvent); 329 assert (d.adr_GenerateConsoleCtrlEvent);
319 d.event = CTRL_C_EVENT; 330 d.event = CTRL_C_EVENT;
320 retval = run_in_other_process (h_process, sigint_proc, 331 retval = run_in_other_process (h_process,
332 sigint_proc, sigint_code_end,
321 &d, sizeof (d)); 333 &d, sizeof (d));
322 break; 334 break;
323 } 335 }
324 default: 336 default:
325 assert (0); 337 assert (0);
339 351
340 assert (h_kernel != NULL); 352 assert (h_kernel != NULL);
341 d.adr_SetConsoleCtrlHandler = 353 d.adr_SetConsoleCtrlHandler =
342 GetProcAddress (h_kernel, "SetConsoleCtrlHandler"); 354 GetProcAddress (h_kernel, "SetConsoleCtrlHandler");
343 assert (d.adr_SetConsoleCtrlHandler); 355 assert (d.adr_SetConsoleCtrlHandler);
344 run_in_other_process (h_process, sig_enable_proc, 356 run_in_other_process (h_process,
357 sig_enable_proc, sig_enable_code_end,
345 &d, sizeof (d)); 358 &d, sizeof (d));
346 } 359 }
347 360
348 #pragma warning (default : 4113) 361 #pragma warning (default : 4113)
349 362
401 * The method must return PID of the new proces, a (positive??? ####) number 414 * The method must return PID of the new proces, a (positive??? ####) number
402 * which fits into Lisp_Int. No return value indicates an error, the method 415 * which fits into Lisp_Int. No return value indicates an error, the method
403 * must signal an error instead. 416 * must signal an error instead.
404 */ 417 */
405 418
419 /* #### This function completely ignores Vprocess_environment */
420
406 static void 421 static void
407 signal_cannot_launch (Lisp_Object image_file, DWORD err) 422 signal_cannot_launch (Lisp_Object image_file, DWORD err)
408 { 423 {
409 mswindows_set_errno (err); 424 mswindows_set_errno (err);
410 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno)); 425 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno));
413 static int 428 static int
414 nt_create_process (struct Lisp_Process *p, 429 nt_create_process (struct Lisp_Process *p,
415 Lisp_Object *argv, int nargv, 430 Lisp_Object *argv, int nargv,
416 Lisp_Object program, Lisp_Object cur_dir) 431 Lisp_Object program, Lisp_Object cur_dir)
417 { 432 {
418 HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr; 433 HANDLE hmyshove, hmyslurp, hprocin, hprocout;
419 LPTSTR command_line; 434 LPTSTR command_line;
420 BOOL do_io, windowed; 435 BOOL do_io, windowed;
421 char *proc_env;
422 436
423 /* Find out whether the application is windowed or not */ 437 /* Find out whether the application is windowed or not */
424 { 438 {
425 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most 439 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most
426 errors. This leads to bogus error message. */ 440 errors. This leads to bogus error message. */
464 sa.lpSecurityDescriptor = NULL; 478 sa.lpSecurityDescriptor = NULL;
465 479
466 CreatePipe (&hprocin, &hmyshove, &sa, 0); 480 CreatePipe (&hprocin, &hmyshove, &sa, 0);
467 CreatePipe (&hmyslurp, &hprocout, &sa, 0); 481 CreatePipe (&hmyslurp, &hprocout, &sa, 0);
468 482
469 /* Duplicate the stdout handle for use as stderr */
470 DuplicateHandle(GetCurrentProcess(), hprocout, GetCurrentProcess(), &hprocerr,
471 0, TRUE, DUPLICATE_SAME_ACCESS);
472
473 /* Stupid Win32 allows to create a pipe with *both* ends either 483 /* Stupid Win32 allows to create a pipe with *both* ends either
474 inheritable or not. We need process ends inheritable, and local 484 inheritable or not. We need process ends inheritable, and local
475 ends not inheritable. */ 485 ends not inheritable. */
476 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp, 486 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp,
477 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); 487 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
508 strcat (command_line, XSTRING_DATA (args_or_ret)); 518 strcat (command_line, XSTRING_DATA (args_or_ret));
509 519
510 UNGCPRO; /* args_or_ret */ 520 UNGCPRO; /* args_or_ret */
511 } 521 }
512 522
513 /* Set `proc_env' to a nul-separated array of the strings in
514 Vprocess_environment terminated by 2 nuls. */
515
516 {
517 extern int compare_env (const char **strp1, const char **strp2);
518 char **env;
519 REGISTER Lisp_Object tem;
520 REGISTER char **new_env;
521 REGISTER int new_length = 0, i, new_space;
522 char *penv;
523
524 for (tem = Vprocess_environment;
525 (CONSP (tem)
526 && STRINGP (XCAR (tem)));
527 tem = XCDR (tem))
528 new_length++;
529
530 /* new_length + 1 to include terminating 0. */
531 env = new_env = alloca_array (char *, new_length + 1);
532
533 /* Copy the Vprocess_environment strings into new_env. */
534 for (tem = Vprocess_environment;
535 (CONSP (tem)
536 && STRINGP (XCAR (tem)));
537 tem = XCDR (tem))
538 {
539 char **ep = env;
540 char *string = (char *) XSTRING_DATA (XCAR (tem));
541 /* See if this string duplicates any string already in the env.
542 If so, don't put it in.
543 When an env var has multiple definitions,
544 we keep the definition that comes first in process-environment. */
545 for (; ep != new_env; ep++)
546 {
547 char *p = *ep, *q = string;
548 while (1)
549 {
550 if (*q == 0)
551 /* The string is malformed; might as well drop it. */
552 goto duplicate;
553 if (*q != *p)
554 break;
555 if (*q == '=')
556 goto duplicate;
557 p++, q++;
558 }
559 }
560 *new_env++ = string;
561 duplicate: ;
562 }
563 *new_env = 0;
564
565 /* Sort the environment variables */
566 new_length = new_env - env;
567 qsort (env, new_length, sizeof (char *), compare_env);
568
569 /* Work out how much space to allocate */
570 new_space = 0;
571 for (i = 0; i < new_length; i++)
572 {
573 new_space += strlen(env[i]) + 1;
574 }
575 new_space++;
576
577 /* Allocate space and copy variables into it */
578 penv = proc_env = alloca(new_space);
579 for (i = 0; i < new_length; i++)
580 {
581 strcpy(penv, env[i]);
582 penv += strlen(env[i]) + 1;
583 }
584 *penv = 0;
585 }
586
587 /* Create process */ 523 /* Create process */
588 { 524 {
589 STARTUPINFO si; 525 STARTUPINFO si;
590 PROCESS_INFORMATION pi; 526 PROCESS_INFORMATION pi;
591 DWORD err; 527 DWORD err;
595 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE; 531 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE;
596 if (do_io) 532 if (do_io)
597 { 533 {
598 si.hStdInput = hprocin; 534 si.hStdInput = hprocin;
599 si.hStdOutput = hprocout; 535 si.hStdOutput = hprocout;
600 si.hStdError = hprocerr; 536 si.hStdError = hprocout;
601 si.dwFlags |= STARTF_USESTDHANDLES; 537 si.dwFlags |= STARTF_USESTDHANDLES;
602 } 538 }
603 539
604 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE, 540 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE,
605 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP 541 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP
606 | CREATE_SUSPENDED, 542 | CREATE_SUSPENDED,
607 proc_env, (char *) XSTRING_DATA (cur_dir), &si, &pi) 543 NULL, (char *) XSTRING_DATA (cur_dir), &si, &pi)
608 ? 0 : GetLastError ()); 544 ? 0 : GetLastError ());
609 545
610 if (do_io) 546 if (do_io)
611 { 547 {
612 /* These just have been inherited; we do not need a copy */ 548 /* These just have been inherited; we do not need a copy */
613 CloseHandle (hprocin); 549 CloseHandle (hprocin);
614 CloseHandle (hprocout); 550 CloseHandle (hprocout);
615 CloseHandle (hprocerr);
616 } 551 }
617 552
618 /* Handle process creation failure */ 553 /* Handle process creation failure */
619 if (err) 554 if (err)
620 { 555 {
697 struct Lisp_Process *p = XPROCESS (proc); 632 struct Lisp_Process *p = XPROCESS (proc);
698 633
699 /* use a reasonable-sized buffer (somewhere around the size of the 634 /* use a reasonable-sized buffer (somewhere around the size of the
700 stream buffer) so as to avoid inundating the stream with blocked 635 stream buffer) so as to avoid inundating the stream with blocked
701 data. */ 636 data. */
702 Bufbyte chunkbuf[128]; 637 Bufbyte chunkbuf[512];
703 Bytecount chunklen; 638 Bytecount chunklen;
704 639
705 while (1) 640 while (1)
706 { 641 {
707 int writeret; 642 int writeret;
708 643
709 chunklen = Lstream_read (lstream, chunkbuf, 128); 644 chunklen = Lstream_read (lstream, chunkbuf, 512);
710 if (chunklen <= 0) 645 if (chunklen <= 0)
711 break; /* perhaps should abort() if < 0? 646 break; /* perhaps should abort() if < 0?
712 This should never happen. */ 647 This should never happen. */
713 648
714 /* Lstream_write() will never successfully write less than the 649 /* Lstream_write() will never successfully write less than the