+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>
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);
}
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;
}
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)
{
/* 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);
}
}
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
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;
}
/* 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)
{
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 */
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;
}
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
{
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: