* dcrt0.cc (dll_crt0_1): Create vfork main storage here so that it can be
queried in waitsig later. * sigproc.cc (wait_sig): Don't deliver a signal if in a vfork. * fork.cc (vfork): Deliver all signals on parent return from vfork.
This commit is contained in:
parent
bf0338856a
commit
9661a0c8b7
|
@ -1,3 +1,10 @@
|
|||
Fri Sep 14 20:43:01 2001 Christopher Faylor <cgf@cygnus.com>
|
||||
|
||||
* dcrt0.cc (dll_crt0_1): Create vfork main storage here so that it can
|
||||
be queried in waitsig later.
|
||||
* sigproc.cc (wait_sig): Don't deliver a signal if in a vfork.
|
||||
* fork.cc (vfork): Deliver all signals on parent return from vfork.
|
||||
|
||||
Fri Sep 14 10:21:00 2001 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* dcrt0.cc (_dll_crt0()): Don't call wincap.init() here.
|
||||
|
|
|
@ -534,6 +534,7 @@ alloc_stack (child_info_fork *ci)
|
|||
static NO_COPY int mypid = 0;
|
||||
int _declspec(dllexport) __argc;
|
||||
char _declspec(dllexport) **__argv;
|
||||
vfork_save NO_COPY *main_vfork = NULL;
|
||||
|
||||
void
|
||||
sigthread::init (const char *s)
|
||||
|
@ -644,6 +645,7 @@ dll_crt0_1 ()
|
|||
events_init ();
|
||||
|
||||
cygheap->cwd.init ();
|
||||
main_vfork = vfork_storage.create ();
|
||||
|
||||
cygbench ("pre-forkee");
|
||||
if (user_data->forkee)
|
||||
|
|
|
@ -700,6 +700,7 @@ vfork ()
|
|||
#ifndef NEWVFORK
|
||||
return fork ();
|
||||
#else
|
||||
sigframe thisframe;
|
||||
vfork_save *vf = get_vfork_val ();
|
||||
char **esp, **pp;
|
||||
|
||||
|
@ -714,22 +715,22 @@ vfork ()
|
|||
__asm__ volatile ("movl %%esp,%0": "=r" (vf->vfork_esp):);
|
||||
__asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):);
|
||||
for (pp = (char **)vf->frame, esp = vf->vfork_esp;
|
||||
esp <= vf->vfork_ebp + 1; pp++, esp++)
|
||||
esp <= vf->vfork_ebp + 2; pp++, esp++)
|
||||
*pp = *esp;
|
||||
int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1;
|
||||
debug_printf ("%d = vfork()", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
cygheap->fdtab.vfork_parent_restore ();
|
||||
|
||||
vf = get_vfork_val ();
|
||||
|
||||
__asm__ volatile ("movl %%esp,%0": "=r" (esp):);
|
||||
for (pp = (char **)vf->frame, esp = vf->vfork_esp;
|
||||
esp <= vf->vfork_ebp + 1; pp++, esp++)
|
||||
esp <= vf->vfork_ebp + 2; pp++, esp++)
|
||||
*esp = *pp;
|
||||
|
||||
thisframe.init (mainthread);
|
||||
cygheap->fdtab.vfork_parent_restore ();
|
||||
|
||||
if (vf->pid < 0)
|
||||
{
|
||||
int exitval = -vf->pid;
|
||||
|
@ -740,6 +741,7 @@ vfork ()
|
|||
|
||||
int pid = vf->pid;
|
||||
vf->pid = 0;
|
||||
sig_dispatch_pending ();
|
||||
return pid;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -67,10 +67,10 @@ but not yet dispatched in the main thread. If the sigsave structure
|
|||
seems to be "active", then a "pending" flag is set (see below) and the
|
||||
function returns. Otherwise processing continues.
|
||||
|
||||
After determining that sigsave is available, setup_handler will take
|
||||
one of two routes, depending on whether the main thread is executing
|
||||
in the cygwin DLL or is currently in "user" code. We'll discuss the
|
||||
cygwin DLL case first.
|
||||
After determining that sigsave is available, setup_handler will take one
|
||||
of two routes, depending on whether the main thread is executing in the
|
||||
cygwin DLL or is currently in "user" code. We'll discuss the cygwin DLL
|
||||
case first.
|
||||
|
||||
If sigsave seems to be available, then the frame information for the
|
||||
main thread is inspected. This information is set by any cygwin
|
||||
|
@ -81,21 +81,33 @@ process. Any function which uses 'sigframe thisframe' should be signal
|
|||
aware. It should detect when a signal has arrived and return
|
||||
immediately.
|
||||
|
||||
So, if mainframe is active, that means that we have good information about
|
||||
the state of the main thread. Cygwin uses the stack frame info from this
|
||||
structure to insert a call to the assembly language function 'sigdelayed'
|
||||
in place of the main thread's normal return address. So, when a call to
|
||||
(e.g.) _read returns after detecting a signal, it does not return to its
|
||||
caller. Rather, it returns to sigdelayed.
|
||||
So, if mainframe is active, that means that we have good information
|
||||
about the state of the main thread. Cygwin uses the stack frame info
|
||||
from this structure to insert a call to the assembly language function
|
||||
'sigdelayed' in place of the main thread's normal return address. So,
|
||||
when a call to (e.g.) _read returns after detecting a signal, it does
|
||||
not return to its caller. Rather, it returns to sigdelayed.
|
||||
|
||||
The sigdelayed function saves a lot of state on the stack and sets the
|
||||
signal mask as appropriate for POSIX. It uses information from the
|
||||
sigsave structure which has been filled in by interrupt_on_return, as
|
||||
called by setup_handler. sigdelayed pushes a "call" the function
|
||||
called by setup_handler. sigdelayed pushes a "call" to the function
|
||||
"sigreturn" on the stack. This will be the return address seen by the
|
||||
signal handler. After setting up the return value, modifying the signal
|
||||
mask, and saving other information on the stack, sigreturn clears the
|
||||
sigsave structure (so that setup_handler can use it) and jumps to the
|
||||
signal handler function.
|
||||
signal handler function. And, so a UNIX signal handler function is
|
||||
emulated.
|
||||
|
||||
The signal handler function operates as normal for UNIX but, upon
|
||||
return, it does not go directly back to the return address of the
|
||||
original cygwin function. Instead it returns to the previously
|
||||
mentioned 'sigreturn' assembly language function.
|
||||
|
||||
sigreturn resets the process mask to its state prior to calling the
|
||||
signal handler. It checks to see if any new signals have come in and
|
||||
calls the handler for them now, ensuring that the order of signal
|
||||
arrival is more or less maintained. It checks to see if a cygwin
|
||||
routine has set a special "restore this errno on returning from a
|
||||
signal" value and sets errno to this, if so. Finally, it restores all
|
||||
of the register values that were in effect when sigdelayed was called.
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
size_t size () {return sizeof (waitq);}
|
||||
};
|
||||
|
||||
#ifdef NEED_VFORK
|
||||
#if defined (NEED_VFORK)
|
||||
struct vfork_save
|
||||
{
|
||||
int pid;
|
||||
|
@ -87,6 +87,7 @@ public:
|
|||
size_t size () {return sizeof (vfork_save);}
|
||||
};
|
||||
extern per_thread_vfork vfork_storage;
|
||||
extern vfork_save *main_vfork;
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
|
|
@ -26,6 +26,7 @@ details. */
|
|||
#include "dtable.h"
|
||||
#include "cygheap.h"
|
||||
#include "child_info.h"
|
||||
#define NEED_VFORK
|
||||
#include "perthread.h"
|
||||
#include <assert.h>
|
||||
#include "shared_info.h"
|
||||
|
@ -1161,6 +1162,7 @@ wait_sig (VOID *)
|
|||
|
||||
if (sig > 0 && sig != SIGKILL && sig != SIGSTOP &&
|
||||
(sigismember (&myself->getsigmask (), sig) ||
|
||||
main_vfork->pid ||
|
||||
(sig != SIGCONT && ISSTATE (myself, PID_STOPPED))))
|
||||
{
|
||||
sigproc_printf ("signal %d blocked", sig);
|
||||
|
|
|
@ -75,7 +75,8 @@ public:
|
|||
}
|
||||
|
||||
sigframe (): st (NULL) {}
|
||||
sigframe (sigthread &t, DWORD ebp = (DWORD) __builtin_frame_address (0))
|
||||
sigframe (sigthread &t, DWORD ebp = (DWORD) __builtin_frame_address (0)) {init (t, ebp);}
|
||||
void init (sigthread &t, DWORD ebp = (DWORD) __builtin_frame_address (0))
|
||||
{
|
||||
if (!t.frame && t.id == GetCurrentThreadId ())
|
||||
set (t, ebp);
|
||||
|
|
Loading…
Reference in New Issue