* child_info.h (CURR_CHILD_INFO_MAGIC): Update.

(class child_info_fork): Remove stacksize, add stackaddr and guardsize
	members.
	* dcrt0.cc (child_info_fork::alloc_stack_hard_way): Partial rewrite
	to regenerate the stack exactly as in the parent.
	(child_info_fork::alloc_stack): Set stackaddr to 0, rather than
	stacksize.
	(dll_crt0_1): Check for stackaddr before changing the stack addresses
	in the TEB.
	* fork.cc (frok::child): Check for stackaddr here.
	(frok::parent): Set ch.stackaddr and ch.guardsize if not called from
	the main thread.
	* init.cc (dll_entry): Replace pointer to NT_TIB with pointer to TEB.
	Fix incorrectly changed address test before removing _my_tls.
	Set StackLimit to NULL on Windows 2000.  Explain why.
	* miscfuncs.cc (struct thread_wrapper_arg): Store stackbase rather
	than stacksize, store commitaddr, remove guardsize.  Store all pointers
	as char * for easier address arithmetic.
	(thread_wrapper): Rewrite to remove OS stack before calling thread
	function.  Add lots of comments to explain what we do.
	(CygwinCreateThread): Reserve our own stack in case we got no
	application stack.  Add comments.
	* ntdll.h (struct _TEB): Extend defintion up to DeallocationStack
	member.
	* thread.cc (pthread_attr::pthread_attr): Use "(size_t) -1"
	rather then 0xffffffff.
	* wincap.h (wincaps::has_stack_size_param_is_a_reservation): New
	element.
	* wincap.cc: Implement above element throughout.
This commit is contained in:
Corinna Vinschen 2011-05-20 07:23:11 +00:00
parent 660302eb67
commit 89d3c72d51
10 changed files with 294 additions and 126 deletions

View File

@ -1,3 +1,35 @@
2011-05-20 Corinna Vinschen <corinna@vinschen.de>
* child_info.h (CURR_CHILD_INFO_MAGIC): Update.
(class child_info_fork): Remove stacksize, add stackaddr and guardsize
members.
* dcrt0.cc (child_info_fork::alloc_stack_hard_way): Partial rewrite
to regenerate the stack exactly as in the parent.
(child_info_fork::alloc_stack): Set stackaddr to 0, rather than
stacksize.
(dll_crt0_1): Check for stackaddr before changing the stack addresses
in the TEB.
* fork.cc (frok::child): Check for stackaddr here.
(frok::parent): Set ch.stackaddr and ch.guardsize if not called from
the main thread.
* init.cc (dll_entry): Replace pointer to NT_TIB with pointer to TEB.
Fix incorrectly changed address test before removing _my_tls.
Set StackLimit to NULL on Windows 2000. Explain why.
* miscfuncs.cc (struct thread_wrapper_arg): Store stackbase rather
than stacksize, store commitaddr, remove guardsize. Store all pointers
as char * for easier address arithmetic.
(thread_wrapper): Rewrite to remove OS stack before calling thread
function. Add lots of comments to explain what we do.
(CygwinCreateThread): Reserve our own stack in case we got no
application stack. Add comments.
* ntdll.h (struct _TEB): Extend defintion up to DeallocationStack
member.
* thread.cc (pthread_attr::pthread_attr): Use "(size_t) -1"
rather then 0xffffffff.
* wincap.h (wincaps::has_stack_size_param_is_a_reservation): New
element.
* wincap.cc: Implement above element throughout.
2011-05-19 Yaakov Selkowitz <yselkowitz@users.sourceforge.net> 2011-05-19 Yaakov Selkowitz <yselkowitz@users.sourceforge.net>
* thread.cc: Mark psiginfo and psignal as available in list of * thread.cc: Mark psiginfo and psignal as available in list of

View File

