diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2011-05-15 18:49:40 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2011-05-15 18:49:40 +0000 |
commit | cdb4231369f4c06795e170f9cb003d8de1581f5b (patch) | |
tree | dd008237ecd92aa1101affbc9577809aa49b8dd5 /winsup/cygwin/miscfuncs.cc | |
parent | 2922c6c4aaa754fee3fcaecddd618ec9dff84cc5 (diff) | |
download | cygnal-cdb4231369f4c06795e170f9cb003d8de1581f5b.tar.gz cygnal-cdb4231369f4c06795e170f9cb003d8de1581f5b.tar.bz2 cygnal-cdb4231369f4c06795e170f9cb003d8de1581f5b.zip |
* cygwin.din (pthread_attr_getguardsize): Export.
(pthread_attr_setguardsize): Export.
(pthread_attr_setstack): Export.
(pthread_attr_setstackaddr): Export.
* init.cc (dll_entry): Remove wow64_test_stack_marker. Check for
unusual stack address by testing stack addresses from current TEB.
Check validity of _my_tls by testing if it's within the stack as
given in current TEB.
* miscfuncs.cc (struct thread_wrapper_arg): New structure used to
push all required information to thread_wrapper function.
(thread_wrapper): Wrapper function for actual thread function.
If an application stack has been given, change %ebp and %esp so that
the thread function runs on that stack. If the thread has been created
by CygwinCreateThread, set up the POSIX guard pages if necessary.
(CygwinCreateThread): New function.
* miscfuncs.h (CygwinCreateThread): Declare.
* ntdll.h (struct _TEB): Define all members up to Peb.
* posix.sgml (std-susv4): Move pthread_attr_getguardsize,
pthread_attr_setguardsize and pthread_attr_setstack here.
(std-deprec): Add pthread_attr_setstackaddr.
* sysconf.cc (sca): Set _SC_THREAD_ATTR_STACKADDR to
_POSIX_THREAD_ATTR_STACKADDR.
* thread.cc (pthread::precreate): Copy pthread_attr stackaddr and
guardsize members.
(pthread::create): Call CygwinCreateThread.
(pthread_attr::pthread_attr): Initialize guardsize.
(pthread_attr_setstack): New function.
(pthread_attr_setstackaddr): New function.
(pthread_attr_setguardsize): New function.
(pthread_attr_getguardsize): New function.
(pthread_getattr_np): Copy attr.guardsize.
* thread.h (pthread_attr): Add member guardsize.
* include/pthread.h (pthread_attr_getguardsize): Declare.
(pthread_attr_setguardsize): Declare.
* include/cygwin/version.h: Bump API minor number.
Diffstat (limited to 'winsup/cygwin/miscfuncs.cc')
-rw-r--r-- | winsup/cygwin/miscfuncs.cc | 142 |
1 files changed, 141 insertions, 1 deletions
diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index 706347240..0e2945125 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -1,7 +1,7 @@ /* miscfuncs.cc: misc funcs that don't belong anywhere else Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2011 Red Hat, Inc. + 2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. This file is part of Cygwin. @@ -15,12 +15,17 @@ details. */ #include <assert.h> #include <alloca.h> #include <limits.h> +#include <sys/param.h> #include <wchar.h> #include <wingdi.h> #include <winuser.h> #include <winnls.h> #include "cygtls.h" #include "ntdll.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" long tls_ix = -1; @@ -376,3 +381,138 @@ slashify (const char *src, char *dst, bool trailing_slash_p) *dst++ = '/'; *dst++ = 0; } + +/* CygwinCreateThread. + + Replacement function for CreateThread. What we do here is to remove + parameters we don't use and instead to add parameters we need to make + the function pthreads compatible. */ + +struct thread_wrapper_arg +{ + LPTHREAD_START_ROUTINE func; + PVOID arg; + PVOID stackaddr; + ULONG stacksize; + ULONG guardsize; +}; + +DWORD WINAPI +thread_wrapper (VOID *arg) +{ + if (!arg) + return ERROR_INVALID_PARAMETER; + + thread_wrapper_arg wrapper_arg = *(thread_wrapper_arg *) arg; + cfree (arg); + + if (wrapper_arg.stackaddr) + { + /* If the application provided the stack, we must make sure that + it's actually used by the thread function. So what we do here is + to compute the stackbase of the application-provided stack and + change the stack pointer accordingly. + + NOTE: _my_tls is on the stack created by CreateThread! It's + unlikely the tls structure will ever exceed 64K, but if + so, we have to raise the size of the stack in the call + to CreateThread, too. */ + wrapper_arg.stackaddr = (PVOID) ((PBYTE) wrapper_arg.stackaddr + + wrapper_arg.stacksize + - sizeof (PVOID)); + __asm__ ("\n\ + movl %[WRAPPER_ARG], %%ebx \n\ + movl (%%ebx), %%eax \n\ + movl 4(%%ebx), %%ecx \n\ + movl 8(%%ebx), %%edx \n\ + xorl %%ebp, %%ebp \n\ + movl %%edx, %%esp \n\ + pushl %%ecx \n\ + pushl %%eax \n\ + jmp *%%eax \n" : : [WRAPPER_ARG] "r" (&wrapper_arg)); + + } + if (wrapper_arg.guardsize) + { + /* Set up POSIX guard pages. Note that this is not the same as the + PAGE_GUARD protection. Rather, the POSIX guard pages are a + PAGE_NOACCESS protected area which is supposed to guard against + stack overflow and to trigger a SIGSEGV if that happens. */ + PNT_TIB tib = &NtCurrentTeb ()->Tib; + wrapper_arg.stackaddr = (PVOID) ((PBYTE) tib->StackBase + - wrapper_arg.stacksize); + if (!VirtualAlloc (wrapper_arg.stackaddr, wrapper_arg.guardsize, + MEM_COMMIT, PAGE_NOACCESS)) + system_printf ("VirtualAlloc, %E"); + } + __asm__ ("\n\ + movl %[WRAPPER_ARG], %%ebx \n\ + movl (%%ebx), %%eax \n\ + movl 4(%%ebx), %%ecx \n\ + pushl %%ecx \n\ + pushl %%eax \n\ + jmp *%%eax \n" : : [WRAPPER_ARG] "r" (&wrapper_arg)); + /* Never reached. */ + return ERROR_INVALID_FUNCTION; +} + +/* FIXME: This should be settable via setrlimit (RLIMIT_STACK). */ +#define DEFAULT_STACKSIZE (512 * 1024) + +HANDLE WINAPI +CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg, + PVOID stackaddr, ULONG stacksize, ULONG guardsize, + DWORD creation_flags, LPDWORD thread_id) +{ + ULONG real_stacksize = 0; + ULONG real_guardsize = 0; + thread_wrapper_arg *wrapper_arg; + + wrapper_arg = (thread_wrapper_arg *) ccalloc (HEAP_STR, 1, + sizeof *wrapper_arg); + if (!wrapper_arg) + { + SetLastError (ERROR_OUTOFMEMORY); + return NULL; + } + wrapper_arg->func = thread_func; + wrapper_arg->arg = thread_arg; + + /* Set stacksize. */ + real_stacksize = stacksize ?: DEFAULT_STACKSIZE; + if (real_stacksize < PTHREAD_STACK_MIN) + real_stacksize = PTHREAD_STACK_MIN; + if (stackaddr) + { + wrapper_arg->stackaddr = stackaddr; + wrapper_arg->stacksize = real_stacksize; + real_stacksize = PTHREAD_STACK_MIN; + } + else + { + /* If not, we have to create the stack here. */ + real_stacksize = roundup2 (real_stacksize, wincap.page_size ()); + /* If no guardsize has been specified by the application, use the + system pagesize as default. */ + real_guardsize = (guardsize != 0xffffffff) + ? guardsize : wincap.page_size (); + if (real_guardsize) + real_guardsize = roundup2 (real_guardsize, wincap.page_size ()); + /* If the default stacksize is used and guardsize has not been specified, + don't add a guard page to the size. */ + if (stacksize && guardsize != 0xffffffff) + real_stacksize += real_guardsize; + /* Now roundup the result to the next allocation boundary. */ + real_stacksize = roundup2 (real_stacksize, + wincap.allocation_granularity ()); + + wrapper_arg->stacksize = real_stacksize; + wrapper_arg->guardsize = real_guardsize; + } + /* Use the STACK_SIZE_PARAM_IS_A_RESERVATION parameter to make sure the + stack size is exactly the size we want. */ + return CreateThread (&sec_none_nih, real_stacksize, thread_wrapper, + wrapper_arg, + creation_flags | STACK_SIZE_PARAM_IS_A_RESERVATION, + thread_id); +} |