make-w32
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: WINDOWS32 "Signal 127" due to a path in quotes bug


From: Eli Zaretskii
Subject: Re: WINDOWS32 "Signal 127" due to a path in quotes bug
Date: Sat, 06 Aug 2005 17:31:14 +0300

> Date: Mon, 01 Aug 2005 00:09:54 +0100
> From: "J. Grant" <address@hidden>
> CC: address@hidden
> 
> 1) Testing on Debian GNU/Linux
> 
> $ make -f makefile_sig.mak -j8
> <snip>
> 15299
> 15300
> make: *** [temp1] Interrupt
> make: *** [temp2] Interrupt

Yep, I see the same on a Debian box, except that I don't see those
15XXX numbers.  Where are they from? did you run a Makefile that's
different from what you sent? was this with a version of Make other
than 3.81beta3?

> MSYS, with MSVC build:
> 
> make -f makefile_sig.mak -j8
> 
> 15299
> 15300
> 
> rxvt.exe
>     sh.exe
>       make.exe
>          main.exe
>          main.exe
> 
> Pressing <ctrl> + C kills make.exe.  So main.exe and main.exe continue
> on their own, sh and rxvt are broken, and have to be killed and restarted.

I cannot reproduce this, but I don't have MSYS and rxvt installed.  In
particular, I don't see make.exe killed, but its children still
running.  Can you see what happens when you invoke the same command,
but outside rxvt/sh?  I.e., if you invoke Make from the stock Windows
Command Prompt window running cmd.exe?

> would it be expected that the <ctrl>+c signal would not be passed to the
> launched process?

In general, Ctrl-C is documented on Windows to be passed to all the
programs that are attached to the console which has the focus when
Ctrl-C is hit.  For the precise Microsoft language and some pointers
to related functions, see:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getexitcodeprocess.asp

> 2) Using todays CVS source on an MSCV build I experienced this:
> 
> C:\msys\1.0\home\now3d>make -f makefile_sig.mak -j2
> main
> main
> counting:
> counting:
> make: *** [temp1] Error -1073741510make:
> *** [temp2] Error -1073741510
> 
> 
> Is the odd exit value just because my simple C test program does not
> handle <ctrl>+C ?

No, it's a bug in Make's w32-specific code.  See the patches below.
In a nutshell, this special value is returned when the subordinate
program was interrupted by Ctrl-C; sub_proc.c should note that and set
pproc->signal accordingly.

I also found another serious problem with the current w32 code.  It
doesn't take into consideration the fact that (as the above URL spells
out), when Ctrl-C is hit, Windows creates a new thread in the
application to handle the signal.  This causes Make to suddenly become
multithreaded, unlike on Posix platforms.  The two threads each call
the function reap_children in a loop, which create ``interesting''
race conditions.  You can see this even without parallelism: just
invoke Make without -j8, but with --debug=v,j and watch the strange
reports about "Live child" even after the interrupt was already
received and the losing child reaped and removed from the chain.  I
fixed that (in the patches below) by manually suspending the main
thread when the signal handler is invoked, because that's what happens
on Posix platforms.

After applying the patches below, I see the same output on both Debian
GNU/Linux and Windows XP.

The next problem to attack would be the other signals: Ctrl-BREAK
first and foremost, then SIGSEGV and SIGFPE.  When I have time...

Here are the patches I suggest to fix the problems with SIGINT.  I
tested them only in the MinGW build running from cmd.exe, so testing
in other environment and with other compilers is welcome.

2005-08-06  Eli Zaretskii  <address@hidden>

        * w32/subproc/sub_proc.c: Include signal.h.
        (process_pipe_io, process_file_io): Pass a pointer to a local
        DWORD variable to GetExitCodeProcess.  If the exit code is
        CONTROL_C_EXIT, put SIGINT into pproc->signal.

        * job.c [WINDOWS32]: Include windows.h.
        (main_thread) [WINDOWS32]: New global variable.
        (reap_children) [WINDOWS32]: Get the handle for the main thread
        and store it in main_thread.

        * commands.c [WINDOWS32]: Include windows.h and w32err.h.
        (fatal_error_signal) [WINDOWS32]: Suspend the main thread before
        doing anything else.  When we are done, close the main thread
        handle and exit with status 130.


--- commands.c~1        2005-03-04 16:52:32.000000000 +0200
+++ commands.c  2005-08-06 15:59:15.770000000 +0300
@@ -23,6 +23,10 @@ Boston, MA 02111-1307, USA.  */
 #include "variable.h"
 #include "job.h"
 #include "commands.h"
+#ifdef WINDOWS32
+#include <windows.h>
+#include "w32err.h"
+#endif
 
 #if VMS
 # define FILE_LIST_SEPARATOR ','
@@ -420,6 +424,27 @@ fatal_error_signal (int sig)
 
   exit (10);
 #else /* not Amiga */
