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:
Diffstat (limited to 'winsup/cygwin/cygtls.cc')
-rw-r--r--winsup/cygwin/cygtls.cc161
1 files changed, 87 insertions, 74 deletions
diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc
index abda77c5f..f45cfaa52 100644
--- a/winsup/cygwin/cygtls.cc
+++ b/winsup/cygwin/cygtls.cc
@@ -1,7 +1,6 @@
/* cygtls.cc
- Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
- 2012 Red Hat, Inc.
+ Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
@@ -19,6 +18,39 @@ details. */
#include "sigproc.h"
#include "exception.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 _cygtls::init ();
+};
+
+muto NO_COPY sentry::lock;
+
+static size_t NO_COPY nthreads;
+
+#define THREADLIST_CHUNK 256
+
+void
+_cygtls::init ()
+{
+ if (cygheap->threadlist)
+ memset (cygheap->threadlist, 0, cygheap->sthreads * sizeof (cygheap->threadlist[0]));
+ else
+ {
+ cygheap->sthreads = THREADLIST_CHUNK;
+ cygheap->threadlist = (_cygtls **) ccalloc_abort (HEAP_TLS, cygheap->sthreads,
+ sizeof (cygheap->threadlist[0]));
+ }
+ sentry::lock.init ("sentry_lock");
+}
+
/* Two calls to get the stack right... */
void
_cygtls::call (DWORD (*func) (void *, void *), void *arg)
@@ -30,72 +62,10 @@ _cygtls::call (DWORD (*func) (void *, void *), void *arg)
_my_tls.call2 (func, arg, buf);
}
-static int
-dll_cmp (const void *a, const void *b)
-{
- return wcscasecmp ((const wchar_t *) a, *(const wchar_t **) b);
-}
-
-/* Keep sorted!
- This is a list of well-known core system DLLs which contain code
- whiuch is started in its own thread by the system. Kernel32.dll,
- for instance, contains the thread called on every Ctrl-C keypress
- in a console window. The DLLs in this list are not recognized as
- BLODAs. */
-const wchar_t *well_known_dlls[] =
-{
- L"advapi32.dll",
- L"kernel32.dll",
- L"mswsock.dll",
- L"ntdll.dll",
- L"ole32.dll",
- L"shlwapi.dll",
- L"wbemprox.dll",
- L"ws2_32.dll",
-};
-
void
_cygtls::call2 (DWORD (*func) (void *, void *), void *arg, void *buf)
{
init_thread (buf, func);
-
- /* Optional BLODA detection. The idea is that the function address is
- supposed to be within Cygwin itself. This is also true for pthreads,
- since pthreads are always calling thread_wrapper in miscfuncs.cc.
- Therefore, every function call to a function outside of the Cygwin DLL
- is potentially a thread injected into the Cygwin process by some BLODA.
-
- But that's a bit too simple. Assuming the application itself calls
- CreateThread, then this is a bad idea, but not really invalid. So we
- shouldn't print a BLODA message if the address is within the loaded
- image of the application. Also, ntdll.dll starts threads into the
- application which */
- if (detect_bloda)
- {
- PIMAGE_DOS_HEADER img_start = (PIMAGE_DOS_HEADER) GetModuleHandle (NULL);
- PIMAGE_NT_HEADERS32 ntheader = (PIMAGE_NT_HEADERS32)
- ((PBYTE) img_start + img_start->e_lfanew);
- void *img_end = (void *) ((PBYTE) img_start
- + ntheader->OptionalHeader.SizeOfImage);
- if (((void *) func < (void *) cygwin_hmodule
- || (void *) func > (void *) cygheap)
- && ((void *) func < (void *) img_start || (void *) func >= img_end))
- {
- MEMORY_BASIC_INFORMATION mbi;
- wchar_t modname[PATH_MAX];
-
- VirtualQuery ((PVOID) func, &mbi, sizeof mbi);
- GetModuleFileNameW ((HMODULE) mbi.AllocationBase, modname, PATH_MAX);
- /* Fetch basename and check against list of above system DLLs. */
- const wchar_t *modbasename = wcsrchr (modname, L'\\') + 1;
- if (!bsearch (modbasename, well_known_dlls,
- sizeof well_known_dlls / sizeof well_known_dlls[0],
- sizeof well_known_dlls[0], dll_cmp))
- small_printf ("\n\nPotential BLODA detected! Thread function "
- "called outside of Cygwin DLL:\n %W\n\n", modname);
- }
- }
-
DWORD res = func (arg, buf);
remove (INFINITE);
/* Don't call ExitThread on the main thread since we may have been
@@ -134,7 +104,18 @@ _cygtls::init_thread (void *x, DWORD (*func) (void *, void *))
|| (void *) func == (void *) cygthread::simplestub)
return;
- cygheap->add_tls (this);
+ cygheap->user.reimpersonate ();
+
+ sentry here (INFINITE);
+ if (nthreads >= cygheap->sthreads)
+ {
+ cygheap->threadlist = (_cygtls **)
+ crealloc_abort (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
@@ -146,7 +127,6 @@ _cygtls::fixup_after_fork ()
sig = 0;
}
stacklock = spinning = 0;
- signal_arrived = NULL;
locals.select.sockevt = NULL;
locals.cw_timer = NULL;
wq.thread_ev = NULL;
@@ -171,13 +151,6 @@ _cygtls::remove (DWORD wait)
/* FIXME: Need some sort of atthreadexit function to allow things like
select to control this themselves. */
- if (signal_arrived)
- {
- HANDLE h = signal_arrived;
- signal_arrived = NULL;
- CloseHandle (h);
- }
-
/* Close handle and free memory used by select. */
if (locals.select.sockevt)
{
@@ -193,7 +166,22 @@ _cygtls::remove (DWORD wait)
free_local (hostent_buf);
/* Free temporary TLS path buffers. */
locals.pathbufs.destroy ();
- cygheap->remove_tls (this, wait);
+
+ do
+ {
+ sentry here (wait);
+ if (here.acquired ())
+ {
+ for (size_t i = 0; i < nthreads; i++)
+ if (this == cygheap->threadlist[i])
+ {
+ if (i < --nthreads)
+ cygheap->threadlist[i] = cygheap->threadlist[nthreads];
+ debug_printf ("removed %p element %d", this, i);
+ break;
+ }
+ }
+ } while (0);
remove_wq (wait);
}
@@ -203,6 +191,31 @@ _cygtls::push (__stack_t addr)
*stackptr++ = (__stack_t) addr;
}
+
+_cygtls *
+_cygtls::find_tls (int sig)
+{
+ static int NO_COPY threadlist_ix;
+
+ debug_printf ("signal %d\n", sig);
+ sentry here (INFINITE);
+
+ _cygtls *res = NULL;
+ threadlist_ix = -1;
+
+ myfault efault;
+ if (efault.faulted ())
+ cygheap->threadlist[threadlist_ix]->remove (INFINITE);
+
+ while (++threadlist_ix < (int) nthreads)
+ if (sigismember (&(cygheap->threadlist[threadlist_ix]->sigwait_mask), sig))
+ {
+ res = cygheap->threadlist[threadlist_ix];
+ break;
+ }
+ return res;
+}
+
void
_cygtls::set_siginfo (sigpacket *pack)
{