From 9661a0c8b7f59960d6d180ffa2872710f5253913 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Sat, 15 Sep 2001 00:47:44 +0000 Subject: [PATCH] * 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. --- winsup/cygwin/ChangeLog | 7 ++++++ winsup/cygwin/dcrt0.cc | 2 ++ winsup/cygwin/fork.cc | 12 +++++---- winsup/cygwin/how-signals-work.txt | 40 +++++++++++++++++++----------- winsup/cygwin/perthread.h | 3 ++- winsup/cygwin/sigproc.cc | 2 ++ winsup/cygwin/sigproc.h | 3 ++- 7 files changed, 48 insertions(+), 21 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 5688af2ff..86b464a1e 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,10 @@ +Fri Sep 14 20:43:01 2001 Christopher Faylor + + * 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 * dcrt0.cc (_dll_crt0()): Don't call wincap.init() here. diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index a9648f213..5402510a7 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -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) diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 30fca7b2d..c4d122f4d 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -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 } diff --git a/winsup/cygwin/how-signals-work.txt b/winsup/cygwin/how-signals-work.txt index aaaea448a..ca1d8efd7 100644 --- a/winsup/cygwin/how-signals-work.txt +++ b/winsup/cygwin/how-signals-work.txt @@ -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. diff --git a/winsup/cygwin/perthread.h b/winsup/cygwin/perthread.h index 889a5d8c4..185cc04d6 100644 --- a/winsup/cygwin/perthread.h +++ b/winsup/cygwin/perthread.h @@ -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" { diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index d3323ab78..607fa81ab 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -26,6 +26,7 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "child_info.h" +#define NEED_VFORK #include "perthread.h" #include #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); diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h index 38e65faaa..0afb02771 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -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); -- 2.43.5