* 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.
This commit is contained in:
		| @@ -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> | ||||
|  | ||||
|   | ||||
| @@ -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 (); | ||||
|   | ||||
| @@ -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"); | ||||
|   | ||||
| @@ -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 (); | ||||
|   | ||||
| @@ -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 | ||||
|     { | ||||
|       /* 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) | ||||
|   else if (cygheap->pid_handle) | ||||
|     { | ||||
|       ForceCloseHandle (cygheap->pid_handle); | ||||
|       cygheap->pid_handle = NULL; | ||||
|     } | ||||
|     } | ||||
| # undef child_proc_info | ||||
|   return; | ||||
| } | ||||
|  | ||||
| @@ -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->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,27 +809,39 @@ 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)) | ||||
|   else | ||||
|     { | ||||
|       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 = myself->wr_proc_pipe; | ||||
|       myself->wr_proc_pipe = INVALID_HANDLE_VALUE; | ||||
| 	  HANDLE closeit = wr_proc_pipe; | ||||
| 	  wr_proc_pipe = INVALID_HANDLE_VALUE; | ||||
| 	  CloseHandle (closeit); | ||||
| 	} | ||||
|     } | ||||
|   return (bool) nb; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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)) | ||||
|   | ||||
| @@ -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 () | ||||
|   | ||||
| @@ -798,13 +798,25 @@ spawn_guts (const char * prog_arg, const char *const *argv, | ||||
|       /* 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). */ | ||||
| 	 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); | ||||
| 	  myself.remember (false); | ||||
| 	  wait_for_myself = true; | ||||
| 	 myself->wr_proc_pipe = INVALID_HANDLE_VALUE; | ||||
| 	} | ||||
|       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: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user