]> sourceware.org Git - newlib-cygwin.git/commitdiff
* child_info.h (CURR_CHILD_INFO_MAGIC): Update.
authorCorinna Vinschen <corinna@vinschen.de>
Fri, 20 May 2011 07:23:11 +0000 (07:23 +0000)
committerCorinna Vinschen <corinna@vinschen.de>
Fri, 20 May 2011 07:23:11 +0000 (07:23 +0000)
(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.

winsup/cygwin/ChangeLog
winsup/cygwin/child_info.h
winsup/cygwin/dcrt0.cc
winsup/cygwin/fork.cc
winsup/cygwin/init.cc
winsup/cygwin/miscfuncs.cc
winsup/cygwin/ntdll.h
winsup/cygwin/thread.cc
winsup/cygwin/wincap.cc
winsup/cygwin/wincap.h

index ca20f97dc5bdb4d645f4471350f3b3151fdb50cb..272595d44a1613dbe0dea4d221c1945edd5191bc 100644 (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>
 
        * thread.cc: Mark psiginfo and psignal as available in list of
index 44767edc9fc9022c37a0b6f78bd4e28f1d4c66df..2bf89c1831df00ba2da3e263d8643669e2649b8c 100644 (file)
@@ -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)));;
index a6eb2696d22ccdb5360aa287c72d8798e079bd13..6248d0e3f8ac07d642c9d944f0cfe8b3b53964b7 100644 (file)
@@ -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;
index 8701cdfa3633f1732d54b2797466d871a493da29..4a800b55159e2c9006537ff6ccb63cf3d4249822 100644 (file)
@@ -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;
index 5404ed15a0d73725c3e76a61cc7d4150e0961120..9f66c3ba28a1e7864572293c0eed5985159068ae 100644 (file)
@@ -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;
     }
 
index e6bb6c31ff443845e796fa3717d8e8502e5ba7a4..e73ac2290ba762ac39d4644831f2f572e5cfbf15 100644 (file)
@@ -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;
 }
index 77aeeece09a39ec357c4f02bd1e2334151a1a7ae..a085a71158e971d5ebba1899e446fcd24101f635 100644 (file)
@@ -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;
 
index e4bfb74e37c5ba9b4c6193a0b4bb34cf0a3c53bb..f0f53510103069a1b74df0f9af6845e56d1b0381 100644 (file)
@@ -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;
 }
index b959d1e572606a6b48ad9869119701d11b4f7ec0..2a848b4b6a28b9fbb020382217fa99008ce87a08 100644 (file)
@@ -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));
index 629a062cd66106a3f63d08c02066f18704535952..7738d1f8be587e1afb45ddde27c1e668d6c9b779 100644 (file)
@@ -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
 };
This page took 0.054514 seconds and 5 git commands to generate.