Implement correct RLIMIT_STACK handling
* miscfuncs.cc (struct pthread_wrapper_arg): Add member guardsize. (pthread_wrapper): Set thread stack guarantee according to guardsize. Tweak assembler code so that $rax/$eax is not required by GCC to prepare the wrapper_arg value. (CygwinCreateThread): Fix deadzone handling. Drop setting a "POSIX" guardpage (aka page w/ PAGE_NOACCESS). Always use Windows guard pages instead. On post-XP systems (providing SetThreadStackGuarantee) always set up stack Windows like with reserved/commited areas and movable guard pages. Only on XP set up stack fully commited if the guardpage size is not the default system guardpage size. Fill out pthread_wrapper_arg::guardsize. Improve comments. * resource.cc: Implement RSTACK_LIMIT Linux-like. (DEFAULT_STACKSIZE): New macro. (DEFAULT_STACKGUARD): Ditto. (rlimit_stack_guard): New muto. (rlimit_stack): New global variable holding current RSTACK_LIMIT values. (__set_rlimit_stack): Set rlimit_stack under lock. (__get_rlimit_stack): Initialize rlimit_stack from executable header and return rlimit_stack values under lock. (get_rlimit_stack): Filtering function to return useful default stacksize from rlimit_stack.rlim_cur value. (getrlimit): Call __get_rlimit_stack in RLIMIT_STACK case. (setrlimit): Call __set_rlimit_stack in RLIMIT_STACK case. * thread.cc (pthread::create): Fetch default stacksize calling get_rlimit_stack. (pthread_attr::pthread_attr): Fetch default guardsize calling wincap.def_guard_page_size. (pthread_attr_getstacksize): Fetch default stacksize calling get_rlimit_stack. * thread.h (PTHREAD_DEFAULT_STACKSIZE): Remove. (PTHREAD_DEFAULT_GUARDSIZE): Remove. (get_rlimit_stack): Declare. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
@ -111,6 +111,61 @@ getrusage (int intwho, struct rusage *rusage_in)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Default stacksize in case RLIMIT_STACK is RLIM_INFINITY is 2 Megs with
|
||||
system-dependent number of guard pages. The pthread stacksize does not
|
||||
include the guardpage size, so we have to subtract the default guardpage
|
||||
size. Additionally the Windows stack handling disallows to commit the
|
||||
last page, so we subtract it, too. */
|
||||
#define DEFAULT_STACKSIZE (2 * 1024 * 1024)
|
||||
#define DEFAULT_STACKGUARD (wincap.def_guard_page_size() + wincap.page_size ())
|
||||
|
||||
muto NO_COPY rlimit_stack_guard;
|
||||
static struct rlimit rlimit_stack = { 0, RLIM_INFINITY };
|
||||
|
||||
static void
|
||||
__set_rlimit_stack (const struct rlimit *rlp)
|
||||
{
|
||||
rlimit_stack_guard.init ("rlimit_stack_guard")->acquire ();
|
||||
rlimit_stack = *rlp;
|
||||
rlimit_stack_guard.release ();
|
||||
}
|
||||
|
||||
static void
|
||||
__get_rlimit_stack (struct rlimit *rlp)
|
||||
{
|
||||
rlimit_stack_guard.init ("rlimit_stack_guard")->acquire ();
|
||||
if (!rlimit_stack.rlim_cur)
|
||||
{
|
||||
/* Fetch the default stacksize from the executable header... */
|
||||
PIMAGE_DOS_HEADER dosheader;
|
||||
PIMAGE_NT_HEADERS ntheader;
|
||||
|
||||
dosheader = (PIMAGE_DOS_HEADER) GetModuleHandle (NULL);
|
||||
ntheader = (PIMAGE_NT_HEADERS) ((PBYTE) dosheader + dosheader->e_lfanew);
|
||||
rlimit_stack.rlim_cur = ntheader->OptionalHeader.SizeOfStackReserve;
|
||||
/* ...and subtract the guardpages. */
|
||||
rlimit_stack.rlim_cur -= DEFAULT_STACKGUARD;
|
||||
}
|
||||
*rlp = rlimit_stack;
|
||||
rlimit_stack_guard.release ();
|
||||
}
|
||||
|
||||
size_t
|
||||
get_rlimit_stack (void)
|
||||
{
|
||||
struct rlimit rl;
|
||||
|
||||
__get_rlimit_stack (&rl);
|
||||
/* RLIM_INFINITY doesn't make much sense. As in glibc, use an
|
||||
"architecture-specific default". */
|
||||
if (rl.rlim_cur == RLIM_INFINITY)
|
||||
rl.rlim_cur = DEFAULT_STACKSIZE - DEFAULT_STACKGUARD;
|
||||
/* Always return at least minimum stacksize. */
|
||||
else if (rl.rlim_cur < PTHREAD_STACK_MIN)
|
||||
rl.rlim_cur = PTHREAD_STACK_MIN;
|
||||
return (size_t) rl.rlim_cur;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
getrlimit (int resource, struct rlimit *rlp)
|
||||
{
|
||||
@ -127,32 +182,7 @@ getrlimit (int resource, struct rlimit *rlp)
|
||||
case RLIMIT_AS:
|
||||
break;
|
||||
case RLIMIT_STACK:
|
||||
PTEB teb;
|
||||
/* 2015-06-26: Originally rlim_cur returned the size of the still
|
||||
available stack area on the current stack, rlim_max the total size
|
||||
of the current stack. Two problems:
|
||||
|
||||
- Per POSIX, RLIMIT_STACK returns "the maximum size of the initial
|
||||
thread's stack, in bytes. The implementation does not
|
||||
automatically grow the stack beyond this limit".
|
||||
|
||||
- With the implementation of sigaltstack, the current stack is not
|
||||
necessarily the "initial thread's stack" anymore. Rather, when
|
||||
called from a signal handler running on the alternate stack,
|
||||
RLIMIT_STACK should return the size of the original stack.
|
||||
|
||||
rlim_cur is now the size of the stack. For system-provided stacks
|
||||
it's the size between DeallocationStack and StackBase. For
|
||||
application-provided stacks (via pthread_attr_setstack),
|
||||
DeallocationStack is NULL, but StackLimit points to the bottom
|
||||
of the stack.
|
||||
|
||||
rlim_max is set to RLIM_INFINITY since there's no hard limit
|
||||
for stack sizes on Windows. */
|
||||
teb = NtCurrentTeb ();
|
||||
rlp->rlim_cur = (rlim_t) teb->Tib.StackBase
|
||||
- (rlim_t) (teb->DeallocationStack
|
||||
?: teb->Tib.StackLimit);
|
||||
__get_rlimit_stack (rlp);
|
||||
break;
|
||||
case RLIMIT_NOFILE:
|
||||
rlp->rlim_cur = getdtablesize ();
|
||||
@ -206,6 +236,9 @@ setrlimit (int resource, const struct rlimit *rlp)
|
||||
if (rlp->rlim_cur != RLIM_INFINITY)
|
||||
return setdtablesize (rlp->rlim_cur);
|
||||
break;
|
||||
case RLIMIT_STACK:
|
||||
__set_rlimit_stack (rlp);
|
||||
break;
|
||||
default:
|
||||
set_errno (EINVAL);
|
||||
__leave;
|
||||
|
Reference in New Issue
Block a user