Hang on to child handle after signalling SIGTERM
authorJan Dubois <jand@activestate.com>
Tue, 15 Mar 2011 23:53:00 +0000 (16:53 -0700)
committerJan Dubois <jand@activestate.com>
Wed, 16 Mar 2011 00:14:16 +0000 (17:14 -0700)
This is a refinement of commit 3aa0ac5aa.  We still want to hang on
to the mapping between pseudo-process and thread handle, so that we
can still waitpid() after signalling SIGTERM. We just don't want to
wait implicitly on the signalled process anymore.

t/op/fork.t
win32/perlhost.h
win32/win32.c
win32/win32.h

index b74da8b..fbff8fb 100644 (file)
@@ -463,3 +463,23 @@ system $^X,  "-e", "if (\$pid=fork){kill(9, \$pid)} else {sleep 5}";
 print $?>>8, "\n";
 EXPECT
 0
+########
+# Windows fork() emulation: can we still waitpid() after signalling SIGTERM?
+$|=1;
+if (my $pid = fork) {
+    sleep 1;
+    print "1\n";
+    kill 'TERM', $pid;
+    waitpid($pid, 0);
+    print "4\n";
+}
+else {
+    $SIG{TERM} = sub { print "2\n" };
+    sleep 3;
+    print "3\n";
+}
+EXPECT
+1
+2
+3
+4
index 70a2f65..0240044 100644 (file)
@@ -1877,6 +1877,7 @@ PerlProcFork(struct IPerlProc* piPerl)
     }
     w32_pseudo_child_handles[w32_num_pseudo_children] = handle;
     w32_pseudo_child_pids[w32_num_pseudo_children] = id;
+    w32_pseudo_child_sigterm[w32_num_pseudo_children] = 0;
     ++w32_num_pseudo_children;
 #  endif
     return -(int)id;
index b8bb5bb..cffd2b5 100644 (file)
@@ -1177,9 +1177,33 @@ remove_dead_pseudo_process(long child)
             (w32_num_pseudo_children-child-1), DWORD);
        Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
             (w32_num_pseudo_children-child-1), HWND);
+       Move(&w32_pseudo_child_sigterm[child+1], &w32_pseudo_child_sigterm[child],
+            (w32_num_pseudo_children-child-1), char);
        w32_num_pseudo_children--;
     }
 }
+
+void
+win32_wait_for_children(pTHX)
+{
+    if (w32_pseudo_children && w32_num_pseudo_children) {
+        long child = 0;
+        long count = 0;
+        HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+
+        for (child = 0; child < w32_num_pseudo_children; ++child) {
+            if (!w32_pseudo_child_sigterm[child])
+                handles[count++] = w32_pseudo_child_handles[child];
+        }
+        /* XXX should use MsgWaitForMultipleObjects() to continue
+         * XXX processing messages while we wait.
+         */
+        WaitForMultipleObjects(count, handles, TRUE, INFINITE);
+
+        while (w32_num_pseudo_children)
+            CloseHandle(w32_pseudo_child_handles[--w32_num_pseudo_children]);
+    }
+}
 #endif
 
 static int
@@ -1316,7 +1340,7 @@ win32_kill(int pid, int sig)
                          */
                         if (sig == SIGTERM) {
                             Sleep(0);
-                            remove_dead_pseudo_process(child);
+                            w32_pseudo_child_sigterm[child] = 1;
                         }
                         /* It might be us ... */
                         PERL_ASYNC_CHECK();
index 65d6d31..204a380 100644 (file)
@@ -443,6 +443,7 @@ typedef struct {
     DWORD      pids[MAXIMUM_WAIT_OBJECTS];
     HANDLE     handles[MAXIMUM_WAIT_OBJECTS];
     HWND       message_hwnds[MAXIMUM_WAIT_OBJECTS];
+    char        sigterm[MAXIMUM_WAIT_OBJECTS];
 } pseudo_child_tab;
 #endif
 
@@ -488,6 +489,7 @@ DllExport int win32_async_check(pTHX);
 #define w32_pseudo_child_pids          (w32_pseudo_children->pids)
 #define w32_pseudo_child_handles       (w32_pseudo_children->handles)
 #define w32_pseudo_child_message_hwnds (w32_pseudo_children->message_hwnds)
+#define w32_pseudo_child_sigterm       (w32_pseudo_children->sigterm)
 #define w32_internal_host              (PL_sys_intern.internal_host)
 #define w32_timerid                    (PL_sys_intern.timerid)
 #define w32_message_hwnd               (PL_sys_intern.message_hwnd)
@@ -503,17 +505,8 @@ DllExport int win32_async_check(pTHX);
 #define w32_showwindow (PL_sys_intern.thr_intern.Wshowwindow)
 
 #ifdef USE_ITHREADS
-#  define PERL_WAIT_FOR_CHILDREN \
-    STMT_START {                                                       \
-       if (w32_pseudo_children && w32_num_pseudo_children) {           \
-           long children = w32_num_pseudo_children;                    \
-           WaitForMultipleObjects(children,                            \
-                                  w32_pseudo_child_handles,            \
-                                  TRUE, INFINITE);                     \
-           while (children)                                            \
-               CloseHandle(w32_pseudo_child_handles[--children]);      \
-       }                                                               \
-    } STMT_END
+void win32_wait_for_children(pTHX);
+#  define PERL_WAIT_FOR_CHILDREN win32_wait_for_children(aTHX)
 #endif
 
 /* IO.xs and POSIX.xs define PERLIO_NOT_STDIO to 1 */