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
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/miscfuncs.cc')
-rw-r--r--winsup/cygwin/miscfuncs.cc147
1 files changed, 132 insertions, 15 deletions
diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc
index 4f9c9df9d..521486ee7 100644
--- a/winsup/cygwin/miscfuncs.cc
+++ b/winsup/cygwin/miscfuncs.cc
@@ -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