diff options
author | Christopher Faylor <me@cgf.cx> | 2003-11-28 20:55:59 +0000 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2003-11-28 20:55:59 +0000 |
commit | 9a4d574b8d4550f53036dced342022b64e508abf (patch) | |
tree | 79d7ab65654ff5cb2fd2c0c035ac2b98deb1fcc2 /winsup/cygwin/exceptions.cc | |
parent | ffe006384344b5d2a86e6bedad96725391cfe88e (diff) | |
download | cygnal-9a4d574b8d4550f53036dced342022b64e508abf.tar.gz cygnal-9a4d574b8d4550f53036dced342022b64e508abf.tar.bz2 cygnal-9a4d574b8d4550f53036dced342022b64e508abf.zip |
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.
Diffstat (limited to 'winsup/cygwin/exceptions.cc')
-rw-r--r-- | winsup/cygwin/exceptions.cc | 573 |
1 files changed, 255 insertions, 318 deletions
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 4baa50594..a15e76132 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -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) -{ - 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) +void __stdcall +_threadinfo::interrupt_setup (int sig, void *handler, + struct sigaction& siga, __stack_t retaddr) { - 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; + if (!retaddr) + continue; + tls->reset_exception (); + tls->interrupt_setup (sig, handler, siga, retaddr); + sigproc_printf ("interrupted known cygwin routine"); + interrupted = true; + break; } - else - { - LeaveCriticalSection (&mainthread.lock); - if (!mainthread.get_winapi_lock (1)) - continue; + 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. */ - hth = myself->getthread2signal (); - th = NULL; - - /* 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 (); -#endif - sigproc_printf ("suspending mainthread PC %p", cx.Eip); + cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + if (!GetThreadContext (hth, &cx)) + memset (&cx, 0, sizeof cx); + 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); - - /* Just set pending if thread is already suspended */ - if (res) - { - mainthread.release_winapi_lock (); - (void) ResumeThread (hth); - break; - } + 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. */ - 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; } +/* Function used by low level sig wrappers. */ +extern "C" void __stdcall +set_process_mask (sigset_t newmask) +{ + 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_process_mask (sigset_t newmask) +set_signal_mask (sigset_t newmask, sigset_t& oldmask) { - sigframe thisframe (mainthread); 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; + /* 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 = (void *) thissig.sa_handler; + void *handler; + 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); - 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*/ -); -} } |