@ -37,7 +37,7 @@ enum child_status
#define EXEC_MAGIC_SIZE sizeof(child_info) #define EXEC_MAGIC_SIZE sizeof(child_info)
/* Change this value if you get a message indicating that it is out-of-sync. */ /* Change this value if you get a message indicating that it is out-of-sync. */
#define CURR_CHILD_INFO_MAGIC 0xe850717aU #define CURR_CHILD_INFO_MAGIC 0xbdf5842aU
/* NOTE: Do not make gratuitous changes to the names or organization of the /* NOTE: Do not make gratuitous changes to the names or organization of the
below class. The layout is checksummed to determine compatibility between below class. The layout is checksummed to determine compatibility between
@ -80,10 +80,12 @@ class child_info_fork: public child_info
{ {
public: public:
HANDLE forker_finished;// for synchronization with child HANDLE forker_finished;// for synchronization with child
DWORD stacksize; // size of parent stack
jmp_buf jmp; // where child will jump to jmp_buf jmp; // where child will jump to
void *stackaddr; // address of parent stack
void *stacktop; // location of top of parent stack void *stacktop; // location of top of parent stack
void *stackbottom; // location of bottom of parent stack void *stackbottom; // location of bottom of parent stack
size_t guardsize; // size of POSIX guard region or (size_t) -1 if
// user stack
char filler[4]; char filler[4];
child_info_fork (); child_info_fork ();
void handle_fork () __attribute__ ((regparm (1)));; void handle_fork () __attribute__ ((regparm (1)));;

View File

@ -392,14 +392,11 @@ child_info NO_COPY *child_proc_info = NULL;
void void
child_info_fork::alloc_stack_hard_way (volatile char *b) child_info_fork::alloc_stack_hard_way (volatile char *b)
{ {
void *new_stack_pointer; void *stack_ptr;
MEMORY_BASIC_INFORMATION m; DWORD stacksize;
void *newbase;
int newlen;
bool guard;
/* First check if the requested stack area is part of the user heap /* First check if the requested stack area is part of the user heap
or part of a mmaped region. If so, we have been started from a or part of a mmapped region. If so, we have been started from a
pthread with an application-provided stack, and the stack has just pthread with an application-provided stack, and the stack has just
to be used as is. */ to be used as is. */
if ((stacktop >= cygheap->user_heap.base if ((stacktop >= cygheap->user_heap.base
@ -407,46 +404,33 @@ child_info_fork::alloc_stack_hard_way (volatile char *b)
|| is_mmapped_region ((caddr_t) stacktop, (caddr_t) stackbottom)) || is_mmapped_region ((caddr_t) stacktop, (caddr_t) stackbottom))
return; return;
if (!VirtualQuery ((LPCVOID) &b, &m, sizeof m)) /* First, try to reserve the entire stack. */
api_fatal ("fork: couldn't get stack info, %E"); stacksize = (char *) stackbottom - (char *) stackaddr;
if (!VirtualAlloc (stackaddr, stacksize, MEM_RESERVE, PAGE_NOACCESS))
LPBYTE curbot = (LPBYTE) m.BaseAddress + m.RegionSize;
if (stacktop > (LPBYTE) m.AllocationBase && stacktop < curbot)
{
newbase = curbot;
newlen = (LPBYTE) stackbottom - (LPBYTE) curbot;
guard = false;
}
else
{
newbase = (LPBYTE) stacktop - (128 * 1024);
newlen = (LPBYTE) stackbottom - (LPBYTE) newbase;
guard = true;
}
if (!VirtualAlloc (newbase, newlen, MEM_RESERVE, PAGE_NOACCESS))
api_fatal ("fork: can't reserve memory for stack %p - %p, %E", api_fatal ("fork: can't reserve memory for stack %p - %p, %E",
stacktop, stackbottom); stackaddr, stackbottom);
new_stack_pointer = (void *) ((LPBYTE) stackbottom - (stacksize += 8192)); stacksize = (char *) stackbottom - (char *) stacktop;
if (!VirtualAlloc (new_stack_pointer, stacksize, MEM_COMMIT, stack_ptr = VirtualAlloc (stacktop, stacksize, MEM_COMMIT,
PAGE_EXECUTE_READWRITE)) PAGE_EXECUTE_READWRITE);
if (!stack_ptr)
api_fatal ("fork: can't commit memory for stack %p(%d), %E", api_fatal ("fork: can't commit memory for stack %p(%d), %E",
new_stack_pointer, stacksize); stacktop, stacksize);
if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m)) if (guardsize != (size_t) -1)
api_fatal ("fork: couldn't get new stack info, %E");
if (guard)
{ {
m.BaseAddress = (LPBYTE) m.BaseAddress - 1; /* Allocate PAGE_GUARD page if it still fits. */
if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT, if (stack_ptr > stackaddr)
{
stack_ptr = (void *) ((LPBYTE) stack_ptr
- wincap.page_size ());
if (!VirtualAlloc (stack_ptr, wincap.page_size (), MEM_COMMIT,
CYGWIN_GUARD)) CYGWIN_GUARD))
api_fatal ("fork: couldn't allocate new stack guard page %p, %E", api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
m.BaseAddress); stack_ptr);
}
/* Allocate POSIX guard pages. */
if (guardsize > 0)
VirtualAlloc (stackaddr, guardsize, MEM_COMMIT, PAGE_NOACCESS);
} }
if (!VirtualQuery ((LPCVOID) m.BaseAddress, &m, sizeof m))
api_fatal ("fork: couldn't get new stack info, %E");
stacktop = m.BaseAddress;
b[0] = '\0'; b[0] = '\0';
} }
@ -473,7 +457,7 @@ child_info_fork::alloc_stack ()
char *st = (char *) stacktop - 4096; char *st = (char *) stacktop - 4096;
while (_tlstop >= st) while (_tlstop >= st)
esp = getstack (esp); esp = getstack (esp);
stacksize = 0; stackaddr = 0;
} }
} }
@ -811,7 +795,7 @@ dll_crt0_1 (void *)
NOTE: Don't do anything that involves the stack until you've completed NOTE: Don't do anything that involves the stack until you've completed
this step. */ this step. */
if (fork_info->stacksize) if (fork_info->stackaddr)
{ {
_tlsbase = (char *) fork_info->stackbottom; _tlsbase = (char *) fork_info->stackbottom;
_tlstop = (char *) fork_info->stacktop; _tlstop = (char *) fork_info->stacktop;

View File

@ -25,6 +25,7 @@ details. */
#include "tls_pbuf.h" #include "tls_pbuf.h"
#include "dll_init.h" #include "dll_init.h"
#include "cygmalloc.h" #include "cygmalloc.h"
#include "ntdll.h"
#define NPIDS_HELD 4 #define NPIDS_HELD 4
@ -178,7 +179,7 @@ frok::child (volatile char * volatile here)
/* If we've played with the stack, stacksize != 0. That means that /* If we've played with the stack, stacksize != 0. That means that
fork() was invoked from other than the main thread. Make sure that fork() was invoked from other than the main thread. Make sure that
the threadinfo information is properly set up. */ the threadinfo information is properly set up. */
if (fork_info->stacksize) if (fork_info->stackaddr)
{ {
_main_tls = &_my_tls; _main_tls = &_my_tls;
_main_tls->init_thread (NULL, NULL); _main_tls->init_thread (NULL, NULL);
@ -327,10 +328,33 @@ frok::parent (volatile char * volatile stack_here)
ch.forker_finished = forker_finished; ch.forker_finished = forker_finished;
ch.stackbottom = _tlsbase; ch.stackbottom = _tlsbase;
ch.stacktop = (void *) stack_here; ch.stacktop = (void *) _tlstop;
ch.stacksize = (char *) ch.stackbottom - (char *) stack_here; ch.stackaddr = 0;
debug_printf ("stack - bottom %p, top %p, size %d", ch.guardsize = 0;
ch.stackbottom, ch.stacktop, ch.stacksize); if (&_my_tls != _main_tls)
{
/* We have not been started from the main thread. Fetch the
information required to set up the thread stack identically
in the child. */
PTEB teb = NtCurrentTeb ();
if (!teb->DeallocationStack)
{
/* Pthread with application-provided stack. Don't set up a
PAGE_GUARD page. guardsize == -1 is used in alloc_stack_hard_way
to recognize this type of stack. */
ch.stackaddr = _my_tls.tid->attr.stackaddr;
ch.guardsize = (size_t) -1;
}
else
{
ch.stackaddr = teb->DeallocationStack;
/* If it's a pthread, fetch guardsize from thread attributes. */
if (_my_tls.tid)
ch.guardsize = _my_tls.tid->attr.guardsize;
}
}
debug_printf ("stack - bottom %p, top %p, addr %p, guardsize %p",
ch.stackbottom, ch.stacktop, ch.stackaddr, ch.guardsize);
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
STARTUPINFOW si; STARTUPINFOW si;

View File

@ -115,7 +115,7 @@ extern void __stdcall dll_crt0_0 ();
extern "C" BOOL WINAPI extern "C" BOOL WINAPI
dll_entry (HANDLE h, DWORD reason, void *static_load) dll_entry (HANDLE h, DWORD reason, void *static_load)
{ {
PNT_TIB tib; PTEB teb;
switch (reason) switch (reason)
{ {
@ -131,10 +131,10 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
the auto load address of DLLs? the auto load address of DLLs?
Check if we're running in WOW64 on a 64 bit machine *and* are Check if we're running in WOW64 on a 64 bit machine *and* are
spawned by a genuine 64 bit process. If so, respawn. */ spawned by a genuine 64 bit process. If so, respawn. */
tib = &NtCurrentTeb ()->Tib; teb = NtCurrentTeb ();
if (wincap.is_wow64 () if (wincap.is_wow64 ()
&& tib->StackLimit >= (PBOOL) 0x400000 && teb->Tib.StackLimit >= (PBOOL) 0x400000
&& tib->StackBase <= (PBOOL) 0x10000000) && teb->Tib.StackBase <= (PBOOL) 0x10000000)
respawn_wow64_process (); respawn_wow64_process ();
dll_crt0_0 (); dll_crt0_0 ();
@ -150,12 +150,19 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
munge_threadfunc (); munge_threadfunc ();
break; break;
case DLL_THREAD_DETACH: case DLL_THREAD_DETACH:
tib = &NtCurrentTeb ()->Tib; teb = NtCurrentTeb ();
if (dll_finished_loading if (dll_finished_loading
&& (PVOID) &_my_tls >= tib->StackLimit && (PVOID) &teb >= teb->Tib.StackLimit
&& (PVOID) &_my_tls < tib->StackBase && (PVOID) &teb < teb->Tib.StackBase
&& _my_tls.isinitialized ()) && _my_tls.isinitialized ())
_my_tls.remove (0); _my_tls.remove (0);
/* Windows 2000 has a bug in NtTerminateThread. Instead of releasing
the stack at teb->DeallocationStack it uses the value of
teb->Tib.StackLimit to evaluate the stack address. So we just claim
there is no stack. */
if (teb->DeallocationStack == NULL
&& !wincap.has_stack_size_param_is_a_reservation ())
teb->Tib.StackLimit = NULL;
break; break;
} }

View File

@ -26,6 +26,8 @@ details. */
#include "fhandler.h" #include "fhandler.h"
#include "dtable.h" #include "dtable.h"
#include "cygheap.h" #include "cygheap.h"
#include "pinfo.h"
#include "exception.h"
long tls_ix = -1; long tls_ix = -1;
@ -392,72 +394,109 @@ struct thread_wrapper_arg
{ {
LPTHREAD_START_ROUTINE func; LPTHREAD_START_ROUTINE func;
PVOID arg; PVOID arg;
PVOID stackaddr; char *stackaddr;
ULONG stacksize; char *stackbase;
ULONG guardsize; char *commitaddr;
}; };
DWORD WINAPI DWORD WINAPI
thread_wrapper (VOID *arg) thread_wrapper (VOID *arg)
{ {
/* Just plain paranoia. */
if (!arg) if (!arg)
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
/* Fetch thread wrapper info and free from cygheap. */
thread_wrapper_arg wrapper_arg = *(thread_wrapper_arg *) arg; thread_wrapper_arg wrapper_arg = *(thread_wrapper_arg *) arg;
cfree (arg); cfree (arg);
if (wrapper_arg.stackaddr) /* Remove _cygtls from this stack since it won't be used anymore. */
{ _cygtls *tls;
/* If the application provided the stack, we must make sure that tls = &_my_tls;
it's actually used by the thread function. So what we do here is
to compute the stackbase of the application-provided stack, move
_my_tls to the stackbase, and change the stack pointer accordingly. */
_my_tls.remove (0); _my_tls.remove (0);
wrapper_arg.stackaddr = (PVOID) ((PBYTE) wrapper_arg.stackaddr
+ wrapper_arg.stacksize);
_tlsbase = (char *) wrapper_arg.stackaddr;
wrapper_arg.stackaddr = (PVOID) ((PBYTE) wrapper_arg.stackaddr
- CYGTLS_PADSIZE);
_tlstop = (char *) wrapper_arg.stackaddr;
_my_tls.init_thread ((char *) wrapper_arg.stackaddr,
(DWORD (*)(void*, void*)) wrapper_arg.func);
wrapper_arg.stackaddr = (PVOID) (_tlstop - sizeof (PVOID));
__asm__ ("\n\
movl %[WRAPPER_ARG], %%ebx # Load &wrapper_arg into ebx \n\
movl (%%ebx), %%eax # Load thread func into eax \n\
movl 4(%%ebx), %%ecx # Load thread arg into ecx \n\
movl 8(%%ebx), %%edx # Load stackbase into edx \n\
xorl %%ebp, %%ebp # Set ebp to 0 \n\
movl %%edx, %%esp # Set esp to stackbase \n\
pushl %%ecx # Push thread arg onto stack \n\
pushl %%eax # Push thread func onto stack \n\
jmp *%%eax # Jump to thread func \n"
: : [WRAPPER_ARG] "r" (&wrapper_arg));
} /* Set stack values in TEB */
if (wrapper_arg.guardsize) PTEB teb = NtCurrentTeb ();
teb->Tib.StackBase = wrapper_arg.stackbase;
teb->Tib.StackLimit = wrapper_arg.commitaddr ?: wrapper_arg.stackaddr;
/* Set DeallocationStack value. If we have an application-provided stack,
we set DeallocationStack to NULL, so NtTerminateThread does not deallocate
any stack. If we created the stack in CygwinCreateThread, we set
DeallocationStack to the stackaddr of our own stack, so it's automatically
deallocated when the thread is terminated. */
char *dealloc_addr = (char *) teb->DeallocationStack;
teb->DeallocationStack = wrapper_arg.commitaddr ? wrapper_arg.stackaddr
: NULL;
/* Store the OS-provided DeallocationStack address in wrapper_arg.stackaddr.
The below assembler code will release the OS stack after switching to our
new stack. */
wrapper_arg.stackaddr = dealloc_addr;
/* Initialize new _cygtls. */
_my_tls.init_thread (wrapper_arg.stackbase - CYGTLS_PADSIZE,
(DWORD (*)(void*, void*)) wrapper_arg.func);
/* Copy exception list over to new stack. I'm not quite sure how the
exception list is extended by Windows itself. What's clear is that it
always grows downwards and that it starts right at the stackbase.
Therefore we first count the number of exception records and place
the copy at the stackbase, too, so there's still a lot of room to
extend the list up to where our _cygtls region starts. */
_exception_list *old_start = (_exception_list *) teb->Tib.ExceptionList;
unsigned count = 0;
teb->Tib.ExceptionList = NULL;
for (_exception_list *e_ptr = old_start;
e_ptr && e_ptr != (_exception_list *) -1;
e_ptr = e_ptr->prev)
++count;
if (count)
{ {
/* Set up POSIX guard pages. Note that this is not the same as the _exception_list *new_start = (_exception_list *) wrapper_arg.stackbase
PAGE_GUARD protection. Rather, the POSIX guard pages are a - count;
PAGE_NOACCESS protected area which is supposed to guard against teb->Tib.ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)
stack overflow and to trigger a SIGSEGV if that happens. */ new_start;
PNT_TIB tib = &NtCurrentTeb ()->Tib; while (true)
wrapper_arg.stackaddr = (PVOID) ((PBYTE) tib->StackBase {
- wrapper_arg.stacksize); new_start->handler = old_start->handler;
if (!VirtualAlloc (wrapper_arg.stackaddr, wrapper_arg.guardsize, if (old_start->prev == (_exception_list *) -1)
MEM_COMMIT, PAGE_NOACCESS)) {
system_printf ("VirtualAlloc, %E"); new_start->prev = (_exception_list *) -1;
break;
} }
new_start->prev = new_start + 1;
new_start = new_start->prev;
old_start = old_start->prev;
}
}
__asm__ ("\n\ __asm__ ("\n\
movl %[WRAPPER_ARG], %%ebx # Load &wrapper_arg into ebx \n\ movl %[WRAPPER_ARG], %%ebx # Load &wrapper_arg into ebx \n\
movl (%%ebx), %%eax # Load thread func into eax \n\ movl (%%ebx), %%eax # Load thread func into eax \n\
movl 4(%%ebx), %%ecx # Load thread arg into ecx \n\ movl 4(%%ebx), %%ecx # Load thread arg into ecx \n\
movl 8(%%ebx), %%edx # Load stackaddr into edx \n\
movl 12(%%ebx), %%ebx # Load stackbase into ebx \n\
subl %[CYGTLS], %%ebx # Subtract CYGTLS_PADSIZE \n\
subl $4, %%ebx # Subtract another 4 bytes \n\
movl %%ebx, %%esp # Set esp \n\
xorl %%ebp, %%ebp # Set ebp to 0 \n\
# Now we moved to the new stack. Save thread func address\n\
# and thread arg on new stack \n\
pushl %%ecx # Push thread arg onto stack \n\ pushl %%ecx # Push thread arg onto stack \n\
pushl %%eax # Push thread func onto stack \n\ pushl %%eax # Push thread func onto stack \n\
jmp *%%eax # Jump to thread func \n" # Now it's safe to release the OS stack. \n\
: : [WRAPPER_ARG] "r" (&wrapper_arg)); pushl $0x8000 # dwFreeType: MEM_RELEASE \n\
/* Never reached. */ pushl $0x0 # dwSize: 0 \n\
return ERROR_INVALID_FUNCTION; pushl %%edx # lpAddress: stackaddr \n\
call _VirtualFree@12 # Shoot \n\
# All set. We can pop the thread function address from \n\
# the stack and call it. The thread arg is still on the \n\
# stack in the expected spot. \n\
popl %%eax # Pop thread_func address \n\
call *%%eax # Call thread func \n"
: : [WRAPPER_ARG] "r" (&wrapper_arg),
[CYGTLS] "i" (CYGTLS_PADSIZE));
/* Never return from here. */
ExitThread (0);
} }
/* FIXME: This should be settable via setrlimit (RLIMIT_STACK). */ /* FIXME: This should be settable via setrlimit (RLIMIT_STACK). */
@ -468,9 +507,11 @@ CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
PVOID stackaddr, ULONG stacksize, ULONG guardsize, PVOID stackaddr, ULONG stacksize, ULONG guardsize,
DWORD creation_flags, LPDWORD thread_id) DWORD creation_flags, LPDWORD thread_id)
{ {
PVOID real_stackaddr = NULL;
ULONG real_stacksize = 0; ULONG real_stacksize = 0;
ULONG real_guardsize = 0; ULONG real_guardsize = 0;
thread_wrapper_arg *wrapper_arg; thread_wrapper_arg *wrapper_arg;
HANDLE thread = NULL;
wrapper_arg = (thread_wrapper_arg *) ccalloc (HEAP_STR, 1, wrapper_arg = (thread_wrapper_arg *) ccalloc (HEAP_STR, 1,
sizeof *wrapper_arg); sizeof *wrapper_arg);
@ -488,9 +529,8 @@ CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
real_stacksize = PTHREAD_STACK_MIN; real_stacksize = PTHREAD_STACK_MIN;
if (stackaddr) if (stackaddr)
{ {
wrapper_arg->stackaddr = stackaddr; wrapper_arg->stackaddr = (char *) stackaddr;
wrapper_arg->stacksize = real_stacksize; wrapper_arg->stackbase = (char *) stackaddr + real_stacksize;
real_stacksize = PTHREAD_STACK_MIN;
} }
else else
{ {
@ -498,25 +538,68 @@ CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
real_stacksize = roundup2 (real_stacksize, wincap.page_size ()); real_stacksize = roundup2 (real_stacksize, wincap.page_size ());
/* If no guardsize has been specified by the application, use the /* If no guardsize has been specified by the application, use the
system pagesize as default. */ system pagesize as default. */
real_guardsize = (guardsize != 0xffffffff) real_guardsize = (guardsize != (ULONG) -1)
? guardsize : wincap.page_size (); ? guardsize : wincap.page_size ();
if (real_guardsize) if (real_guardsize)
real_guardsize = roundup2 (real_guardsize, wincap.page_size ()); real_guardsize = roundup2 (real_guardsize, wincap.page_size ());
/* If the default stacksize is used and guardsize has not been specified, /* If the default stacksize is used and guardsize has not been specified,
don't add a guard page to the size. */ don't add a guard page to the size. Same if stacksize is only
if (stacksize && guardsize != 0xffffffff) PTHREAD_STACK_MIN. */
if (stacksize && guardsize != (ULONG) -1
&& real_stacksize > PTHREAD_STACK_MIN)
real_stacksize += real_guardsize; real_stacksize += real_guardsize;
/* Now roundup the result to the next allocation boundary. */ /* Now roundup the result to the next allocation boundary. */
real_stacksize = roundup2 (real_stacksize, real_stacksize = roundup2 (real_stacksize,
wincap.allocation_granularity ()); wincap.allocation_granularity ());
/* Reserve stack.
wrapper_arg->stacksize = real_stacksize; FIXME? If the TOP_DOWN method tends to collide too much with
wrapper_arg->guardsize = real_guardsize; other stuff, we should provide our own mechanism to find a
suitable place for the stack. Top down from the start of
the Cygwin DLL comes to mind. */
real_stackaddr = VirtualAlloc (NULL, real_stacksize,
MEM_RESERVE | MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE);
if (!real_stackaddr)
return NULL;
/* Set up committed region. In contrast to the OS we commit 64K and
set up just a single guard page at the end. */
char *commitaddr = (char *) real_stackaddr
+ real_stacksize
- wincap.allocation_granularity ();
if (!VirtualAlloc (commitaddr, wincap.page_size (), MEM_COMMIT,
PAGE_EXECUTE_READWRITE | PAGE_GUARD))
goto err;
commitaddr += wincap.page_size ();
if (!VirtualAlloc (commitaddr, wincap.allocation_granularity ()
- wincap.page_size (), MEM_COMMIT,
PAGE_EXECUTE_READWRITE))
goto err;
if (real_guardsize)
VirtualAlloc (real_stackaddr, real_guardsize, MEM_COMMIT,
PAGE_NOACCESS);
wrapper_arg->stackaddr = (char *) real_stackaddr;
wrapper_arg->stackbase = (char *) real_stackaddr + real_stacksize;
wrapper_arg->commitaddr = commitaddr;
} }
/* Use the STACK_SIZE_PARAM_IS_A_RESERVATION parameter to make sure the /* Use the STACK_SIZE_PARAM_IS_A_RESERVATION parameter so only the
stack size is exactly the size we want. */ minimum size for a thread stack is reserved by the OS. This doesn't
return CreateThread (&sec_none_nih, real_stacksize, thread_wrapper, work on Windows 2000, but we deallocate the OS stack in thread_wrapper
wrapper_arg, anyway, so this should be a problem only in a tight memory condition.
Note that we reserve a 256K stack, not 64K, otherwise the thread creation
might crash the process due to a stack overflow. */
thread = CreateThread (&sec_none_nih, 4 * PTHREAD_STACK_MIN,
thread_wrapper, wrapper_arg,
creation_flags | STACK_SIZE_PARAM_IS_A_RESERVATION, creation_flags | STACK_SIZE_PARAM_IS_A_RESERVATION,
thread_id); thread_id);
err:
if (!thread && real_stackaddr)
{
/* Don't report the wrong error even though VirtualFree is very unlikely
to fail. */
DWORD err = GetLastError ();
VirtualFree (real_stackaddr, 0, MEM_RELEASE);
SetLastError (err);
}
return thread;
} }

View File

@ -622,7 +622,7 @@ typedef struct _PEB
ULONG SessionId; ULONG SessionId;
} PEB, *PPEB; } PEB, *PPEB;
/* Simplified definition, just to get the TIB and the PEB pointer. */ /* Simplified definition, just to get stuff we're interested in. */
typedef struct _TEB typedef struct _TEB
{ {
NT_TIB Tib; NT_TIB Tib;
@ -631,6 +631,32 @@ typedef struct _TEB
PVOID ActiveRpcHandle; PVOID ActiveRpcHandle;
PVOID ThreadLocalStoragePointer; PVOID ThreadLocalStoragePointer;
PPEB Peb; PPEB Peb;
ULONG LastErrorValue;
ULONG CountOfOwnedCriticalSections;
PVOID _reserved1[2];
ULONG _reserved2[31];
PVOID WOW32Reserved;
ULONG CurrentLocale;
ULONG FpSoftwareStatusRegister;
PVOID SystemReserved1[54];
LONG ExceptionCode;
PVOID ActivationContextStackPointer;
UCHAR SpareBytes1[36];
ULONG TxFsContext;
ULONG GdiTebBatch[312];
CLIENT_ID RealClientId;
PVOID GdiCachedProcessHandle;
ULONG GdiClientPID;
ULONG GdiClientTID;
PVOID GdiThreadLocalInfo;
ULONG Win32ClientInfo[62];
PVOID glDispatchTable[233];
ULONG glReserved1[29];
PVOID glReserved2[6];
ULONG LastStatusValue;
UNICODE_STRING StaticUnicodeString;
WCHAR StaticUnicodeBuffer[261];
PVOID DeallocationStack;
/* A lot more follows... */ /* A lot more follows... */
} TEB, *PTEB; } TEB, *PTEB;

View File

@ -1089,7 +1089,7 @@ pthread::resume ()
pthread_attr::pthread_attr ():verifyable_object (PTHREAD_ATTR_MAGIC), pthread_attr::pthread_attr ():verifyable_object (PTHREAD_ATTR_MAGIC),
joinable (PTHREAD_CREATE_JOINABLE), contentionscope (PTHREAD_SCOPE_PROCESS), joinable (PTHREAD_CREATE_JOINABLE), contentionscope (PTHREAD_SCOPE_PROCESS),
inheritsched (PTHREAD_INHERIT_SCHED), stackaddr (NULL), stacksize (0), inheritsched (PTHREAD_INHERIT_SCHED), stackaddr (NULL), stacksize (0),
guardsize (0xffffffff) guardsize ((size_t) -1)
{ {
schedparam.sched_priority = 0; schedparam.sched_priority = 0;
} }

View File

@ -51,6 +51,7 @@ wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_fast_cwd:false, has_fast_cwd:false,
has_restricted_raw_disk_access:false, has_restricted_raw_disk_access:false,
use_dont_resolve_hack:false, use_dont_resolve_hack:false,
has_stack_size_param_is_a_reservation:false,
}; };
wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = { wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = {
@ -81,6 +82,7 @@ wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) =
has_fast_cwd:false, has_fast_cwd:false,
has_restricted_raw_disk_access:false, has_restricted_raw_disk_access:false,
use_dont_resolve_hack:false, use_dont_resolve_hack:false,
has_stack_size_param_is_a_reservation:false,
}; };
wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = {
@ -111,6 +113,7 @@ wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = {
has_fast_cwd:false, has_fast_cwd:false,
has_restricted_raw_disk_access:false, has_restricted_raw_disk_access:false,
use_dont_resolve_hack:true, use_dont_resolve_hack:true,
has_stack_size_param_is_a_reservation:true,
}; };
wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = {
@ -141,6 +144,7 @@ wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_fast_cwd:false, has_fast_cwd:false,
has_restricted_raw_disk_access:false, has_restricted_raw_disk_access:false,
use_dont_resolve_hack:true, use_dont_resolve_hack:true,
has_stack_size_param_is_a_reservation:true,
}; };
wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
@ -171,6 +175,7 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_fast_cwd:false, has_fast_cwd:false,
has_restricted_raw_disk_access:false, has_restricted_raw_disk_access:false,
use_dont_resolve_hack:true, use_dont_resolve_hack:true,
has_stack_size_param_is_a_reservation:true,
}; };
wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
@ -201,6 +206,7 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_fast_cwd:false, has_fast_cwd:false,
has_restricted_raw_disk_access:false, has_restricted_raw_disk_access:false,
use_dont_resolve_hack:true, use_dont_resolve_hack:true,
has_stack_size_param_is_a_reservation:true,
}; };
wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
@ -231,6 +237,7 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
has_fast_cwd:true, has_fast_cwd:true,
has_restricted_raw_disk_access:true, has_restricted_raw_disk_access:true,
use_dont_resolve_hack:false, use_dont_resolve_hack:false,
has_stack_size_param_is_a_reservation:true,
}; };
wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = { wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
@ -261,6 +268,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_fast_cwd:true, has_fast_cwd:true,
has_restricted_raw_disk_access:true, has_restricted_raw_disk_access:true,
use_dont_resolve_hack:false, use_dont_resolve_hack:false,
has_stack_size_param_is_a_reservation:true,
}; };
wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); wincapc wincap __attribute__((section (".cygwin_dll_common"), shared));

View File

@ -41,6 +41,7 @@ struct wincaps
unsigned has_fast_cwd : 1; unsigned has_fast_cwd : 1;
unsigned has_restricted_raw_disk_access : 1; unsigned has_restricted_raw_disk_access : 1;
unsigned use_dont_resolve_hack : 1; unsigned use_dont_resolve_hack : 1;
unsigned has_stack_size_param_is_a_reservation : 1;
}; };
class wincapc class wincapc
@ -90,6 +91,7 @@ public:
bool IMPLEMENT (has_fast_cwd) bool IMPLEMENT (has_fast_cwd)
bool IMPLEMENT (has_restricted_raw_disk_access) bool IMPLEMENT (has_restricted_raw_disk_access)
bool IMPLEMENT (use_dont_resolve_hack) bool IMPLEMENT (use_dont_resolve_hack)
bool IMPLEMENT (has_stack_size_param_is_a_reservation)
#undef IMPLEMENT #undef IMPLEMENT
}; };