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
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2011-05-20 11:23:11 +0400
committerCorinna Vinschen <corinna@vinschen.de>2011-05-20 11:23:11 +0400
commit89d3c72d510b4e254b38b15865d921d45b26d80a (patch)
tree8be3d82b93084d305beae6c87019bb8d192e4b44 /winsup
parent660302eb67bc951f9a4e543f4b5d02450eea10e2 (diff)
* 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.
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/ChangeLog32
-rw-r--r--winsup/cygwin/child_info.h6
-rw-r--r--winsup/cygwin/dcrt0.cc72
-rw-r--r--winsup/cygwin/fork.cc34
-rw-r--r--winsup/cygwin/init.cc21
-rw-r--r--winsup/cygwin/miscfuncs.cc217
-rw-r--r--winsup/cygwin/ntdll.h28
-rw-r--r--winsup/cygwin/thread.cc2
-rw-r--r--winsup/cygwin/wincap.cc8
-rw-r--r--winsup/cygwin/wincap.h2
10 files changed, 295 insertions, 127 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index ca20f97dc..272595d44 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -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>
* thread.cc: Mark psiginfo and psignal as available in list of
diff --git a/winsup/cygwin/child_info.h b/winsup/cygwin/child_info.h
index 44767edc9..2bf89c183 100644
--- a/winsup/cygwin/child_info.h
+++ b/winsup/cygwin/child_info.h
@@ -37,7 +37,7 @@ enum child_status
#define EXEC_MAGIC_SIZE sizeof(child_info)
/* 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
below class. The layout is checksummed to determine compatibility between
@@ -80,10 +80,12 @@ class child_info_fork: public child_info
{
public:
HANDLE forker_finished;// for synchronization with child
- DWORD stacksize; // size of parent stack
jmp_buf jmp; // where child will jump to
+ void *stackaddr; // address of parent stack
void *stacktop; // location of top 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];
child_info_fork ();
void handle_fork () __attribute__ ((regparm (1)));;
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index a6eb2696d..6248d0e3f 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -392,14 +392,11 @@ child_info NO_COPY *child_proc_info = NULL;
void
child_info_fork::alloc_stack_hard_way (volatile char *b)
{
- void *new_stack_pointer;
- MEMORY_BASIC_INFORMATION m;
- void *newbase;
- int newlen;
- bool guard;
+ void *stack_ptr;
+ DWORD stacksize;
/* 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
to be used as is. */
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))
return;
- if (!VirtualQuery ((LPCVOID) &b, &m, sizeof m))
- api_fatal ("fork: couldn't get stack info, %E");
-
- 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))
+ /* First, try to reserve the entire stack. */
+ stacksize = (char *) stackbottom - (char *) stackaddr;
+ if (!VirtualAlloc (stackaddr, stacksize, MEM_RESERVE, PAGE_NOACCESS))
api_fatal ("fork: can't reserve memory for stack %p - %p, %E",
- stacktop, stackbottom);
- new_stack_pointer = (void *) ((LPBYTE) stackbottom - (stacksize += 8192));
- if (!VirtualAlloc (new_stack_pointer, stacksize, MEM_COMMIT,
- PAGE_EXECUTE_READWRITE))
+ stackaddr, stackbottom);
+ stacksize = (char *) stackbottom - (char *) stacktop;
+ stack_ptr = VirtualAlloc (stacktop, stacksize, MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE);
+ if (!stack_ptr)
api_fatal ("fork: can't commit memory for stack %p(%d), %E",
- new_stack_pointer, stacksize);
- if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m))
- api_fatal ("fork: couldn't get new stack info, %E");
-
- if (guard)
+ stacktop, stacksize);
+ if (guardsize != (size_t) -1)
{
- m.BaseAddress = (LPBYTE) m.BaseAddress - 1;
- if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT,
- CYGWIN_GUARD))
- api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
- m.BaseAddress);
+ /* Allocate PAGE_GUARD page if it still fits. */
+ if (stack_ptr > stackaddr)
+ {
+ stack_ptr = (void *) ((LPBYTE) stack_ptr
+ - wincap.page_size ());
+ if (!VirtualAlloc (stack_ptr, wincap.page_size (), MEM_COMMIT,
+ CYGWIN_GUARD))
+ api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
+ 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';
}
@@ -473,7 +457,7 @@ child_info_fork::alloc_stack ()
char *st = (char *) stacktop - 4096;
while (_tlstop >= st)
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
this step. */
- if (fork_info->stacksize)
+ if (fork_info->stackaddr)
{
_tlsbase = (char *) fork_info->stackbottom;
_tlstop = (char *) fork_info->stacktop;
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 8701cdfa3..4a800b551 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -25,6 +25,7 @@ details. */
#include "tls_pbuf.h"
#include "dll_init.h"
#include "cygmalloc.h"
+#include "ntdll.h"
#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
fork() was invoked from other than the main thread. Make sure that
the threadinfo information is properly set up. */
- if (fork_info->stacksize)
+ if (fork_info->stackaddr)
{
_main_tls = &_my_tls;
_main_tls->init_thread (NULL, NULL);
@@ -327,10 +328,33 @@ frok::parent (volatile char * volatile stack_here)
ch.forker_finished = forker_finished;
ch.stackbottom = _tlsbase;
- ch.stacktop = (void *) stack_here;
- ch.stacksize = (char *) ch.stackbottom - (char *) stack_here;
- debug_printf ("stack - bottom %p, top %p, size %d",
- ch.stackbottom, ch.stacktop, ch.stacksize);
+ ch.stacktop = (void *) _tlstop;
+ ch.stackaddr = 0;
+ ch.guardsize = 0;
+ 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;
STARTUPINFOW si;
diff --git a/winsup/cygwin/init.cc b/winsup/cygwin/init.cc
index 5404ed15a..9f66c3ba2 100644
--- a/winsup/cygwin/init.cc
+++ b/winsup/cygwin/init.cc
@@ -115,7 +115,7 @@ extern void __stdcall dll_crt0_0 ();
extern "C" BOOL WINAPI
dll_entry (HANDLE h, DWORD reason, void *static_load)
{
- PNT_TIB tib;
+ PTEB teb;
switch (reason)
{
@@ -131,10 +131,10 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
the auto load address of DLLs?
Check if we're running in WOW64 on a 64 bit machine *and* are
spawned by a genuine 64 bit process. If so, respawn. */
- tib = &NtCurrentTeb ()->Tib;
+ teb = NtCurrentTeb ();
if (wincap.is_wow64 ()
- && tib->StackLimit >= (PBOOL) 0x400000
- && tib->StackBase <= (PBOOL) 0x10000000)
+ && teb->Tib.StackLimit >= (PBOOL) 0x400000
+ && teb->Tib.StackBase <= (PBOOL) 0x10000000)
respawn_wow64_process ();
dll_crt0_0 ();
@@ -150,12 +150,19 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
munge_threadfunc ();
break;
case DLL_THREAD_DETACH:
- tib = &NtCurrentTeb ()->Tib;
+ teb = NtCurrentTeb ();
if (dll_finished_loading
- && (PVOID) &_my_tls >= tib->StackLimit
- && (PVOID) &_my_tls < tib->StackBase
+ && (PVOID) &teb >= teb->Tib.StackLimit
+ && (PVOID) &teb < teb->Tib.StackBase
&& _my_tls.isinitialized ())
_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;
}
diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc
index e6bb6c31f..e73ac2290 100644
--- a/winsup/cygwin/miscfuncs.cc
+++ b/winsup/cygwin/miscfuncs.cc
@@ -26,6 +26,8 @@ details. */
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
+#include "pinfo.h"
+#include "exception.h"
long tls_ix = -1;
@@ -392,72 +394,109 @@ struct thread_wrapper_arg
{
LPTHREAD_START_ROUTINE func;
PVOID arg;
- PVOID stackaddr;
- ULONG stacksize;
- ULONG guardsize;
+ char *stackaddr;
+ char *stackbase;
+ char *commitaddr;
};
DWORD WINAPI
thread_wrapper (VOID *arg)
{
+ /* Just plain paranoia. */
if (!arg)
return ERROR_INVALID_PARAMETER;
+ /* Fetch thread wrapper info and free from cygheap. */
thread_wrapper_arg wrapper_arg = *(thread_wrapper_arg *) arg;
cfree (arg);
- if (wrapper_arg.stackaddr)
+ /* Remove _cygtls from this stack since it won't be used anymore. */
+ _cygtls *tls;
+ tls = &_my_tls;
+ _my_tls.remove (0);
+
+ /* Set stack values in TEB */
+ 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)
{
- /* 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, move
- _my_tls to the stackbase, and change the stack pointer accordingly. */
- _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));
-
- }
- 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");
+ _exception_list *new_start = (_exception_list *) wrapper_arg.stackbase
+ - count;
+ teb->Tib.ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)
+ new_start;
+ while (true)
+ {
+ new_start->handler = old_start->handler;
+ if (old_start->prev == (_exception_list *) -1)
+ {
+ 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\
- 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\
- 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));
- /* Never reached. */
- return ERROR_INVALID_FUNCTION;
+ 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 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 %%eax # Push thread func onto stack \n\
+ # Now it's safe to release the OS stack. \n\
+ pushl $0x8000 # dwFreeType: MEM_RELEASE \n\
+ pushl $0x0 # dwSize: 0 \n\
+ 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). */
@@ -468,9 +507,11 @@ CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
PVOID stackaddr, ULONG stacksize, ULONG guardsize,
DWORD creation_flags, LPDWORD thread_id)
{
+ PVOID real_stackaddr = NULL;
ULONG real_stacksize = 0;
ULONG real_guardsize = 0;
thread_wrapper_arg *wrapper_arg;
+ HANDLE thread = NULL;
wrapper_arg = (thread_wrapper_arg *) ccalloc (HEAP_STR, 1,
sizeof *wrapper_arg);
@@ -488,9 +529,8 @@ CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
real_stacksize = PTHREAD_STACK_MIN;
if (stackaddr)
{
- wrapper_arg->stackaddr = stackaddr;
- wrapper_arg->stacksize = real_stacksize;
- real_stacksize = PTHREAD_STACK_MIN;
+ wrapper_arg->stackaddr = (char *) stackaddr;
+ wrapper_arg->stackbase = (char *) stackaddr + real_stacksize;
}
else
{
@@ -498,25 +538,68 @@ CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
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)
+ real_guardsize = (guardsize != (ULONG) -1)
? 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)
+ don't add a guard page to the size. Same if stacksize is only
+ PTHREAD_STACK_MIN. */
+ if (stacksize && guardsize != (ULONG) -1
+ && real_stacksize > PTHREAD_STACK_MIN)
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;
+ /* Reserve stack.
+ FIXME? If the TOP_DOWN method tends to collide too much with
+ 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 so only the
+ minimum size for a thread stack is reserved by the OS. This doesn't
+ work on Windows 2000, but we deallocate the OS stack in thread_wrapper
+ 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,
+ 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);
}
- /* 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);
+ return thread;
}
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index 77aeeece0..a085a7115 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -622,7 +622,7 @@ typedef struct _PEB
ULONG SessionId;
} 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
{
NT_TIB Tib;
@@ -631,6 +631,32 @@ typedef struct _TEB
PVOID ActiveRpcHandle;
PVOID ThreadLocalStoragePointer;
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... */
} TEB, *PTEB;
diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc
index e4bfb74e3..f0f535101 100644
--- a/winsup/cygwin/thread.cc
+++ b/winsup/cygwin/thread.cc
@@ -1089,7 +1089,7 @@ pthread::resume ()
pthread_attr::pthread_attr ():verifyable_object (PTHREAD_ATTR_MAGIC),
joinable (PTHREAD_CREATE_JOINABLE), contentionscope (PTHREAD_SCOPE_PROCESS),
inheritsched (PTHREAD_INHERIT_SCHED), stackaddr (NULL), stacksize (0),
-guardsize (0xffffffff)
+guardsize ((size_t) -1)
{
schedparam.sched_priority = 0;
}
diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc
index b959d1e57..2a848b4b6 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -51,6 +51,7 @@ wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_fast_cwd:false,
has_restricted_raw_disk_access:false,
use_dont_resolve_hack:false,
+ has_stack_size_param_is_a_reservation:false,
};
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_restricted_raw_disk_access:false,
use_dont_resolve_hack:false,
+ has_stack_size_param_is_a_reservation:false,
};
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_restricted_raw_disk_access:false,
use_dont_resolve_hack:true,
+ has_stack_size_param_is_a_reservation:true,
};
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_restricted_raw_disk_access:false,
use_dont_resolve_hack:true,
+ has_stack_size_param_is_a_reservation:true,
};
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_restricted_raw_disk_access:false,
use_dont_resolve_hack:true,
+ has_stack_size_param_is_a_reservation:true,
};
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_restricted_raw_disk_access:false,
use_dont_resolve_hack:true,
+ has_stack_size_param_is_a_reservation:true,
};
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_restricted_raw_disk_access:true,
use_dont_resolve_hack:false,
+ has_stack_size_param_is_a_reservation:true,
};
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_restricted_raw_disk_access:true,
use_dont_resolve_hack:false,
+ has_stack_size_param_is_a_reservation:true,
};
wincapc wincap __attribute__((section (".cygwin_dll_common"), shared));
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
index 629a062cd..7738d1f8b 100644
--- a/winsup/cygwin/wincap.h
+++ b/winsup/cygwin/wincap.h
@@ -41,6 +41,7 @@ struct wincaps
unsigned has_fast_cwd : 1;
unsigned has_restricted_raw_disk_access : 1;
unsigned use_dont_resolve_hack : 1;
+ unsigned has_stack_size_param_is_a_reservation : 1;
};
class wincapc
@@ -90,6 +91,7 @@ public:
bool IMPLEMENT (has_fast_cwd)
bool IMPLEMENT (has_restricted_raw_disk_access)
bool IMPLEMENT (use_dont_resolve_hack)
+ bool IMPLEMENT (has_stack_size_param_is_a_reservation)
#undef IMPLEMENT
};