+#ifdef WINDOWS32
+  extern HANDLE main_thread;
+
+  /* Windows creates a sperate thread for handling Ctrl+C, so we need
+     to suspend the main thread, or else we will have race conditions
+     when both threads call reap_children.  */
+  if (main_thread)
+    {
+      DWORD susp_count = SuspendThread (main_thread);
+
+      if (susp_count != 0)
+       fprintf (stderr, "SuspendThread: suspend count = %ld\n", susp_count);
+      else if (susp_count == (DWORD)-1)
+       {
+         DWORD ierr = GetLastError ();
+
+         fprintf (stderr, "SuspendThread: error %ld: %s\n",
+                  ierr, map_windows32_error_to_string (ierr));
+       }
+    }
+#endif
   handling_fatal_signal = 1;
 
   /* Set the handling for this signal to the default.
@@ -482,8 +507,11 @@ fatal_error_signal (int sig)
 #endif
 
 #ifdef WINDOWS32
-  /* Cannot call W32_kill with a pid (it needs a handle) */
-  exit (EXIT_FAILURE);
+  if (main_thread)
+    CloseHandle (main_thread);
+  /* Cannot call W32_kill with a pid (it needs a handle).  The exit
+     status of 130 emulates what happens in Bash.  */
+  exit (130);
 #else
   /* Signal the same code; this time it will really be fatal.  The signal
      will be unblocked when we return and arrive then to kill us.  */

--- job.c~1     2005-07-30 16:57:16.755000000 +0300
+++ job.c       2005-08-06 17:14:42.691875000 +0300
@@ -33,10 +33,12 @@ Boston, MA 02111-1307, USA.  */
 
 /* Default shell to use.  */
 #ifdef WINDOWS32
+#include <windows.h>
 
 char *default_shell = "sh.exe";
 int no_default_sh_exe = 1;
 int batch_mode_shell = 1;
+HANDLE main_thread;
 
 #elif defined (_AMIGA)
 
@@ -611,10 +613,30 @@ reap_children (int block, int err)
           {
             HANDLE hPID;
             int err;
+            HANDLE hcTID, hcPID;
             exit_code = 0;
             exit_sig = 0;
             coredump = 0;
 
+            /* Record the thread ID of the main process, so that we
+               could suspend it in the signal handler.  */
+            if (!main_thread)
+              {
+                hcTID = GetCurrentThread ();
+                hcPID = GetCurrentProcess ();
+                if (!DuplicateHandle (hcPID, hcTID, hcPID, &main_thread, 0,
+                                      FALSE, DUPLICATE_SAME_ACCESS))
+                  {
+                    DWORD e = GetLastError ();
+                    fprintf(stderr,
+                            "Determine main thread ID (Error %ld: %s)\n",
+                            e, map_windows32_error_to_string(e));
+                  }
+                else
+                  DB (DB_VERBOSE, ("Main thread handle = 0x%08lx\n",
+                                   (unsigned long)main_thread));
+              }
+
             /* wait for anything to finish */
             hPID = process_wait_for_any();
             if (hPID)

--- w32/subproc/sub_proc.c~     2005-06-27 21:40:56.000000000 +0300
+++ w32/subproc/sub_proc.c      2005-08-06 16:45:22.941875000 +0300
@@ -1,6 +1,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <process.h>  /* for msvc _beginthreadex, _endthreadex */
+#include <signal.h>
 #include <windows.h>
 
 #include "sub_proc.h"
@@ -762,7 +764,13 @@ process_pipe_io(
 
                } else if (ready_hand == childhand) {
 
-                       GetExitCodeResult = GetExitCodeProcess(childhand, 
(DWORD*)&pproc->exit_code);
+                       DWORD ierr;
+                       GetExitCodeResult = GetExitCodeProcess(childhand, 
&ierr);
+                       if (ierr == CONTROL_C_EXIT) {
+                               pproc->signal = SIGINT;
+                       } else {
+                               pproc->exit_code = ierr;
+                       }
                        if (GetExitCodeResult == FALSE) {
                                pproc->last_err = GetLastError();
                                pproc->lerrno = E_SCALL;
@@ -811,6 +819,7 @@ process_file_io(
        HANDLE childhand;
        DWORD wait_return;
        BOOL GetExitCodeResult;
+       DWORD ierr;
 
        if (proc == NULL)
                pproc = process_wait_for_any_private();
@@ -854,7 +863,12 @@ process_file_io(
                goto done2;
        }
 
-       GetExitCodeResult = GetExitCodeProcess(childhand, 
(DWORD*)&pproc->exit_code);
+       GetExitCodeResult = GetExitCodeProcess(childhand, &ierr);
+       if (ierr == CONTROL_C_EXIT) {
+               pproc->signal = SIGINT;
+       } else {
+               pproc->exit_code = ierr;
+       }
        if (GetExitCodeResult == FALSE) {
                pproc->last_err = GetLastError();
                pproc->lerrno = E_SCALL;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]