summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <cgf@redhat.com>2004-01-21 15:16:28 +0000
committerChristopher Faylor <cgf@redhat.com>2004-01-21 15:16:28 +0000
commit8476bebae10fb86a4bf42cce42abf7b6fe49527c (patch)
tree149f96a28997ec51f41db17ebd80bc8ea669b5b4
parent456a03998eedde4197b3e87e81a51a810d9f6bf3 (diff)
downloadgdb-8476bebae10fb86a4bf42cce42abf7b6fe49527c.tar.gz
* cygtls.cc (handle_threadlist_exception): Change logic, improve debugging
output.
-rw-r--r--winsup/cygwin/ChangeLog5
-rw-r--r--winsup/cygwin/cygtls.cc229
2 files changed, 234 insertions, 0 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 82e8f581ed3..d8e637c746f 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,10 @@
2004-01-21 Christopher Faylor <cgf@redhat.com>
+ * cygtls.cc (handle_threadlist_exception): Change logic, improve
+ debugging output.
+
+2004-01-21 Christopher Faylor <cgf@redhat.com>
+
* fhandler_tty.cc (fhandler_tty::ioctl): Semi-revert 2003-09-26 change
for TIOCSWINSZ. It is not an error for ioctl_request_event to be
missing.
diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc
new file mode 100644
index 00000000000..88c8bfb323c
--- /dev/null
+++ b/winsup/cygwin/cygtls.cc
@@ -0,0 +1,229 @@
+/* cygtls.cc
+
+ Copyright 2003, 2004 Red Hat, Inc.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include "thread.h"
+#include "cygtls.h"
+#include "assert.h"
+#include <syslog.h>
+#include <signal.h>
+#include "exceptions.h"
+#include "sync.h"
+#include "cygerrno.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "cygthread.h"
+
+class sentry
+{
+ static muto *lock;
+ int destroy;
+public:
+ void init ();
+ bool acquired () {return lock->acquired ();}
+ sentry () {destroy = 0;}
+ sentry (DWORD wait) {destroy = lock->acquire (wait);}
+ ~sentry () {if (destroy) lock->release ();}
+ friend void _threadinfo::init ();
+};
+
+muto NO_COPY *sentry::lock;
+
+static size_t NO_COPY nthreads;
+
+#define THREADLIST_CHUNK 256
+
+void
+_threadinfo::init ()
+{
+ if (cygheap->threadlist)
+ memset (cygheap->threadlist, 0, cygheap->sthreads * sizeof (cygheap->threadlist[0]));
+ else
+ {
+ cygheap->sthreads = THREADLIST_CHUNK;
+ cygheap->threadlist = (_threadinfo **) ccalloc (HEAP_TLS, cygheap->sthreads,
+ sizeof (cygheap->threadlist[0]));
+ }
+ new_muto1 (sentry::lock, sentry_lock);
+}
+
+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);
+ }
+}
+
+/* Two calls to get the stack right... */
+void
+_threadinfo::call (DWORD (*func) (void *, void *), void *arg)
+{
+ char buf[CYGTLS_PADSIZE];
+ call2 (func, arg, buf);
+}
+
+void
+_threadinfo::call2 (DWORD (*func) (void *, void *), void *arg, void *buf)
+{
+ exception_list except_entry;
+ /* Initialize this thread's ability to respond to things like
+ SIGSEGV or SIGFPE. */
+ init_exceptions (&except_entry);
+ _my_tls.init_thread (buf, func);
+ DWORD res = func (arg, buf);
+ _my_tls.remove (INFINITE);
+ ExitThread (res);
+}
+
+void
+_threadinfo::init_thread (void *x, DWORD (*func) (void *, void *))
+{
+ if (x)
+ {
+ memset (this, 0, CYGTLS_PADSIZE);
+ stackptr = stack;
+ if (_GLOBAL_REENT)
+ {
+ local_clib._stdin = _GLOBAL_REENT->_stdin;
+ local_clib._stdout = _GLOBAL_REENT->_stdout;
+ local_clib._stderr = _GLOBAL_REENT->_stderr;
+ local_clib.__sdidinit = _GLOBAL_REENT->__sdidinit;
+ local_clib.__cleanup = _GLOBAL_REENT->__cleanup;
+ }
+ local_clib._current_locale = "C";
+ locals.process_logmask = LOG_UPTO (LOG_DEBUG);
+ }
+
+ set_state (false);
+ errno_addr = &(local_clib._errno);
+
+ if ((void *) func == (void *) cygthread::stub
+ || (void *) func == (void *) cygthread::simplestub)
+ return;
+
+ sentry here (INFINITE);
+ if (nthreads >= cygheap->sthreads)
+ {
+ cygheap->threadlist = (_threadinfo **)
+ crealloc (cygheap->threadlist, (cygheap->sthreads += THREADLIST_CHUNK)
+ * sizeof (cygheap->threadlist[0]));
+ memset (cygheap->threadlist + nthreads, 0, THREADLIST_CHUNK * sizeof (cygheap->threadlist[0]));
+ }
+
+ cygheap->threadlist[nthreads++] = this;
+}
+
+void
+_threadinfo::remove (DWORD wait)
+{
+ debug_printf ("wait %p\n", wait);
+ sentry here (wait);
+ if (here.acquired ())
+ {
+ for (size_t i = 0; i < nthreads; i++)
+ if (&_my_tls == cygheap->threadlist[i])
+ {
+ if (i < --nthreads)
+ cygheap->threadlist[i] = cygheap->threadlist[nthreads];
+ break;
+ }
+ }
+}
+
+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;
+#ifdef DEBUGGING
+ *stackptr = 0;
+ debug_printf ("popped %p, stack %p, stackptr %p", res, stack, stackptr);
+#endif
+ return res;
+}
+
+#define BAD_IX ((size_t) -1)
+static size_t NO_COPY threadlist_ix = BAD_IX;
+
+_threadinfo *
+_threadinfo::find_tls (int sig)
+{
+ debug_printf ("sig %d\n", sig);
+ sentry here (INFINITE);
+ __asm__ volatile (".equ _threadlist_exception_return,.");
+ _threadinfo *res = NULL;
+ for (threadlist_ix = 0; threadlist_ix < nthreads; threadlist_ix++)
+ if (sigismember (&(cygheap->threadlist[threadlist_ix]->sigwait_mask), sig))
+ {
+ res = cygheap->threadlist[threadlist_ix];
+ break;
+ }
+ threadlist_ix = BAD_IX;
+ return res;
+}
+
+extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD);
+static int
+handle_threadlist_exception (EXCEPTION_RECORD *e, void *frame, CONTEXT *, void *)
+{
+ if (e->ExceptionCode != STATUS_ACCESS_VIOLATION)
+ {
+ system_printf ("handle_threadlist_exception called with exception code %d\n",
+ e->ExceptionCode);
+ return 1;
+ }
+
+ sentry here;
+ if (threadlist_ix == BAD_IX)
+ {
+ system_printf ("handle_threadlist_exception called with threadlist_ix %d\n",
+ BAD_IX);
+ return 1;
+ }
+
+ if (!here.acquired ())
+ {
+ system_printf ("handle_threadlist_exception couldn't aquire muto\n");
+ return 1;
+ }
+
+ extern void *threadlist_exception_return;
+ cygheap->threadlist[threadlist_ix]->remove (INFINITE);
+ threadlist_ix = 0;
+ RtlUnwind (frame, threadlist_exception_return, e, 0);
+ return 0;
+}
+
+void
+_threadinfo::init_threadlist_exceptions (exception_list *el)
+{
+ extern void init_exception_handler (exception_list *, exception_handler *);
+ init_exception_handler (el, handle_threadlist_exception);
+}