OSDN Git Service

* child_info.h (CURR_CHILD_INFO_MAGIC): Update.
authorcgf <cgf>
Fri, 24 Dec 2004 18:31:22 +0000 (18:31 +0000)
committercgf <cgf>
Fri, 24 Dec 2004 18:31:22 +0000 (18:31 +0000)
(child_info::parent_wr_proc_pipe): Eliminate.
* pinfo.h (_pinfo::alert_parent): Move here from pinfo class.
(_pinfo::dup_proc_pipe): New method.
(_pinfo::sync_proc_pipe): Ditto.
* exceptions.cc (sig_handle_tty_stop): Reflect move of alert_parent.
* init.cc (dll_entry): Exit with status one if main process called ExitProcess.
* pinfo.cc (set_myself): Remove handling of parent_wr_proc_pipe.
(_pinfo::exit): Reflect move of alert_parent.  Set procinfo to NULL to flag
that we are exiting normally.  Always use exitcode when exiting
(although this could be a little racy).
(pinfo::init): Set default exit to SIGTERM.  This will be the exit code
reported if process is terminated.
(_pinfo::dup_proc_pipe): New function.
(pinfo::wait): Duplicate wr_proc_pipe to the right place.  Use dup_proc_pipe to
move the pipe to the child.
(_pinfo::sync_proc_pipe): New function.
(_pinfo::alert_parent): Move to _pinfo.  Make sure that wr_proc_pipe is ours
before using it.
* sigproc.cc (child_info::child_info): Remove handling of parent_wr_proc_pipe.
* spawn.cc (spawn_guts): Pass our wr_proc_pipe to the child when execing.
Ensure that exit code of cygwin process started from windows is correctly set.

winsup/cygwin/ChangeLog
winsup/cygwin/child_info.h
winsup/cygwin/exceptions.cc
winsup/cygwin/init.cc
winsup/cygwin/pinfo.cc
winsup/cygwin/pinfo.h
winsup/cygwin/sigproc.cc
winsup/cygwin/spawn.cc

index e2251d2..4e341a9 100644 (file)
@@ -1,3 +1,31 @@
+2004-12-24  Christopher Faylor  <cgf@timesys.com>
+
+       * child_info.h (CURR_CHILD_INFO_MAGIC): Update.
+       (child_info::parent_wr_proc_pipe): Eliminate.
+       * pinfo.h (_pinfo::alert_parent): Move here from pinfo class.
+       (_pinfo::dup_proc_pipe): New method.
+       (_pinfo::sync_proc_pipe): Ditto.
+       * exceptions.cc (sig_handle_tty_stop): Reflect move of alert_parent.
+       * init.cc (dll_entry): Exit with status one if main process called
+       ExitProcess.
+       * pinfo.cc (set_myself): Remove handling of parent_wr_proc_pipe.
+       (_pinfo::exit): Reflect move of alert_parent.  Set procinfo to NULL to
+       flag that we are exiting normally.  Always use exitcode when exiting
+       (although this could be a little racy).
+       (pinfo::init): Set default exit to SIGTERM.  This will be the exit code
+       reported if process is terminated.
+       (_pinfo::dup_proc_pipe): New function.
+       (pinfo::wait): Duplicate wr_proc_pipe to the right place.  Use
+       dup_proc_pipe to move the pipe to the child.
+       (_pinfo::sync_proc_pipe): New function.
+       (_pinfo::alert_parent): Move to _pinfo.  Make sure that wr_proc_pipe is
+       ours before using it.
+       * sigproc.cc (child_info::child_info): Remove handling of
+       parent_wr_proc_pipe.
+       * spawn.cc (spawn_guts): Pass our wr_proc_pipe to the child when
+       execing.  Ensure that exit code of cygwin process started from windows
+       is correctly set.
+
 2004-12-23  Pierre Humblet <pierre.humblet@ieee.org>
            Christopher Faylor  <cgf@timesys.com>
 
index 97cf455..33133d6 100644 (file)
@@ -29,7 +29,7 @@ enum child_info_types
 
 #define EXEC_MAGIC_SIZE sizeof(child_info)
 
