summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/resource.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/resource.cc')
-rw-r--r--winsup/cygwin/resource.cc85
1 files changed, 59 insertions, 26 deletions
diff --git a/winsup/cygwin/resource.cc b/winsup/cygwin/resource.cc
index 895ba7f33..a5a23a4d8 100644
--- a/winsup/cygwin/resource.cc
+++ b/winsup/cygwin/resource.cc
@@ -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;