Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2003-11-28 23:55:59 +0300
committerChristopher Faylor <me@cgf.cx>2003-11-28 23:55:59 +0300
commit9a4d574b8d4550f53036dced342022b64e508abf (patch)
tree79d7ab65654ff5cb2fd2c0c035ac2b98deb1fcc2 /winsup/cygwin/exceptions.cc
parentffe006384344b5d2a86e6bedad96725391cfe88e (diff)
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.cc573
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*/
-);
-}
}