Eliminate use of sigframe and sigthread throughout.

* Makefile.in (DLL_OFILES): Add sigfe.o.  Remove reliance on cygwin.def from
cygwin0.dll dependency since dependence on sigfe.o implies that.  Generate def
file on the fly using 'gendef'.
* configure.in: Don't auto-generate cygwin.def.
* configure: Regenerate.
* cygwin.din: Add SIGFE stuff where appropriate.
* dcrt0.cc (dll_crt0_1): Initialize cygwin tls early in process startup.  Set
_main_tls to address of the main thread's cygwin tls.
* debug.h: Remove now unneeded WFSO and WFMO declarations.
* exceptions.cc (_last_thread): Define.
(set_thread_state_for_signals): New function.
(reset_thread_exception_for_signals): Ditto.
(init_thread_for_signals): Ditto.
(delete_thread_for_signals): Ditto.
(capture_thread_for_signals): Ditto.
(handle_exceptions): Set return address explicitly for exceptions prior to
calling sig_send.
(interrupt_on_return): Eliminate.
(setup_handler): Add preliminary implementation for dealing with
thread-specific signals by querying _main_tls.
(signal_exit): Use cygthread::main_thread_id instead of mainthread.id.
(call_signal_handler_now): For now, just handle the main thread.
* fork.cc (vfork): Save and restore main _my_tls.
* gendef: New file.  Generates def file and sigfe.s file.
* gentls_offsets: New file.  Generates offsets for perl to use in sigfe.s.
* how-signals-work.txt: Mention that info is obsolete.
* init.cc (dll_entry): Initialize cygwin tls storage here.
* miscfuncs.cc (low_priority_sleep): Make a C function for easier calling from
asm.
* perthread.h (vfork_save::tls): New element.
* signal.cc (nanosleep): Replace previous use of
sigframe.call_signal_handler_now with straight call to call_signal_handler_now.
(abort): Ditto.
* syscalls.cc (readv): Ditto.
* termios.cc (tcsetattr): Ditto.
* wait.cc (wait4): Ditto.
* sigproc.cc (sig_dispatch_pending): Ditto.
(sig_send): Ditto.
* sigproc.h: Declare call_signal_handler_now.
* thread.cc (pthread::thread_init_wrapper): Initialize cygwin tls.  Remove
obsolete and unworking signal stuff.
* thread.h (verifyable_object::sigs): Eliminate.
(verifyable_object::sigmask): Eliminate.
(verifyable_object::sigtodo): Eliminate.
(verifyable_object::exit): Make attribute noreturn.
(verifyable_object::thread_init_wrapper): Ditto.
(pthread_null::exit): Ditto.
* winbase.h (__stackbase): Always define.
* winsup.h (low_priority_sleep): Declare as a "C" function.
* include/cygwin/version.h: Bump API version to reflect sigwait export.
* include/sys/queue.h: Protect SLIST_ENTRY from previous declaration.
* signal.cc (sigwait): Implement.
* select.cc (fhandler_base::ready_for_read): Add debugging output.
* devices.h: Define more device pointers via their storage.
* devices.in: Don't parse things like /dev/inet/tcp, as they really have no
meaning.
* devices.cc: Regenerate.
* gendevices: Set proper protection for output file.
* cygtls.h: New file.
* gendef: New file.
* gentls_offsets: New file.
* tlsoffsets.h: New file.  Autogenerated.
* config/i386/longjmp.c: Remove.  File subsumed by gendef output.
* config/i386/makefrag: Remove obsolete file.
* fhandler.cc: Remove spurious access_worker declaration.
* spawn.cc (spawnve): Make debugging output more accurate.
* cygwin-gperf: Remove.
* devices.cc: Remove.
This commit is contained in:
Christopher Faylor
2003-11-28 20:55:59 +00:00
parent ffe0063843
commit 9a4d574b8d
50 changed files with 3311 additions and 3466 deletions

View File

