* 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.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user