-#define CURR_CHILD_INFO_MAGIC 0x17ad771aU
+#define CURR_CHILD_INFO_MAGIC 0xd079e02U
 
 /* NOTE: Do not make gratuitous changes to the names or organization of the
    below class.  The layout is checksummed to determine compatibility between
@@ -49,7 +49,6 @@ public:
   void *cygheap_max;
   DWORD cygheap_reserve_sz;
   HANDLE cygheap_h;
-  HANDLE parent_wr_proc_pipe;
   unsigned fhandler_union_cb;
   child_info (unsigned, child_info_types);
   ~child_info ();
index bc28cc8..9993ef4 100644 (file)
@@ -600,7 +600,7 @@ sig_handle_tty_stop (int sig)
     }
 
   myself->stopsig = sig;
-  myself.alert_parent (sig);
+  myself->alert_parent (sig);
   sigproc_printf ("process %d stopped by signal %d", myself->pid, sig);
   HANDLE w4[2];
   w4[0] = sigCONT;
@@ -610,7 +610,7 @@ sig_handle_tty_stop (int sig)
     case WAIT_OBJECT_0:
     case WAIT_OBJECT_0 + 1:
       reset_signal_arrived ();
-      myself.alert_parent (SIGCONT);
+      myself->alert_parent (SIGCONT);
       break;
     default:
       api_fatal ("WaitSingleObject failed, %E");
index 7ba0dc3..261b20b 100644 (file)
@@ -13,6 +13,7 @@ details. */
 #include "thread.h"
 #include "perprocess.h"
 #include "cygtls.h"
+#include "pinfo.h"
 
 int NO_COPY dynamically_loaded;
 static char *search_for = (char *) cygthread::stub;
@@ -126,6 +127,8 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
       dll_crt0_0 ();
       break;
     case DLL_PROCESS_DETACH:
+      if (myself)
+       myself->exitcode = 1 << 8;
       break;
     case DLL_THREAD_ATTACH:
       munge_threadfunc ();
index ec51c85..69a4380 100644 (file)
@@ -44,8 +44,6 @@ pinfo NO_COPY myself ((_pinfo *)&pinfo_dummy);        // Avoid myself != NULL checks
 void __stdcall
 set_myself (HANDLE h)
 {
-  extern child_info *child_proc_info;
-
   if (!h)
     cygheap->pid = cygwin_pid (GetCurrentProcessId ());
   myself.init (cygheap->pid, PID_IN_USE | PID_MYSELF, h);
@@ -68,19 +66,11 @@ set_myself (HANDLE h)
     }
   else if (!myself->wr_proc_pipe)
     myself->start_time = time (NULL); /* Register our starting time. */
-  else
+  else if (cygheap->pid_handle)
     {
-      /* We've inherited the parent's wr_proc_pipe.  We don't need it,
-        so close it. */
-      if (child_proc_info->parent_wr_proc_pipe)
-       CloseHandle (child_proc_info->parent_wr_proc_pipe);
-      if (cygheap->pid_handle)
-       {
-         ForceCloseHandle (cygheap->pid_handle);
-         cygheap->pid_handle = NULL;
-       }
+      ForceCloseHandle (cygheap->pid_handle);
+      cygheap->pid_handle = NULL;
     }
-# undef child_proc_info
   return;
 }
 
@@ -117,9 +107,9 @@ _pinfo::exit (UINT n, bool norecord)
   exit_state = ES_FINAL;
   cygthread::terminate ();
   if (norecord)
-    sigproc_terminate ();      /* Just terminate signal and process stuff */
+    sigproc_terminate ();              /* Just terminate signal and process stuff */
   else
-    exitcode = n;              /* We're really exiting.  Record the UNIX exit code. */
+    exitcode = n;                      /* We're really exiting.  Record the UNIX exit code. */
 
   if (this)
     {
@@ -135,7 +125,7 @@ _pinfo::exit (UINT n, bool norecord)
          /* We could just let this happen automatically when the process
             exits but this should gain us a microsecond or so by notifying
             the parent early.  */
-         myself.alert_parent (0);
+         myself->alert_parent (0);
            
        }
     }
@@ -143,7 +133,8 @@ _pinfo::exit (UINT n, bool norecord)
   sigproc_printf ("Calling ExitProcess %d", n);
   _my_tls.stacklock = 0;
   _my_tls.stackptr = _my_tls.stack;
-  ExitProcess (n);
+  myself.procinfo = NULL;      // This breaks the abstraction a little doesn't it?
+  ExitProcess (exitcode);
 }
 
 void
@@ -273,7 +264,10 @@ pinfo::init (pid_t n, DWORD flag, HANDLE in_h)
       if (!created)
        /* nothing */;
       else if (!(flag & PID_EXECED))