@ -12,19 +12,20 @@ details. */
#include <imagehlp.h>
#include <stdlib.h>
#include <setjmp.h>
#include <wingdi.h>
#include <winuser.h>
#include <assert.h>
#include "exceptions.h"
#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "cygtls.h"
#include "sigproc.h"
#include "cygerrno.h"
#define NEED_VFORK
#include "perthread.h"
#include "shared_info.h"
#include "perprocess.h"
#include "security.h"
#include "cygthread.h"
#define CALL_HANDLER_RETRY 20
@ -32,13 +33,13 @@ char debugger_command[2 * CYG_MAX_PATH + 20];
extern "C" {
static int handle_exceptions (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
extern void sigreturn ();
extern void sigdelayed ();
extern void sigdelayed0 ();
extern void siglast ();
extern DWORD __no_sig_start, __no_sig_end;
};
_threadinfo NO_COPY dummy_thread;
_threadinfo NO_COPY *_last_thread = &dummy_thread;
extern _threadinfo *_main_tls;
extern DWORD sigtid;
extern HANDLE hExeced;
@ -54,8 +55,6 @@ static size_t windows_system_directory_length;
static NO_COPY int exit_already = 0;
static NO_COPY muto *mask_sync = NULL;
HMODULE NO_COPY cygwin_hmodule;
NO_COPY static struct
{
unsigned int code;
@ -97,8 +96,6 @@ NO_COPY static struct
/* Initialization code. */
#ifdef __i386__
// Set up the exception handler for the current thread. The PowerPC & Mips
// use compiler generated tables to set up the exception handlers for each
// region of code, and the kernel walks the call list until it finds a region
@ -116,7 +113,6 @@ init_exception_handler (exception_list *el)
el->prev = _except_list;
_except_list = el;
}
#endif
void
init_console_handler ()
@ -132,6 +128,74 @@ init_exceptions (exception_list *el)
init_exception_handler (el);
}
void
_threadinfo::set_state (bool is_exception)
{
initialized = CYGTLS_INITIALIZED + is_exception;
}
void
_threadinfo::reset_exception ()
{
if (initialized == CYGTLS_EXCEPTION)
{
#ifdef DEBUGGING
debug_printf ("resetting stack after an exception stack %p, stackptr %p", stack, stackptr);
#endif
set_state (false);
stackptr--;
}
}
_threadinfo *
_threadinfo::init (void *, void *thread)
{
memset (this, 0, sizeof (*this));
stackptr = stack;
prev = _last_thread;
_last_thread->next = this;
_last_thread = this;
set_state (false);
errno_addr = &errno;
return this;
}
void
_threadinfo::remove ()
{
_threadinfo *t;
for (t = _last_thread; t && t != this; t = t->prev)
continue;
if (!t)
return;
t->prev->next = t->next;
if (t->next)
t->next->prev = t->prev;
if (t == _last_thread)
_last_thread = t->prev;
}
void
_threadinfo::push (__stack_t addr, bool exception)
{
*stackptr++ = (__stack_t) addr;
set_state (exception);
}
__stack_t
_threadinfo::pop ()
{
#ifdef DEBUGGING
assert (stackptr > stack);
#endif
__stack_t res = *--stackptr;
#ifndef DEBUGGING
_my_tls.stackptr = 0;
debug_printf ("popped %p, stack %p, stackptr %p", res, stack, stackptr);
#endif
return res;
}
extern "C" void
error_start_init (const char *buf)
{
@ -241,7 +305,6 @@ public:
/* This is the main stack frame info for this process. */
static NO_COPY stack_info thestack;
static signal_dispatch sigsave;
/* Initialize everything needed to start iterating. */
void
@ -392,22 +455,19 @@ try_to_debug (bool waitloop)
Sleep (0);
Sleep (2000);
small_printf ("*** continuing from debugger call\n");
SetThreadPriority (GetCurrentThread (), prio);
}
/* FIXME: need to know handles of all running threads to
resume_all_threads_except (current_thread_id);
*/
SetThreadPriority (GetCurrentThread (), prio);
return 0;
}
/* Main exception handler. */
extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD);
static int
handle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *)
handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *)
{
int sig;
static int NO_COPY debugging = 0;
static bool NO_COPY debugging = false;
static int NO_COPY recursed = 0;
if (debugging && ++debugging < 500000)
@ -421,8 +481,16 @@ handle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *)
if (exit_already)
return 1;
EXCEPTION_RECORD e = *e0;
CONTEXT in = *in0;
extern DWORD ret_here[];
RtlUnwind (frame, ret_here, e0, 0);
__asm__ volatile (".equ _ret_here,.");
int sig;
/* Coerce win32 value to posix value. */
switch (e->ExceptionCode)
switch (e.ExceptionCode)
{
case STATUS_FLOAT_DENORMAL_OPERAND:
case STATUS_FLOAT_DIVIDE_BY_ZERO:
@ -476,8 +544,8 @@ handle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *)
return 1;
}
debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp);
debug_printf ("In cygwin_except_handler sig = %d at %p", sig, in->Eip);
debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e.ExceptionCode, in.Eip, in.Esp);
debug_printf ("In cygwin_except_handler sig = %d at %p", sig, in.Eip);
if (myself->getsig (sig).sa_mask & SIGTOMASK (sig))
syscall_printf ("signal %d, masked %p", sig, myself->getsig (sig).sa_mask);
@ -485,9 +553,9 @@ handle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *)
debug_printf ("In cygwin_except_handler calling %p",
myself->getsig (sig).sa_handler);
DWORD *ebp = (DWORD *)in->Esp;
DWORD *ebp = (DWORD *)in.Esp;
for (DWORD *bpend = (DWORD *) __builtin_frame_address (0); ebp > bpend; ebp--)
if (*ebp == in->SegCs && ebp[-1] == in->Eip)
if (*ebp == in.SegCs && ebp[-1] == in.Eip)
{
ebp -= 2;
break;
@ -500,11 +568,11 @@ handle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *)
|| (void *) myself->getsig (sig).sa_handler == (void *) SIG_ERR)
{
/* Print the exception to the console */
if (e)
if (1)
{
for (int i = 0; status_info[i].name; i++)
{
if (status_info[i].code == e->ExceptionCode)
if (status_info[i].code == e.ExceptionCode)
{
if (!myself->ppid_handle)
system_printf ("Exception: %s", status_info[i].name);
@ -521,20 +589,21 @@ handle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *)
{
if (try_to_debug (0))
{
debugging = 1;
debugging = true;
return 0;
}
open_stackdumpfile ();
exception (e, in);
exception (&e, &in);
stackdump ((DWORD) ebp, 0, 1);
}
signal_exit (0x80 | sig); // Flag signal + core dump
}
sig_send (NULL, sig, (DWORD) ebp, 1); // Signal myself
return 0;
_my_tls.push ((__stack_t) ebp, true);
sig_send (NULL, sig, &_my_tls); // Signal myself
return 1;
}
#endif /* __i386__ */
@ -564,10 +633,9 @@ int __stdcall
handle_sigsuspend (sigset_t tempmask)
{
sig_dispatch_pending ();
sigframe thisframe (mainthread);
sigset_t oldmask = myself->getsigmask (); // Remember for restoration
set_process_mask (tempmask & ~SIG_NONMASKABLE);// Let signals we're
set_signal_mask (tempmask & ~SIG_NONMASKABLE);// Let signals we're
// interested in through.
sigproc_printf ("old mask %x, new mask %x", oldmask, tempmask);
@ -580,7 +648,7 @@ handle_sigsuspend (sigset_t tempmask)
be hit eventually. Set the old mask to be restored when the signal
handler returns. */
sigsave.oldmask = oldmask; // Will be restored by signal handler
_my_tls.oldmask = oldmask; // Will be restored by signal handler
return -1;
}
@ -617,7 +685,7 @@ sig_handle_tty_stop (int sig)
}
int
interruptible (DWORD pc, int testvalid = 0)
interruptible (DWORD pc)
{
int res;
MEMORY_BASIC_INFORMATION m;
@ -635,75 +703,47 @@ interruptible (DWORD pc, int testvalid = 0)
These should *never* be treated as interruptible. */
if (!h || m.State != MEM_COMMIT)
res = 0;
else if (testvalid)
res = 1; /* All we wanted to know was if this was a valid module. */
else if (h == user_data->hmodule)
res = 1;
else if (h == cygwin_hmodule)
res = 0;
else if (!GetModuleFileName (h, checkdir, windows_system_directory_length + 2))
res = 0;
else
res = !strncasematch (windows_system_directory, checkdir,
windows_system_directory_length);
sigproc_printf ("pc %p, h %p, interruptible %d, testvalid %d", pc, h, res, testvalid);
sigproc_printf ("pc %p, h %p, interruptible %d", pc, h, res);
# undef h
return res;
}
bool
sigthread::get_winapi_lock (int test)
void __stdcall
_threadinfo::interrupt_setup (int sig, void *handler,
struct sigaction& siga, __stack_t retaddr)
{
if (test)
return !InterlockedExchange (&winapi_lock, 1);
/* Need to do a busy loop because we can't block or a potential SuspendThread
will hang. */
while (InterlockedExchange (&winapi_lock, 1))
low_priority_sleep (0);
return 1;
}
void
sigthread::release_winapi_lock ()
{
/* Assumes that we have the lock. */
InterlockedExchange (&winapi_lock, 0);
}
static void __stdcall interrupt_setup (int sig, void *handler, DWORD retaddr,
DWORD *retaddr_on_stack,
struct sigaction& siga)
__attribute__((regparm(3)));
static void __stdcall
interrupt_setup (int sig, void *handler, DWORD retaddr, DWORD *retaddr_on_stack,
struct sigaction& siga)
{
sigsave.retaddr = retaddr;
sigsave.retaddr_on_stack = retaddr_on_stack;
/* FIXME: Not multi-thread aware */
sigsave.oldmask = myself->getsigmask ();
sigsave.newmask = sigsave.oldmask | siga.sa_mask | SIGTOMASK (sig);
sigsave.sa_flags = siga.sa_flags;
sigsave.func = (void (*)(int)) handler;
sigsave.saved_errno = -1; // Flag: no errno to save
__stack_t *retaddr_in_tls = stackptr - 1;
push ((__stack_t) sigdelayed);
oldmask = myself->getsigmask ();
newmask = oldmask | siga.sa_mask | SIGTOMASK (sig);
sa_flags = siga.sa_flags;
func = (void (*) (int)) handler;
saved_errno = -1; // Flag: no errno to save
if (handler == sig_handle_tty_stop)
{
myself->stopsig = 0;
myself->process_state |= PID_STOPPED;
}
this->sig = sig; // Should ALWAYS be second to last setting set to avoid a race
*retaddr_in_tls = retaddr;
/* Clear any waiting threads prior to dispatching to handler function */
proc_subproc (PROC_CLEARWAIT, 1);
int res = SetEvent (signal_arrived); // For an EINTR case
sigsave.sig = sig; // Should ALWAYS be last thing set to avoid a race
proc_subproc (PROC_CLEARWAIT, 1);
sigproc_printf ("armed signal_arrived %p, res %d", signal_arrived, res);
}
static bool interrupt_now (CONTEXT *, int, void *, struct sigaction&) __attribute__((regparm(3)));
static bool
interrupt_now (CONTEXT *ctx, int sig, void *handler, struct sigaction& siga)
bool
_threadinfo::interrupt_now (CONTEXT *ctx, int sig, void *handler,
struct sigaction& siga)
{
interrupt_setup (sig, handler, ctx->Eip, 0, siga);
push (0);
interrupt_setup (sig, handler, siga, (__stack_t) ctx->Eip);
ctx->Eip = (DWORD) sigdelayed;
SetThreadContext (myself->getthread2signal (), ctx); /* Restart the thread in a new location */
return 1;
@ -712,167 +752,112 @@ interrupt_now (CONTEXT *ctx, int sig, void *handler, struct sigaction& siga)
void __stdcall
signal_fixup_after_fork ()
{
if (sigsave.sig)
if (_my_tls.sig)
{
sigsave.sig = 0;
if (sigsave.retaddr_on_stack)
{
*sigsave.retaddr_on_stack = sigsave.retaddr;
set_process_mask (sigsave.oldmask);
}
_my_tls.sig = 0;
_my_tls.stackptr = _my_tls.stack + 1; // FIXME?
set_signal_mask (_my_tls.oldmask);
}
sigproc_init ();
}
static int interrupt_on_return (sigthread *, int, void *, struct sigaction&) __attribute__((regparm(3)));
static int
interrupt_on_return (sigthread *th, int sig, void *handler, struct sigaction& siga)
{
int i;
DWORD ebp = th->frame;
if (!ebp)
return 0;
thestack.init (ebp, 0, 1); /* Initialize from the input CONTEXT */
for (i = 0; i < 32 && thestack++ ; i++)
if (th->exception || interruptible (thestack.sf.AddrReturn.Offset))
{
DWORD *addr_retaddr = ((DWORD *)thestack.sf.AddrFrame.Offset) + 1;
if (*addr_retaddr == thestack.sf.AddrReturn.Offset)
{
interrupt_setup (sig, handler, *addr_retaddr, addr_retaddr, siga);
*addr_retaddr = (DWORD) sigdelayed;
}
return 1;
}
sigproc_printf ("couldn't find a stack frame, i %d", i);
return 0;
}
extern "C" void __stdcall
set_sig_errno (int e)
{
set_errno (e);
sigsave.saved_errno = e;
_my_tls.saved_errno = e;
// sigproc_printf ("errno %d", e);
}
static int setup_handler (int, void *, struct sigaction&) __attribute__((regparm(3)));
static int setup_handler (int, void *, struct sigaction&, _threadinfo *tls)
__attribute__((regparm(3)));
static int
setup_handler (int sig, void *handler, struct sigaction& siga)
setup_handler (int sig, void *handler, struct sigaction& siga, _threadinfo *tls)
{
CONTEXT cx;
bool interrupted = false;
sigthread *th = NULL; // Initialization needed to shut up gcc
if (sigsave.sig)
if (tls->sig)
goto out;
for (int i = 0; i < CALL_HANDLER_RETRY; i++)
{
DWORD res;
HANDLE hth;
EnterCriticalSection (&mainthread.lock);
if (mainthread.frame)
__stack_t retaddr;
__stack_t *retaddr_on_stack = tls->stackptr - 1;
#ifdef DEBUGGING
if (tls->stackptr > (tls->stack + 1))
try_to_debug ();
#endif
if (retaddr_on_stack >= tls->stack
&& (retaddr = InterlockedExchange ((LONG *) retaddr_on_stack, 0)))
{
hth = NULL;
th = &mainthread;
}
else
{
LeaveCriticalSection (&mainthread.lock);
if (!mainthread.get_winapi_lock (1))
if (!retaddr)
continue;
tls->reset_exception ();
tls->interrupt_setup (sig, handler, siga, retaddr);
sigproc_printf ("interrupted known cygwin routine");
interrupted = true;
break;
}
hth = myself->getthread2signal ();
th = NULL;
DWORD res;
HANDLE hth = myself->getthread2signal ();
/* Suspend the thread which will receive the signal. But first ensure that
this thread doesn't have any mutos. (FIXME: Someday we should just grab
all of the mutos rather than checking for them)
For Windows 95, we also have to ensure that the addresses returned by GetThreadContext
are valid.
If one of these conditions is not true we loop for a fixed number of times
since we don't want to stall the signal handler. FIXME: Will this result in
noticeable delays?
If the thread is already suspended (which can occur when a program has called
SuspendThread on itself then just queue the signal. */
/* Suspend the thread which will receive the signal. But first ensure that
this thread doesn't have any mutos. (FIXME: Someday we should just grab
all of the mutos rather than checking for them)
For Windows 95, we also have to ensure that the addresses returned by GetThreadContext
are valid.
If one of these conditions is not true we loop for a fixed number of times
since we don't want to stall the signal handler. FIXME: Will this result in
noticeable delays?
If the thread is already suspended (which can occur when a program has called
SuspendThread on itself then just queue the signal. */
EnterCriticalSection (&mainthread.lock);
#ifndef DEBUGGING
sigproc_printf ("suspending mainthread");
sigproc_printf ("suspending mainthread");
#else
cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
if (!GetThreadContext (hth, &cx))
memset (&cx, 0, sizeof cx);
#if 0
if ((cx.Eip & 0xff000000) == 0x77000000)
try_to_debug ();
cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
if (!GetThreadContext (hth, &cx))
memset (&cx, 0, sizeof cx);
sigproc_printf ("suspending mainthread PC %p", cx.Eip);
#endif
sigproc_printf ("suspending mainthread PC %p", cx.Eip);
#endif
res = SuspendThread (hth);
/* Just release the lock now since we hav suspended the main thread and it
definitely can't be grabbing it now. This will have to change, of course,
if/when we can send signals to other than the main thread. */
LeaveCriticalSection (&mainthread.lock);
res = SuspendThread (hth);
/* Just release the lock now since we hav suspended the main thread and it
definitely can't be grabbing it now. This will have to change, of course,
if/when we can send signals to other than the main thread. */
/* Just set pending if thread is already suspended */
if (res)
{
mainthread.release_winapi_lock ();
(void) ResumeThread (hth);
break;
}
mainthread.release_winapi_lock ();
if (mainthread.frame)
goto resume_thread; /* We just got the frame. What are the odds?
Just loop and we'll hopefully pick it up on
the next pass through. */
muto *m;
/* FIXME: Make multi-thread aware */
for (m = muto_start.next; m != NULL; m = m->next)
if (m->unstable () || m->owner () == mainthread.id)
{
sigproc_printf ("suspended thread owns a muto (%s)", m->name);
goto resume_thread;
}
if (mainthread.frame)
th = &mainthread;
else
{
cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
if (!GetThreadContext (hth, &cx))
{
system_printf ("couldn't get context of main thread, %E");
goto resume_thread;
}
}
}
if (th)
/* Just set pending if thread is already suspended */
if (res)
{
interrupted = interrupt_on_return (th, sig, handler, siga);
LeaveCriticalSection (&th->lock);
(void) ResumeThread (hth);
break;
}
// FIXME - add check for reentering of DLL here
muto *m;
/* FIXME: Make multi-thread aware */
for (m = muto_start.next; m != NULL; m = m->next)
if (m->unstable () || m->owner () == cygthread::main_thread_id)
{
sigproc_printf ("suspended thread owns a muto (%s)", m->name);
goto resume_thread;
}
cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
if (!GetThreadContext (hth, &cx))
system_printf ("couldn't get context of main thread, %E");
else if (interruptible (cx.Eip))
interrupted = interrupt_now (&cx, sig, handler, siga);
interrupted = tls->interrupt_now (&cx, sig, handler, siga);
resume_thread:
if (hth)
res = ResumeThread (hth);
res = ResumeThread (hth);
if (interrupted)
break;
sigproc_printf ("couldn't interrupt. trying again.");
low_priority_sleep (0);
}
out:
@ -921,7 +906,7 @@ ctrl_c_handler (DWORD type)
window station, one which actually represents a visible desktop.
If not, the CTRL_LOGOFF_EVENT doesn't concern this process. */
if (has_visible_window_station ())
sig_send (NULL, SIGHUP);
sig_send (myself_nowait, SIGHUP);
return FALSE;
}
}
@ -954,14 +939,19 @@ ctrl_c_handler (DWORD type)
return TRUE;
}
/* Set the signal mask for this process.
Note that some signals are unmaskable, as in UNIX. */
/* Function used by low level sig wrappers. */
extern "C" void __stdcall
set_process_mask (sigset_t newmask)
{
sigframe thisframe (mainthread);
set_signal_mask (newmask);
}
/* Set the signal mask for this process.
Note that some signals are unmaskable, as in UNIX. */
extern "C" void __stdcall
set_signal_mask (sigset_t newmask, sigset_t& oldmask)
{
mask_sync->acquire (INFINITE);
sigset_t oldmask = myself->getsigmask ();
newmask &= ~SIG_NONMASKABLE;
sigproc_printf ("old mask = %x, new mask = %x", myself->getsigmask (), newmask);
myself->setsigmask (newmask); // Set a new mask
@ -969,13 +959,21 @@ set_process_mask (sigset_t newmask)
if (oldmask & ~newmask)
sig_dispatch_pending ();
else
sigproc_printf ("not calling sig_dispatch_pending. sigtid %p current %p",
sigtid, GetCurrentThreadId ());
sigproc_printf ("not calling sig_dispatch_pending");
return;
}
_threadinfo *
find_tls (int sig)
{
for (_threadinfo *t = _last_thread; t ; t = t->prev)
if (sigismember (&t->sigwait_mask, sig))
return t;
return NULL;
}
int __stdcall
sig_handle (int sig, sigset_t mask)
sig_handle (int sig, sigset_t mask, int pid, _threadinfo *tls)
{
if (sig == SIGCONT)
{
@ -991,26 +989,33 @@ sig_handle (int sig, sigset_t mask)
SetEvent (sigCONT);
}
int rc = 1;
bool insigwait_mask = tls ? sigismember (&tls->sigwait_mask, sig) : false;
if (sig != SIGKILL && sig != SIGSTOP
&& (sigismember (&mask, sig) || main_vfork->pid
&& (sigismember (&mask, sig)
|| (tls
&& (insigwait_mask || sigismember (&tls->sigmask, sig)))
|| main_vfork->pid
|| ISSTATE (myself, PID_STOPPED)))
{
sigproc_printf ("signal %d blocked", sig);
return -1;
if (insigwait_mask || (tls = find_tls (sig)) != NULL)
goto thread_specific;
rc = -1;
goto done;
}
int rc = 1;
sigproc_printf ("signal %d processing", sig);
struct sigaction thissig = myself->getsig (sig);
void *handler = (void *) thissig.sa_handler;
myself->rusage_self.ru_nsignals++;
/* Clear pending SIGCONT on stop signals */
if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
sig_clear (SIGCONT);
sigproc_printf ("signal %d processing", sig);
struct sigaction thissig = myself->getsig (sig);
void *handler;
handler = (void *) thissig.sa_handler;
myself->rusage_self.ru_nsignals++;
if (sig == SIGKILL)
goto exit_sig;
@ -1025,6 +1030,8 @@ sig_handle (int sig, sigset_t mask)
if (handler == (void *) SIG_DFL)
{
if (insigwait_mask)
goto thread_specific;
if (sig == SIGCHLD || sig == SIGIO || sig == SIGCONT || sig == SIGWINCH
|| sig == SIGURG)
{
@ -1059,12 +1066,18 @@ stop:
dosig:
/* Dispatch to the appropriate function. */
sigproc_printf ("signal %d, about to call %p", sig, handler);
rc = setup_handler (sig, handler, thissig);
rc = setup_handler (sig, handler, thissig, tls ?: _main_tls);
done:
sigproc_printf ("returning %d", rc);
return rc;
thread_specific:
tls->sig = sig;
sigproc_printf ("releasing sigwait for thread");
SetEvent (tls->event);
goto done;
exit_sig:
if (sig == SIGQUIT || sig == SIGABRT)
{
@ -1102,7 +1115,7 @@ signal_exit (int rc)
/* Unlock any main thread mutos since we're executing with prejudice. */
muto *m;
for (m = muto_start.next; m != NULL; m = m->next)
if (m->unstable () || m->owner () == mainthread.id)
if (m->unstable () || m->owner () == cygthread::main_thread_id)
m->reset ();
user_data->resourcelocks->Delete ();
@ -1149,7 +1162,6 @@ events_init (void)
windows_system_directory_length = end - windows_system_directory;
debug_printf ("windows_system_directory '%s', windows_system_directory_length %d",
windows_system_directory, windows_system_directory_length);
debug_printf ("cygwin_hmodule %p", cygwin_hmodule);
InitializeCriticalSection (&exit_lock);
}
@ -1160,114 +1172,39 @@ events_terminate (void)
}
extern "C" {
static int __stdcall
int __stdcall
call_signal_handler_now ()
{
if (!sigsave.sig)
int sa_flags = 0;
while (_my_tls.sig && _my_tls.stackptr > _my_tls.stack)
{
sigproc_printf ("call_signal_handler_now called when no signal active");
return 0;
sa_flags = _my_tls.sa_flags;
int sig = _my_tls.sig;
void (*sigfunc) (int) = _my_tls.func;
(void) _my_tls.pop ();
#ifdef DEBUGGING
if (_my_tls.stackptr > (_my_tls.stack + 1))
try_to_debug ();
#endif
reset_signal_arrived ();
sigset_t oldmask = _my_tls.oldmask;
int this_errno = _my_tls.saved_errno;
set_process_mask (_my_tls.newmask);
_my_tls.sig = 0;
sigfunc (sig);
set_process_mask (oldmask);
if (this_errno >= 0)
set_errno (this_errno);
}
int sa_flags = sigsave.sa_flags;
sigproc_printf ("sa_flags %p", sa_flags);
*sigsave.retaddr_on_stack = sigsave.retaddr;
sigdelayed0 ();
return sa_flags & SA_RESTART;
}
/* This kludge seems to keep a copy of call_signal_handler_now around
even when compiling with -finline-functions. */
static int __stdcall call_signal_handler_now_dummy ()
__attribute__((alias ("call_signal_handler_now")));
};
int
sigframe::call_signal_handler ()
{
return unregister () ? call_signal_handler_now () : 0;
}
#define pid_offset (unsigned)(((_pinfo *)NULL)->pid)
extern "C" {
void __stdcall
reset_signal_arrived ()
{
(void) ResetEvent (signal_arrived);
sigproc_printf ("reset signal_arrived");
}
#undef errno
#define errno ((DWORD volatile) _impure_ptr) + (((char *) &_impure_ptr->_errno) - ((char *) _impure_ptr))
__attribute__((const, used, noinline)) static void
unused_sig_wrapper ()
{
/* Signal cleanup stuff. Cleans up stack (too bad that we didn't
prototype signal handlers as __stdcall), calls _set_process_mask
to restore any mask, restores any potentially clobbered registers
and returns to original caller. */
__asm__ volatile ("\n\
.text \n\
_sigreturn: \n\
addl $4,%%esp # Remove argument \n\
call _set_process_mask@4 \n\
\n\
cmpl $0,%4 # Did a signal come in? \n\
jz 1f # No, if zero \n\
movl %2,%%eax \n\
movl %8,%%ebx # Where return address lives \n\
movl %%eax,(%%ebx) # Restore return address of \n\
# most recent caller \n\
jmp 3f \n\
\n\
1: popl %%eax # saved errno \n\
testl %%eax,%%eax # Is it < 0 \n\
jl 2f # yup. ignore it \n\
movl %1,%%ebx \n\
movl %%eax,(%%ebx) \n\
2: popl %%eax \n\
popl %%ebx \n\
popl %%ecx \n\
popl %%edx \n\
popl %%edi \n\
popl %%esi \n\
popf \n\
popl %%ebp \n\
ret \n\
\n\
__no_sig_start: \n\
_sigdelayed: \n\
pushl %2 # original return address \n\
_sigdelayed0: \n\
pushl %%ebp \n\
movl %%esp,%%ebp \n\
pushf \n\
pushl %%esi \n\
pushl %%edi \n\
pushl %%edx \n\
pushl %%ecx \n\
pushl %%ebx \n\
pushl %%eax \n\
pushl %6 # saved errno \n\
3: pushl %3 # oldmask \n\
pushl %4 # signal argument \n\
pushl $_sigreturn \n\
\n\
call _reset_signal_arrived@0 \n\
pushl %5 # signal number \n\
pushl %7 # newmask \n\
\n\
call _set_process_mask@4 \n\
movl $0,%0 # zero the signal number as a \n\
# flag to the signal handler thread\n\
# that it is ok to set up sigsave\n\
popl %%eax \n\
jmp *%%eax \n\
__no_sig_end: \n\
" : "=m" (sigsave.sig)/*0*/: "X" ((char *) &_impure_ptr->_errno)/*1*/,
"g" (sigsave.retaddr)/*2*/, "g" (sigsave.oldmask)/*3*/, "g" (sigsave.sig)/*4*/,
"g" (sigsave.func)/*5*/, "g" (sigsave.saved_errno)/*6*/, "g" (sigsave.newmask)/*7*/,
"g" (sigsave.retaddr_on_stack)/*8*/
);
}
}