about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVicent Segui Pascual <segui@google.com>2016-01-18 02:05:31 -0800
committerVicent Segui Pascual <segui@google.com>2016-01-18 02:05:31 -0800
commitbab244a0066749511f2c76efa2a499b39b6181ef (patch)
tree3afc484f1f03daf9f96be0528c6defa2602ca7ed
parentfa9a6cbaeaf0ddd6ff6dcbbc09a4dda802cdb15e (diff)
downloadglibc-bab244a0066749511f2c76efa2a499b39b6181ef.tar.gz
glibc-bab244a0066749511f2c76efa2a499b39b6181ef.tar.xz
glibc-bab244a0066749511f2c76efa2a499b39b6181ef.zip
Use munlock before madvise to make sure that we effectively "uncommit" the page
-rw-r--r--README.google5
-rw-r--r--nptl/Makefile2
-rw-r--r--nptl/allocatestack.c6
-rw-r--r--nptl/tst-basic8.c91
4 files changed, 103 insertions, 1 deletions
diff --git a/README.google b/README.google
index 3b478f5da7..0b0792ec93 100644
--- a/README.google
+++ b/README.google
@@ -544,3 +544,8 @@ iconv/gconv_trans.c
 resolv/res_send.c
   For b/25900273, adjust allocations to avoid segfault.
   (bmoses, google-local)
+
+nptl/allocatestack.c
+nptl/Makefile
+nptl/tst-basic8.c
+  For b/24399992 unlock guard pages to avoid wasting memory.
diff --git a/nptl/Makefile b/nptl/Makefile
index f669d1a3cc..3176e54dba 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -234,7 +234,7 @@ tests = tst-typesizes \
 	tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \
 	tst-align tst-align2 tst-align3 \
 	tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \
-	tst-basic7 \
+	tst-basic7 tst-basic8 \
 	tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \
 	tst-raise1 \
 	tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-join6 \
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index e8dfbbb8de..c6264aa4dd 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -656,6 +656,12 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 
 	      return errno;
 	    }
+	  /* The call to madvise(...MADV_DONTNEED) below will fail if pages
+	     are locked. Unlock the guard memory to make sure the
+	     madvise function succeeds (memory can be locked if
+	     process called mlockall(MCL_FUTURE) at some point in the
+	     past).*/
+	  munlock (guard, guardsize);
 	  /* We've marked this guard region unwritable, but it's
 	     possible it already became resident, the most common case
 	     being transparent hugepages; if stack + guard (+ adjacent
diff --git a/nptl/tst-basic8.c b/nptl/tst-basic8.c
new file mode 100644
index 0000000000..3dc700c814
--- /dev/null
+++ b/nptl/tst-basic8.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <pthread.h>
+/* Test that stack guards do not become resident, even with
+mlockall(MCL_FUTURE) by verifying that spawning NTHREADS with these
+stack/guard sizes use a reasonable (<100kb/thread) amount of RSS. */
+#define NTHREADS 100
+#define STACKSIZE (64 * 1024)
+#define GUARDSIZE (1024 * 1024)
+
+pthread_barrier_t barrier;
+
+
+static void fail (const char *msg)
+{
+  puts (msg);
+  exit (1);
+}
+
+static size_t get_rss_bytes (void)
+{
+  struct rusage usage;
+  if (getrusage(RUSAGE_SELF, &usage) != 0)
+    fail ("getrusage failed");
+
+  return usage.ru_maxrss * 1024;
+}
+
+static void *
+child (void *arg)
+{
+  int ret = pthread_barrier_wait(&barrier);
+  if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
+    fail("pthread_barrier_wait failed");
+  while (1)
+    {
+      sleep (10);
+    }
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  int err;
+  int i;
+  size_t bytes;
+  char buffer[2048];
+  size_t overhead, count;
+  int fd;
+  mlockall(MCL_CURRENT);
+  overhead = get_rss_bytes();
+  mlockall(MCL_CURRENT|MCL_FUTURE);
+  if (pthread_barrier_init(&barrier, NULL, NTHREADS + 1) != 0)
+    fail("pthread_barrier_init failed");
+  for (i = 0; i < NTHREADS; ++i)
+    {
+      pthread_attr_t attr;
+      pthread_t tid;
+      pthread_attr_init (&attr);
+      pthread_attr_setstacksize (&attr, STACKSIZE + GUARDSIZE);
+      pthread_attr_setguardsize (&attr, GUARDSIZE);
+      err = pthread_create (&tid, &attr, child, NULL);
+      if (err != 0)
+        fail("pthread_create failed");
+    }
+  err = pthread_barrier_wait(&barrier);
+  if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+    fail("pthread_barrier_wait failed");
+  bytes = get_rss_bytes ();
+  fd = open("/proc/self/smaps", O_RDONLY);
+  while(0 < (count = read(fd, buffer, 2048)))
+    write(1, buffer, count);
+  close(fd);
+  printf ("%d threads with %d stacks and %d guards using %zu per thread\n",
+          NTHREADS, STACKSIZE, GUARDSIZE, (bytes-overhead)/NTHREADS);
+  if ((bytes-overhead) > (NTHREADS * GUARDSIZE))
+    fail ("memory usage too high");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"