 = 16	\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] "o" (wrapper_arg),
	       [CYGTLS] "i" (CYGTLS_PADSIZE));
#endif
  /* pthread::thread_init_wrapper calls pthread::exit, which
     in turn calls ExitThread, so we should never arrive here. */
  api_fatal ("Dumb thinko in pthread handling.  Whip the developer.");
}

#ifdef __x86_64__
/* The memory region used for thread stacks */
#define THREAD_STORAGE_LOW	0x080000000L
#define THREAD_STORAGE_HIGH	0x100000000L
/* We provide the stacks always in 1 Megabyte slots */
#define THREAD_STACK_SLOT	0x100000L	/* 1 Meg */
/* Maximum stack size returned from the pool. */
#define THREAD_STACK_MAX	0x20000000L	/* 512 Megs */

class thread_allocator
{
  UINT_PTR current;
public:
  thread_allocator () : current (THREAD_STORAGE_HIGH) {}
  PVOID alloc (SIZE_T size)
  {
    SIZE_T real_size = roundup2 (size, THREAD_STACK_SLOT);
    BOOL overflow = FALSE;
    PVOID real_stackaddr = NULL;

    /* If an application requests a monster stack, we fulfill this request
       from outside of our pool, top down. */
    if (real_size > THREAD_STACK_MAX)
      return VirtualAlloc (NULL, real_size, MEM_RESERVE | MEM_TOP_DOWN,
			   PAGE_READWRITE);
    /* Simple round-robin.  Keep looping until VirtualAlloc succeeded, or
       until we overflowed and hit the current address. */
    for (UINT_PTR addr = current - real_size;
	!real_stackaddr && (!overflow || addr >= current);
	 addr -= THREAD_STACK_SLOT)
      {
	if (addr < THREAD_STORAGE_LOW)
	  {
	    addr = THREAD_STORAGE_HIGH - real_size;
	    overflow = TRUE;
	  }
	real_stackaddr = VirtualAlloc ((PVOID) addr, real_size,
				       MEM_RESERVE, PAGE_READWRITE);
	if (!real_stackaddr)
	  {
	    /* So we couldn't grab this space.  Let's check the state.
	       If this area is free, simply try the next lower 1 Meg slot.
	       Otherwise, shift the next try down to the AllocationBase
	       of the current address, minus the requested slot size.
	       Add THREAD_STACK_SLOT since that's subtracted in the next
	       run of the loop anyway. */
	    MEMORY_BASIC_INFORMATION mbi;
	    VirtualQuery ((PVOID) addr, &mbi, sizeof mbi);
	    if (mbi.State!= MEM_FREE)
	      addr = (UINT_PTR) mbi.AllocationBase - real_size
						    + THREAD_STACK_SLOT;
	  }
      }
    /* If we got an address, remember it for the next allocation attempt. */
    if (real_stackaddr)
      current = (UINT_PTR) real_stackaddr;
    return real_stackaddr;
  }
};

thread_allocator thr_alloc NO_COPY;
#endif

HANDLE WINAPI
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;
  pthread_wrapper_arg *wrapper_arg;
  HANDLE thread = NULL;

  wrapper_arg = (pthread_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;

  if (stackaddr)
    {
      /* If the application provided the stack, just use it.  There won't
	 be any stack overflow handling! */
      wrapper_arg->stackaddr = (PBYTE) stackaddr;
      wrapper_arg->stackbase = (PBYTE) stackaddr + stacksize;
    }
  else
    {
      PBYTE real_stacklimit;

      /* If not, we have to create the stack here. */
      real_stacksize = roundup2 (stacksize, wincap.page_size ());
      real_guardsize = roundup2 (guardsize, wincap.page_size ());
      /* Add the guardsize to the stacksize */
      real_stacksize += real_guardsize;
      /* Take dead zone page into account, which always stays uncommited. */
      real_stacksize += wincap.page_size ();
      /* Now roundup the result to the next allocation boundary. */
      real_stacksize = roundup2 (real_stacksize,
				 wincap.allocation_granularity ());
      /* Reserve stack. */
#ifdef __x86_64__
      real_stackaddr = thr_alloc.alloc (real_stacksize);
#else
      /* 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_READWRITE);
#endif
      if (!real_stackaddr)
	return NULL;
      /* Set up committed region.  We have two cases: */
      if (!wincap.has_set_thread_stack_guarantee ()
	  && real_guardsize!= wincap.def_guard_page_size ())
	{
	  /* If guardsize is set to something other than the default guard page
	     size, and if we're running on Windows XP 32 bit, we commit the
	     entire stack, and, if guardsize is > 0, set up a guard page. */
	  real_stacklimit = (PBYTE) real_stackaddr + wincap.page_size ();
	  if (real_guardsize
	      &&!VirtualAlloc (real_stacklimit, real_guardsize, MEM_COMMIT,
				PAGE_READWRITE | PAGE_GUARD))
	    goto err;
	  real_stacklimit += real_guardsize;
	  if (!VirtualAlloc (real_stacklimit, real_stacksize - real_guardsize
					      - wincap.page_size (),
			     MEM_COMMIT, PAGE_READWRITE))
	    goto err;
	}
      else
	{
	  /* Otherwise we set up the stack like the OS does, with a reserved
	     region, the guard pages, and a commited region.  We commit the
	     stack commit size from the executable header, but at least
	     PTHREAD_STACK_MIN (64K). */
	  static ULONG exe_commitsize;

	  if (!exe_commitsize)
	    {
	      PIMAGE_DOS_HEADER dosheader;
	      PIMAGE_NT_HEADERS ntheader;

	      dosheader = (PIMAGE_DOS_HEADER