comparison src/process-nt.c @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents c6012109f545
children a86b2b5e0111
comparison
equal deleted inserted replaced
397:f4aeb21a5bad 398:74fd4e045ea6
30 #include "lstream.h" 30 #include "lstream.h"
31 #include "process.h" 31 #include "process.h"
32 #include "procimpl.h" 32 #include "procimpl.h"
33 #include "sysdep.h" 33 #include "sysdep.h"
34 34
35 #include <windows.h> 35 #ifndef __MINGW32__
36 #include <shellapi.h> 36 #include <shellapi.h>
37 #else
38 #include <errno.h>
39 #endif
37 #include <signal.h> 40 #include <signal.h>
38 #ifdef HAVE_SOCKETS 41 #ifdef HAVE_SOCKETS
39 #include <winsock.h> 42 #include <winsock.h>
40 #endif 43 #endif
41 44
47 50
48 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */ 51 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */
49 struct nt_process_data 52 struct nt_process_data
50 { 53 {
51 HANDLE h_process; 54 HANDLE h_process;
55 int need_enable_child_signals;
52 }; 56 };
53 57
54 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data)) 58 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data))
55 59
56 /*-----------------------------------------------------------------------*/ 60 /*-----------------------------------------------------------------------*/
58 /*-----------------------------------------------------------------------*/ 62 /*-----------------------------------------------------------------------*/
59 63
60 /* This one breaks process abstraction. Prototype is in console-msw.h, 64 /* This one breaks process abstraction. Prototype is in console-msw.h,
61 used by select_process method in event-msw.c */ 65 used by select_process method in event-msw.c */
62 HANDLE 66 HANDLE
63 get_nt_process_handle (struct Lisp_Process *p) 67 get_nt_process_handle (Lisp_Process *p)
64 { 68 {
65 return (NT_DATA (p)->h_process); 69 return (NT_DATA (p)->h_process);
66 } 70 }
67 71
68 /*-----------------------------------------------------------------------*/ 72 /*-----------------------------------------------------------------------*/
162 run_in_other_process (HANDLE h_process, 166 run_in_other_process (HANDLE h_process,
163 LPTHREAD_START_ROUTINE routine, 167 LPTHREAD_START_ROUTINE routine,
164 LPVOID data, size_t data_size) 168 LPVOID data, size_t data_size)
165 { 169 {
166 process_memory pm; 170 process_memory pm;
167 CONST size_t code_size = FRAGMENT_CODE_SIZE; 171 const size_t code_size = FRAGMENT_CODE_SIZE;
168 /* Need at most 3 extra bytes of memory, for data alignment */ 172 /* Need at most 3 extra bytes of memory, for data alignment */
169 size_t total_size = code_size + data_size + 3; 173 size_t total_size = code_size + data_size + 3;
170 LPVOID remote_data; 174 LPVOID remote_data;
171 HANDLE h_thread; 175 HANDLE h_thread;
172 DWORD dw_unused; 176 DWORD dw_unused;
304 case SIGHUP: 308 case SIGHUP:
305 { 309 {
306 sigkill_data d; 310 sigkill_data d;
307 d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess"); 311 d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess");
308 assert (d.adr_ExitProcess); 312 assert (d.adr_ExitProcess);
309 retval = run_in_other_process (h_process, sigkill_proc, 313 retval = run_in_other_process (h_process,
314 (LPTHREAD_START_ROUTINE)sigkill_proc,
310 &d, sizeof (d)); 315 &d, sizeof (d));
311 break; 316 break;
312 } 317 }
313 case SIGINT: 318 case SIGINT:
314 { 319 {
315 sigint_data d; 320 sigint_data d;
316 d.adr_GenerateConsoleCtrlEvent = 321 d.adr_GenerateConsoleCtrlEvent =
317 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); 322 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent");
318 assert (d.adr_GenerateConsoleCtrlEvent); 323 assert (d.adr_GenerateConsoleCtrlEvent);
319 d.event = CTRL_C_EVENT; 324 d.event = CTRL_C_EVENT;
320 retval = run_in_other_process (h_process, sigint_proc, 325 retval = run_in_other_process (h_process,
326 (LPTHREAD_START_ROUTINE)sigint_proc,
321 &d, sizeof (d)); 327 &d, sizeof (d));
322 break; 328 break;
323 } 329 }
324 default: 330 default:
325 assert (0); 331 assert (0);
339 345
340 assert (h_kernel != NULL); 346 assert (h_kernel != NULL);
341 d.adr_SetConsoleCtrlHandler = 347 d.adr_SetConsoleCtrlHandler =
342 GetProcAddress (h_kernel, "SetConsoleCtrlHandler"); 348 GetProcAddress (h_kernel, "SetConsoleCtrlHandler");
343 assert (d.adr_SetConsoleCtrlHandler); 349 assert (d.adr_SetConsoleCtrlHandler);
344 run_in_other_process (h_process, sig_enable_proc, 350 run_in_other_process (h_process, (LPTHREAD_START_ROUTINE)sig_enable_proc,
345 &d, sizeof (d)); 351 &d, sizeof (d));
346 } 352 }
347 353
348 #pragma warning (default : 4113) 354 #pragma warning (default : 4113)
349 355
366 /* 372 /*
367 * Allocate and initialize Lisp_Process->process_data 373 * Allocate and initialize Lisp_Process->process_data
368 */ 374 */
369 375
370 static void 376 static void
371 nt_alloc_process_data (struct Lisp_Process *p) 377 nt_alloc_process_data (Lisp_Process *p)
372 { 378 {
373 p->process_data = xnew_and_zero (struct nt_process_data); 379 p->process_data = xnew_and_zero (struct nt_process_data);
374 } 380 }
375 381
376 static void 382 static void
377 nt_finalize_process_data (struct Lisp_Process *p, int for_disksave) 383 nt_finalize_process_data (Lisp_Process *p, int for_disksave)
378 { 384 {
379 assert (!for_disksave); 385 assert (!for_disksave);
380 if (NT_DATA(p)->h_process) 386 if (NT_DATA(p)->h_process)
381 CloseHandle (NT_DATA(p)->h_process); 387 CloseHandle (NT_DATA(p)->h_process);
382 } 388 }
401 * The method must return PID of the new process, a (positive??? ####) number 407 * The method must return PID of the new process, a (positive??? ####) number
402 * which fits into Lisp_Int. No return value indicates an error, the method 408 * which fits into Lisp_Int. No return value indicates an error, the method
403 * must signal an error instead. 409 * must signal an error instead.
404 */ 410 */
405 411
406 /* #### This function completely ignores Vprocess_environment */
407
408 static void 412 static void
409 signal_cannot_launch (Lisp_Object image_file, DWORD err) 413 signal_cannot_launch (Lisp_Object image_file, DWORD err)
410 { 414 {
411 mswindows_set_errno (err); 415 mswindows_set_errno (err);
412 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno)); 416 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno));
413 } 417 }
414 418
415 static int 419 static int
416 nt_create_process (struct Lisp_Process *p, 420 nt_create_process (Lisp_Process *p,
417 Lisp_Object *argv, int nargv, 421 Lisp_Object *argv, int nargv,
418 Lisp_Object program, Lisp_Object cur_dir) 422 Lisp_Object program, Lisp_Object cur_dir)
419 { 423 {
420 HANDLE hmyshove, hmyslurp, hprocin, hprocout; 424 HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr;
421 LPTSTR command_line; 425 LPTSTR command_line;
422 BOOL do_io, windowed; 426 BOOL do_io, windowed;
427 char *proc_env;
423 428
424 /* Find out whether the application is windowed or not */ 429 /* Find out whether the application is windowed or not */
425 { 430 {
426 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most 431 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most
427 errors. This leads to bogus error message. */ 432 errors. This leads to bogus error message. */
465 sa.lpSecurityDescriptor = NULL; 470 sa.lpSecurityDescriptor = NULL;
466 471
467 CreatePipe (&hprocin, &hmyshove, &sa, 0); 472 CreatePipe (&hprocin, &hmyshove, &sa, 0);
468 CreatePipe (&hmyslurp, &hprocout, &sa, 0); 473 CreatePipe (&hmyslurp, &hprocout, &sa, 0);
469 474
475 /* Duplicate the stdout handle for use as stderr */
476 DuplicateHandle(GetCurrentProcess(), hprocout, GetCurrentProcess(), &hprocerr,
477 0, TRUE, DUPLICATE_SAME_ACCESS);
478
470 /* Stupid Win32 allows to create a pipe with *both* ends either 479 /* Stupid Win32 allows to create a pipe with *both* ends either
471 inheritable or not. We need process ends inheritable, and local 480 inheritable or not. We need process ends inheritable, and local
472 ends not inheritable. */ 481 ends not inheritable. */
473 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp, 482 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp,
474 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); 483 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
505 strcat (command_line, XSTRING_DATA (args_or_ret)); 514 strcat (command_line, XSTRING_DATA (args_or_ret));
506 515
507 UNGCPRO; /* args_or_ret */ 516 UNGCPRO; /* args_or_ret */
508 } 517 }
509 518
519 /* Set `proc_env' to a nul-separated array of the strings in
520 Vprocess_environment terminated by 2 nuls. */
521
522 {
523 extern int compare_env (const char **strp1, const char **strp2);
524 char **env;
525 REGISTER Lisp_Object tem;
526 REGISTER char **new_env;
527 REGISTER int new_length = 0, i, new_space;
528 char *penv;
529
530 for (tem = Vprocess_environment;
531 (CONSP (tem)
532 && STRINGP (XCAR (tem)));
533 tem = XCDR (tem))
534 new_length++;
535
536 /* new_length + 1 to include terminating 0. */
537 env = new_env = alloca_array (char *, new_length + 1);
538
539 /* Copy the Vprocess_environment strings into new_env. */
540 for (tem = Vprocess_environment;
541 (CONSP (tem)
542 && STRINGP (XCAR (tem)));
543 tem = XCDR (tem))
544 {
545 char **ep = env;
546 char *string = (char *) XSTRING_DATA (XCAR (tem));
547 /* See if this string duplicates any string already in the env.
548 If so, don't put it in.
549 When an env var has multiple definitions,
550 we keep the definition that comes first in process-environment. */
551 for (; ep != new_env; ep++)
552 {
553 char *p = *ep, *q = string;
554 while (1)
555 {
556 if (*q == 0)
557 /* The string is malformed; might as well drop it. */
558 goto duplicate;
559 if (*q != *p)
560 break;
561 if (*q == '=')
562 goto duplicate;
563 p++, q++;
564 }
565 }
566 *new_env++ = string;
567 duplicate: ;
568 }
569 *new_env = 0;
570
571 /* Sort the environment variables */
572 new_length = new_env - env;
573 qsort (env, new_length, sizeof (char *), compare_env);
574
575 /* Work out how much space to allocate */
576 new_space = 0;
577 for (i = 0; i < new_length; i++)
578 {
579 new_space += strlen(env[i]) + 1;
580 }
581 new_space++;
582
583 /* Allocate space and copy variables into it */
584 penv = proc_env = alloca(new_space);
585 for (i = 0; i < new_length; i++)
586 {
587 strcpy(penv, env[i]);
588 penv += strlen(env[i]) + 1;
589 }
590 *penv = 0;
591 }
592
510 /* Create process */ 593 /* Create process */
511 { 594 {
512 STARTUPINFO si; 595 STARTUPINFO si;
513 PROCESS_INFORMATION pi; 596 PROCESS_INFORMATION pi;
514 DWORD err; 597 DWORD err;
518 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE; 601 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE;
519 if (do_io) 602 if (do_io)
520 { 603 {
521 si.hStdInput = hprocin; 604 si.hStdInput = hprocin;
522 si.hStdOutput = hprocout; 605 si.hStdOutput = hprocout;
523 si.hStdError = hprocout; 606 si.hStdError = hprocerr;
524 si.dwFlags |= STARTF_USESTDHANDLES; 607 si.dwFlags |= STARTF_USESTDHANDLES;
525 } 608 }
526 609
527 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE, 610 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE,
528 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP 611 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP
529 | CREATE_SUSPENDED, 612 | CREATE_SUSPENDED,
530 NULL, (char *) XSTRING_DATA (cur_dir), &si, &pi) 613 proc_env, (char *) XSTRING_DATA (cur_dir), &si, &pi)
531 ? 0 : GetLastError ()); 614 ? 0 : GetLastError ());
532 615
533 if (do_io) 616 if (do_io)
534 { 617 {
535 /* These just have been inherited; we do not need a copy */ 618 /* These just have been inherited; we do not need a copy */
536 CloseHandle (hprocin); 619 CloseHandle (hprocin);
537 CloseHandle (hprocout); 620 CloseHandle (hprocout);
621 CloseHandle (hprocerr);
538 } 622 }
539 623
540 /* Handle process creation failure */ 624 /* Handle process creation failure */
541 if (err) 625 if (err)
542 { 626 {
559 /* Indicate as if the process has exited immediately. */ 643 /* Indicate as if the process has exited immediately. */
560 p->status_symbol = Qexit; 644 p->status_symbol = Qexit;
561 CloseHandle (pi.hProcess); 645 CloseHandle (pi.hProcess);
562 } 646 }
563 647
564 if (!windowed)
565 enable_child_signals (pi.hProcess);
566
567 ResumeThread (pi.hThread); 648 ResumeThread (pi.hThread);
568 CloseHandle (pi.hThread); 649 CloseHandle (pi.hThread);
569 650
570 /* Hack to support Windows 95 negative pids */ 651 /* Remember to enable child signals later if this is not a windowed
571 return ((int)pi.dwProcessId < 0 652 app. Can't do it right now because that screws up the MKS Toolkit
572 ? -(int)pi.dwProcessId : (int)pi.dwProcessId); 653 shell. */
654 if (!windowed)
655 {
656 NT_DATA(p)->need_enable_child_signals = 10;
657 kick_status_notify ();
658 }
659
660 return ((int)pi.dwProcessId);
573 } 661 }
574 } 662 }
575 663
576 /* 664 /*
577 * This method is called to update status fields of the process 665 * This method is called to update status fields of the process
580 * 668 *
581 * The method is called only for real child processes. 669 * The method is called only for real child processes.
582 */ 670 */
583 671
584 static void 672 static void
585 nt_update_status_if_terminated (struct Lisp_Process* p) 673 nt_update_status_if_terminated (Lisp_Process* p)
586 { 674 {
587 DWORD exit_code; 675 DWORD exit_code;
676
677 if (NT_DATA(p)->need_enable_child_signals > 1)
678 {
679 NT_DATA(p)->need_enable_child_signals -= 1;
680 kick_status_notify ();
681 }
682 else if (NT_DATA(p)->need_enable_child_signals == 1)
683 {
684 enable_child_signals(NT_DATA(p)->h_process);
685 NT_DATA(p)->need_enable_child_signals = 0;
686 }
687
588 if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code) 688 if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code)
589 && exit_code != STILL_ACTIVE) 689 && exit_code != STILL_ACTIVE)
590 { 690 {
591 p->tick++; 691 p->tick++;
592 p->core_dumped = 0; 692 p->core_dumped = 0;
614 unix_send_process... */ 714 unix_send_process... */
615 715
616 static void 716 static void
617 nt_send_process (Lisp_Object proc, struct lstream* lstream) 717 nt_send_process (Lisp_Object proc, struct lstream* lstream)
618 { 718 {
619 struct Lisp_Process *p = XPROCESS (proc); 719 volatile Lisp_Object vol_proc = proc;
720 Lisp_Process *volatile p = XPROCESS (proc);
620 721
621 /* use a reasonable-sized buffer (somewhere around the size of the 722 /* use a reasonable-sized buffer (somewhere around the size of the
622 stream buffer) so as to avoid inundating the stream with blocked 723 stream buffer) so as to avoid inundating the stream with blocked
623 data. */ 724 data. */
624 Bufbyte chunkbuf[128]; 725 Bufbyte chunkbuf[128];
625 Bytecount chunklen; 726 Bytecount chunklen;
626 727
627 while (1) 728 while (1)
628 { 729 {
629 int writeret; 730 ssize_t writeret;
630 731
631 chunklen = Lstream_read (lstream, chunkbuf, 128); 732 chunklen = Lstream_read (lstream, chunkbuf, 128);
632 if (chunklen <= 0) 733 if (chunklen <= 0)
633 break; /* perhaps should abort() if < 0? 734 break; /* perhaps should abort() if < 0?
634 This should never happen. */ 735 This should never happen. */
644 p->status_symbol = Qexit; 745 p->status_symbol = Qexit;
645 p->exit_code = ERROR_BROKEN_PIPE; 746 p->exit_code = ERROR_BROKEN_PIPE;
646 p->core_dumped = 0; 747 p->core_dumped = 0;
647 p->tick++; 748 p->tick++;
648 process_tick++; 749 process_tick++;
649 deactivate_process (proc); 750 deactivate_process (*((Lisp_Object *) (&vol_proc)));
650 error ("Broken pipe error sending to process %s; closed it", 751 error ("Broken pipe error sending to process %s; closed it",
651 XSTRING_DATA (p->name)); 752 XSTRING_DATA (p->name));
652 } 753 }
653 754
654 { 755 {
682 783
683 static void 784 static void
684 nt_kill_child_process (Lisp_Object proc, int signo, 785 nt_kill_child_process (Lisp_Object proc, int signo,
685 int current_group, int nomsg) 786 int current_group, int nomsg)
686 { 787 {
687 struct Lisp_Process *p = XPROCESS (proc); 788 Lisp_Process *p = XPROCESS (proc);
789
790 /* Enable child signals if necessary. This may lose the first
791 but it's better than nothing. */
792 if (NT_DATA(p)->need_enable_child_signals > 0)
793 {
794 enable_child_signals(NT_DATA(p)->h_process);
795 NT_DATA(p)->need_enable_child_signals = 0;
796 }
688 797
689 /* Signal error if SIGNO cannot be sent */ 798 /* Signal error if SIGNO cannot be sent */
690 validate_signal_number (signo); 799 validate_signal_number (signo);
691 800
692 /* Send signal */ 801 /* Send signal */
777 if (msg.message == XM_SOCKREPLY) 886 if (msg.message == XM_SOCKREPLY)
778 { 887 {
779 /* Ok, got an answer */ 888 /* Ok, got an answer */
780 if (WSAGETASYNCERROR(msg.lParam) == NO_ERROR) 889 if (WSAGETASYNCERROR(msg.lParam) == NO_ERROR)
781 success = 1; 890 success = 1;
891 else
892 {
893 warn_when_safe(Qstream, Qwarning,
894 "cannot get IP address for host \"%s\"",
895 XSTRING_DATA (host));
896 }
782 goto done; 897 goto done;
783 } 898 }
784 else if (msg.message == WM_TIMER && msg.wParam == SOCK_TIMER_ID) 899 else if (msg.message == WM_TIMER && msg.wParam == SOCK_TIMER_ID)
785 { 900 {
786 if (QUITP) 901 if (QUITP)
826 connection has no PID; you cannot signal it. All you can do is 941 connection has no PID; you cannot signal it. All you can do is
827 deactivate and close it via delete-process */ 942 deactivate and close it via delete-process */
828 943
829 static void 944 static void
830 nt_open_network_stream (Lisp_Object name, Lisp_Object host, Lisp_Object service, 945 nt_open_network_stream (Lisp_Object name, Lisp_Object host, Lisp_Object service,
831 Lisp_Object family, void** vinfd, void** voutfd) 946 Lisp_Object protocol, void** vinfd, void** voutfd)
832 { 947 {
833 struct sockaddr_in address; 948 struct sockaddr_in address;
834 SOCKET s; 949 SOCKET s;
835 int port; 950 int port;
836 int retval; 951 int retval;
837 952
838 CHECK_STRING (host); 953 CHECK_STRING (host);
839 954
840 if (!EQ (family, Qtcpip)) 955 if (!EQ (protocol, Qtcp))
841 error ("Unsupported protocol family \"%s\"", 956 error ("Unsupported protocol \"%s\"",
842 string_data (symbol_name (XSYMBOL (family)))); 957 string_data (symbol_name (XSYMBOL (protocol))));
843 958
844 if (INTP (service)) 959 if (INTP (service))
845 port = htons ((unsigned short) XINT (service)); 960 port = htons ((unsigned short) XINT (service));
846 else 961 else
847 { 962 {
860 if (s < 0) 975 if (s < 0)
861 report_file_error ("error creating socket", list1 (name)); 976 report_file_error ("error creating socket", list1 (name));
862 977
863 /* We don't want to be blocked on connect */ 978 /* We don't want to be blocked on connect */
864 { 979 {
865 unsigned int nonblock = 1; 980 unsigned long nonblock = 1;
866 ioctlsocket (s, FIONBIO, &nonblock); 981 ioctlsocket (s, FIONBIO, &nonblock);
867 } 982 }
868 983
869 retval = connect (s, (struct sockaddr *) &address, sizeof (address)); 984 retval = connect (s, (struct sockaddr *) &address, sizeof (address));
870 if (retval != NO_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) 985 if (retval != NO_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
871 goto connect_failed; 986 goto connect_failed;
872
873 /* Wait while connection is established */ 987 /* Wait while connection is established */
874 while (1) 988 while (1)
875 { 989 {
876 fd_set fdset; 990 fd_set fdset;
877 struct timeval tv; 991 struct timeval tv;
910 0, FALSE, DUPLICATE_SAME_ACCESS); 1024 0, FALSE, DUPLICATE_SAME_ACCESS);
911 return; 1025 return;
912 1026
913 connect_failed: 1027 connect_failed:
914 closesocket (s); 1028 closesocket (s);
1029 if (INTP (service)) {
1030 warn_when_safe(Qstream, Qwarning,
1031 "failure to open network stream to host \"%s\" for service \"%d\"",
1032 XSTRING_DATA (host),
1033 (unsigned short) XINT (service));
1034 }
1035 else {
1036 warn_when_safe(Qstream, Qwarning,
1037 "failure to open network stream to host \"%s\" for service \"%s\"",
1038 XSTRING_DATA (host),
1039 XSTRING_DATA (service));
1040 }
915 report_file_error ("connection failed", list2 (host, name)); 1041 report_file_error ("connection failed", list2 (host, name));
916 } 1042 }
917 1043
918 #endif 1044 #endif
919 1045