* Merge in cygwin-64bit-branch.
This commit is contained in:
@ -32,7 +32,7 @@ details. */
|
||||
|
||||
long tls_ix = -1;
|
||||
|
||||
const char case_folded_lower[] NO_COPY = {
|
||||
const unsigned char case_folded_lower[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, '!', '"', '#', '$', '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
|
||||
@ -51,7 +51,7 @@ const char case_folded_lower[] NO_COPY = {
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
|
||||
};
|
||||
|
||||
const char case_folded_upper[] NO_COPY = {
|
||||
const unsigned char case_folded_upper[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, '!', '"', '#', '$', '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
|
||||
@ -70,7 +70,7 @@ const char case_folded_upper[] NO_COPY = {
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
|
||||
};
|
||||
|
||||
const char isalpha_array[] NO_COPY = {
|
||||
const char isalpha_array[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@ -282,7 +282,7 @@ winprio_to_nice (DWORD prio)
|
||||
DWORD
|
||||
nice_to_winprio (int &nice)
|
||||
{
|
||||
static const DWORD priority[] NO_COPY =
|
||||
static const DWORD priority[] =
|
||||
{
|
||||
REALTIME_PRIORITY_CLASS, /* 0 */
|
||||
HIGH_PRIORITY_CLASS, /* 1 */
|
||||
@ -443,7 +443,11 @@ __import_address (void *imp)
|
||||
if (efault.faulted ())
|
||||
return NULL;
|
||||
const char *ptr = (const char *) imp;
|
||||
#ifdef __x86_64__
|
||||
const uintptr_t *jmpto = (uintptr_t *) (ptr + 6 + *(int32_t *)(ptr + 2));
|
||||
#else
|
||||
const uintptr_t *jmpto = (uintptr_t *) *((uintptr_t *) (ptr + 2));
|
||||
#endif
|
||||
return (void *) *jmpto;
|
||||
}
|
||||
|
||||
@ -463,7 +467,7 @@ struct thread_wrapper_arg
|
||||
};
|
||||
|
||||
static DWORD WINAPI
|
||||
thread_wrapper (VOID *arg)
|
||||
thread_wrapper (PVOID arg)
|
||||
{
|
||||
/* Just plain paranoia. */
|
||||
if (!arg)
|
||||
@ -496,7 +500,7 @@ thread_wrapper (VOID *arg)
|
||||
/* Initialize new _cygtls. */
|
||||
_my_tls.init_thread (wrapper_arg.stackbase - CYGTLS_PADSIZE,
|
||||
(DWORD (*)(void*, void*)) wrapper_arg.func);
|
||||
|
||||
#ifndef __x86_64__
|
||||
/* 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.
|
||||
@ -529,9 +533,34 @@ thread_wrapper (VOID *arg)
|
||||
old_start = old_start->prev;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
__asm__ ("\n\
|
||||
movl %[WRAPPER_ARG], %%ebx # Load &wrapper_arg into ebx \n\
|
||||
movq %[WRAPPER_ARG], %%rbx # Load &wrapper_arg into rbx \n\
|
||||
movq (%%rbx), %%r12 # Load thread func into r12 \n\
|
||||
movq 8(%%rbx), %%r13 # Load thread arg into r13 \n\
|
||||
movq 16(%%rbx), %%rcx # Load stackaddr into rcx \n\
|
||||
movq 24(%%rbx), %%rsp # Load stackbase into rsp \n\
|
||||
subq %[CYGTLS], %%rsp # Subtract CYGTLS_PADSIZE \n\
|
||||
# (here we are 16 bytes aligned)\n\
|
||||
subq $32, %%rsp # Subtract another 32 bytes \n\
|
||||
# (shadow space for arg regs) \n\
|
||||
xorq %%rbp, %%rbp # Set rbp to 0 \n\
|
||||
# We moved to the new stack. \n\
|
||||
# Now it's safe to release the OS stack. \n\
|
||||
movl $0x8000, %%r8d # dwFreeType: MEM_RELEASE \n\
|
||||
xorl %%edx, %%edx # dwSize: 0 \n\
|
||||
# dwAddress is already in the correct arg register rcx \n\
|
||||
call VirtualFree \n\
|
||||
# All set. We can copy the thread arg from the safe \n\
|
||||
# register r13 and then just call the function. \n\
|
||||
movq %%r13, %%rcx # Move thread arg to 1st arg reg\n\
|
||||
call *%%r12 # Call thread func \n"
|
||||
: : [WRAPPER_ARG] "r" (&wrapper_arg),
|
||||
[CYGTLS] "i" (CYGTLS_PADSIZE));
|
||||
#else
|
||||
__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 stackaddr into edx \n\
|
||||
@ -560,10 +589,74 @@ thread_wrapper (VOID *arg)
|
||||
call *%%eax # Call thread func \n"
|
||||
: : [WRAPPER_ARG] "r" (&wrapper_arg),
|
||||
[CYGTLS] "i" (CYGTLS_PADSIZE));
|
||||
#endif
|
||||
/* Never return from here. */
|
||||
ExitThread (0);
|
||||
}
|
||||
|
||||
#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,
|
||||
@ -607,14 +700,18 @@ CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
|
||||
/* Now roundup the result to the next allocation boundary. */
|
||||
real_stacksize = roundup2 (real_stacksize,
|
||||
wincap.allocation_granularity ());
|
||||
/* Reserve stack.
|
||||
FIXME? If the TOP_DOWN method tends to collide too much with
|
||||
/* 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. Two cases: */
|
||||
@ -659,11 +756,9 @@ CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
|
||||
wrapper_arg->stacklimit = real_stacklimit;
|
||||
}
|
||||
/* 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. */
|
||||
minimum size for a thread stack is reserved by the OS. 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,
|
||||
@ -680,3 +775,25 @@ err:
|
||||
}
|
||||
return thread;
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
// TODO: The equivalent newlib functions only work for SYSV ABI so far.
|
||||
#undef RtlFillMemory
|
||||
#undef RtlCopyMemory
|
||||
extern "C" void NTAPI RtlFillMemory (PVOID, SIZE_T, BYTE);
|
||||
extern "C" void NTAPI RtlCopyMemory (PVOID, const VOID *, SIZE_T);
|
||||
|
||||
extern "C" void *
|
||||
memset (void *s, int c, size_t n)
|
||||
{
|
||||
RtlFillMemory (s, n, c);
|
||||
return s;
|
||||
}
|
||||
|
||||
extern "C" void *
|
||||
memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
RtlCopyMemory (dest, src, n);
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user