-       procinfo->pid = n;
+       {
+         procinfo->pid = n;
+         procinfo->exitcode = SIGTERM;
+       }
       else
        {
          procinfo->process_state |= PID_IN_USE | PID_EXECED;
@@ -664,15 +658,10 @@ _pinfo::cmdline (size_t& n)
 }
 
 /* This is the workhorse which waits for the write end of the pipe
-   created during new process creation.  If the pipe is closed, it is
-   assumed that the cygwin pid has exited.  Otherwise, various "signals"
-   can be sent to the parent to inform the parent to perform a certain
-   action.
-
-   This code was originally written to eliminate the need for "reparenting"
-   but, unfortunately, reparenting is still needed in order to get the
-   exit code of an execed windows process.  Otherwise, the exit code of
-   a cygwin process comes from the exitcode field in _pinfo. */
+   created during new process creation.  If the pipe is closed or a zero
+   is received on the pipe, it is assumed that the cygwin pid has exited.
+   Otherwise, various "signals" can be sent to the parent to inform the
+   parent to perform a certain action. */
 static DWORD WINAPI
 proc_waiter (void *arg)
 {
@@ -768,29 +757,41 @@ proc_waiter (void *arg)
   return 0;
 }
 
+bool
+_pinfo::dup_proc_pipe (HANDLE hProcess)
+{
+  bool res = DuplicateHandle (hMainProc, wr_proc_pipe, hProcess, &wr_proc_pipe,
+                             0, FALSE,
+                             DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+  if (!res)
+    sigproc_printf ("DuplicateHandle failed, pid %d, hProcess %p, %E", pid, hProcess);
+  else
+    {
+      wr_proc_pipe_owner = dwProcessId;
+      sigproc_printf ("closed wr_proc_pipe %p for pid %d(%u)", wr_proc_pipe,
+                     pid, dwProcessId);
+    }
+  return res;
+}
+
 /* function to set up the process pipe and kick off proc_waiter */
 int
 pinfo::wait ()
 {
-  HANDLE out;
   /* FIXME: execed processes should be able to wait for pids that were started
      by the process which execed them. */
-  if (!CreatePipe (&rd_proc_pipe, &out, &sec_none_nih, 16))
+  if (!CreatePipe (&rd_proc_pipe, &((*this)->wr_proc_pipe), &sec_none_nih, 16))
     {
       system_printf ("Couldn't create pipe tracker for pid %d, %E",
                     (*this)->pid);
       return 0;
     }
-  /* Duplicate the write end of the pipe into the subprocess.  Make it inheritable
-     so that all of the execed children get it.  */
-  if (!DuplicateHandle (hMainProc, out, hProcess, &((*this)->wr_proc_pipe), 0,
-                       TRUE, DUPLICATE_SAME_ACCESS))
+
+  if (!(*this)->dup_proc_pipe (hProcess))
     {
-      system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid,
-                    hProcess);
+      system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, hProcess);
       return 0;
     }
-  CloseHandle (out);   /* Don't need this end in this proces */
 
   preserve ();         /* Preserve the shared memory associated with the pinfo */
 
@@ -808,26 +809,38 @@ pinfo::wait ()
   return 1;
 }
 
+void
+_pinfo::sync_proc_pipe ()
+{
+  if (wr_proc_pipe && wr_proc_pipe != INVALID_HANDLE_VALUE)
+    while (wr_proc_pipe_owner != GetCurrentProcessId ())
+      low_priority_sleep (0);
+}
+
 /* function to send a "signal" to the parent when something interesting happens
    in the child. */
 bool
-pinfo::alert_parent (char sig)
+_pinfo::alert_parent (char sig)
 {
   DWORD nb = 0;
   /* Send something to our parent.  If the parent has gone away,
      close the pipe. */
-  if (myself->wr_proc_pipe == INVALID_HANDLE_VALUE
+  if (wr_proc_pipe == INVALID_HANDLE_VALUE
       || !myself->wr_proc_pipe)
     /* no parent */;
-  else if (WriteFile (myself->wr_proc_pipe, &sig, 1, &nb, NULL))
-    /* all is well */;
-  else if (GetLastError () != ERROR_BROKEN_PIPE)
-    debug_printf ("sending %d notification to parent failed, %E", sig);
   else
     {
-      HANDLE closeit = myself->wr_proc_pipe;
-      myself->wr_proc_pipe = INVALID_HANDLE_VALUE;
-      CloseHandle (closeit);
+      sync_proc_pipe ();
+      if (WriteFile (wr_proc_pipe, &sig, 1, &nb, NULL))
+       /* all is well */;
+      else if (GetLastError () != ERROR_BROKEN_PIPE)
+       debug_printf ("sending %d notification to parent failed, %E", sig);
+      else
+       {
+         HANDLE closeit = wr_proc_pipe;
+         wr_proc_pipe = INVALID_HANDLE_VALUE;
+         CloseHandle (closeit);
+       }
     }
   return (bool) nb;
 }
index 6516832..dd998a6 100644 (file)
@@ -106,6 +106,9 @@ public:
   bool alive ();
   char *cmdline (size_t &);
   void set_ctty (class tty_min *, int, class fhandler_tty_slave *);
+  bool dup_proc_pipe (HANDLE) __attribute__ ((regparm(2)));
+  void sync_proc_pipe ();
+  bool alert_parent (char);
 
   friend void __stdcall set_myself (HANDLE);
 
@@ -117,6 +120,7 @@ private:
   sigset_t sig_mask;
 public:
   HANDLE wr_proc_pipe;
+  DWORD wr_proc_pipe_owner;
   friend class pinfo;
 };
 
@@ -163,8 +167,6 @@ public:
   operator _pinfo * () const {return procinfo;}
   // operator bool () const {return (int) h;}
   void preserve () { destroy = false; }
-  bool alert_parent (char);
-  bool parent_alive () { return alert_parent (__ALERT_ALIVE); }
 #ifndef _SIGPROC_H
   int remember () {system_printf ("remember is not here"); return 0;}
 #else
@@ -178,6 +180,7 @@ public:
 #endif
   HANDLE shared_handle () {return h;}
   void set_acl();
+  friend class _pinfo;
 };
 
 #define ISSTATE(p, f)  (!!((p)->process_state & f))
index 934988d..b5a2815 100644 (file)
@@ -735,8 +735,6 @@ child_info::child_info (unsigned in_cb, child_info_types chtype)
   if (chtype != PROC_SPAWN)
     subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
   sigproc_printf ("subproc_ready %p", subproc_ready);
-  if (chtype != PROC_EXEC && myself->wr_proc_pipe != INVALID_HANDLE_VALUE)
-    parent_wr_proc_pipe = myself->wr_proc_pipe;
 }
 
 child_info::~child_info ()
index 1c84fad..3fcf92c 100644 (file)
@@ -796,16 +796,28 @@ spawn_guts (const char * prog_arg, const char *const *argv,
       sigproc_printf ("new process name %s", myself->progname);
       close_all_files ();
       /* If wr_proc_pipe doesn't exist then this process was not started by a cygwin
-       process.  So, we need to wait around until the process we've just "execed"
-       dies.  Use our own wait facility to wait for our own pid to exit (there
-       is some minor special case code in proc_waiter and friends to accommodeate
-       this). */
+        process.  So, we need to wait around until the process we've just "execed"
+        dies.  Use our own wait facility to wait for our own pid to exit (there
+        is some minor special case code in proc_waiter and friends to accommodate
+        this).
+
+        If wr_proc_pipe exists, then it should be duplicated to the child.
+        If the child has exited already, that's ok.  The parent will pick up
+        on this fact when we exit.  dup_proc_pipe also closes our end of the pipe.
+        Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE.  That will make
+        dup_proc_pipe essentially a no-op.  */
       if (!myself->wr_proc_pipe)
-       {
-        myself.remember (true);
-        wait_for_myself = true;
-        myself->wr_proc_pipe = INVALID_HANDLE_VALUE;
-       }
+       {
+         myself.remember (false);
+         wait_for_myself = true;
+       }
+      else
+       {
+         /* Make sure that we own wr_proc_pipe just in case we've been
+            previously execed. */
+         myself->sync_proc_pipe ();
+         (void) myself->dup_proc_pipe (pi.hProcess);
+       }
     }
   else
     {
@@ -849,14 +861,13 @@ ForceCloseHandle (pi.hThread);
 
 sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
 
-if (wait_for_myself)
-  waitpid (myself->pid, &res, 0);
-else
-  ciresrv.sync (myself, INFINITE);
+ciresrv.sync (myself, INFINITE);
 
 switch (mode)
   {
   case _P_OVERLAY:
+    if (wait_for_myself)
+      waitpid (myself->pid, &res, 0);
     myself->exit (res, 1);
     break;
   case _P_WAIT: