This is the mail archive of the libc-hacker@sourceware.org mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Support multiple pagesize kernels


The recently announced POWER5+ hardware now supports 4KB, 64KB, and 16KB
pages sizes. For large systems used in High Performance Computing or
large scale data base applications a larger page size makes the TLB more
effective and boosts performance.

At this year's OLS there was discussion of adding a kernel option to
support 64KB (vs 4KB) as the base page size in these environments. I
suspect that a larger base page is an issue for IA64 as well. This
raises the possibility that the page size may change depending on which
kernel was booted for that machine. This page size will be reported via
AT_PAGESZ but currently NPTL pthread_create does not handle the larger
pagesize.

The attached patch allows PTHREAD_STACK_MIN to remain unchanged and
still apply when stackaddr is supplied. But allow the default case to
allocate the minimum 2 * pagesize stack (plus guardpage), even when
PTHREAD_STACK_MIN is < (2 * pagesize).

2005-10-05  Steven Munroe  <sjmunroe@us.ibm.com>

	* allocatestack.c (allocate_stack): Add support for large page
	kernels.  Handled cases where __default_stacksize is less than
	2 * pagesize.  
	* init.c (__pthread_initialize_minimal_internal): Insure that
	__default_stacksize is at least the greater of PTHREAD_STACK_MIN
	or (2 * pagesz).
	* tst-stack2.c (do_test): pthread_create may fail when stacksize
	is PTHREAD_STACK_MIN, stackaddr is not specified, and 
	PTHREAD_STACK_MIN is < (2 * pagesize).  pthread_create should 
	succeed when, stacksize >= PTHREAD_STACK_MIN and stackaddr is
	supplied.  pthread_create() should always succeed with the default
	pthread_attr_t.

diff -urN libc24-cvstip-20050926/nptl/allocatestack.c libc24/nptl/allocatestack.c
--- libc24-cvstip-20050926/nptl/allocatestack.c	2005-01-06 16:40:24.000000000 -0600
+++ libc24/nptl/allocatestack.c	2005-10-05 11:31:42.000000000 -0500
@@ -291,7 +291,8 @@
 {
   struct pthread *pd;
   size_t size;
-  size_t pagesize_m1 = __getpagesize () - 1;
+  size_t pagesize = __getpagesize ();
+  size_t pagesize_m1 = pagesize - 1;
   void *stacktop;
 
   assert (attr != NULL);
@@ -390,6 +391,16 @@
       void *mem;
       const int prot = (PROT_READ | PROT_WRITE
 			| ((GL(dl_stack_flags) & PF_X) ? PROT_EXEC : 0));
+  
+      /* Handle the case where the system page size is not the default
+         and is larger then the default stack size.  If so we bump size 
+	 up to 2 pages and set the __default_stacksize to be two pages.  */
+      if ((attr->stacksize == 0) && (size < (2 * pagesize)))
+        {
+          size = 2 * pagesize; 
+          if (size > __default_stacksize)
+            __default_stacksize = size;
+        }
 
 #if COLORING_INCREMENT != 0
       /* Add one more page for stack coloring.  Don't do it for stacks
@@ -406,8 +417,9 @@
       /* Make sure the size of the stack is enough for the guard and
 	 eventually the thread descriptor.  */
       guardsize = (attr->guardsize + pagesize_m1) & ~pagesize_m1;
-      if (__builtin_expect (size < (guardsize + __static_tls_size
-				    + MINIMAL_REST_STACK + pagesize_m1 + 1),
+      if (__builtin_expect (size < ((guardsize + __static_tls_size
+				    + MINIMAL_REST_STACK
+				    + pagesize_m1) & ~pagesize_m1),
 			    0))
 	/* The stack is too small (or the guard too large).  */
 	return EINVAL;
diff -urN libc24-cvstip-20050926/nptl/init.c libc24/nptl/init.c
--- libc24-cvstip-20050926/nptl/init.c	2004-12-27 19:39:50.000000000 -0600
+++ libc24/nptl/init.c	2005-09-28 16:43:20.000000000 -0500
@@ -284,19 +284,25 @@
   /* Determine the default allowed stack size.  This is the size used
      in case the user does not specify one.  */
   struct rlimit limit;
+  const uintptr_t pagesz = __sysconf (_SC_PAGESIZE);
   if (getrlimit (RLIMIT_STACK, &limit) != 0
       || limit.rlim_cur == RLIM_INFINITY)
     /* The system limit is not usable.  Use an architecture-specific
        default.  */
     __default_stacksize = ARCH_STACK_DEFAULT_SIZE;
-  else if (limit.rlim_cur < PTHREAD_STACK_MIN)
-    /* The system limit is unusably small.
-       Use the minimal size acceptable.  */
-    __default_stacksize = PTHREAD_STACK_MIN;
+  else if (limit.rlim_cur < PTHREAD_STACK_MIN
+           || limit.rlim_cur < (2 * pagesz))
+    {
+      /* The system limit is unusably small.
+         Use the minimal size acceptable.  */
+      if (PTHREAD_STACK_MIN < (2 * pagesz))
+        __default_stacksize = (2 * pagesz);
+      else
+        __default_stacksize = PTHREAD_STACK_MIN;
+    }
   else
     {
       /* Round the resource limit up to page size.  */
-      const uintptr_t pagesz = __sysconf (_SC_PAGESIZE);
       __default_stacksize = (limit.rlim_cur + pagesz - 1) & -pagesz;
     }
 
diff -urN libc24-cvstip-20050926/nptl/tst-stack2.c libc24/nptl/tst-stack2.c
--- libc24-cvstip-20050926/nptl/tst-stack2.c	2003-09-03 00:06:52.000000000 -0500
+++ libc24/nptl/tst-stack2.c	2005-10-05 15:42:12.487259896 -0500
@@ -23,6 +23,7 @@
 #include <pthread.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <unistd.h>
 
 static int seen;
 
@@ -38,9 +39,15 @@
 {
   pthread_attr_t attr;
   pthread_attr_init (&attr);
+  long pagesize;
 
   int result = 0;
-  int res = pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
+  int res;
+
+  pagesize = sysconf(_SC_PAGESIZE);
+  printf ("sysconf(_SC_PAGESIZE) = %ld\n", pagesize);
+  
+  res = pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
   if (res)
     {
       printf ("pthread_attr_setstacksize failed %d\n", res);
@@ -53,6 +60,74 @@
   if (res)
     {
       printf ("pthread_create failed %d\n", res);
+      
+      if ((PTHREAD_STACK_MIN) < (2 * pagesize))
+        {
+	/* This is OK because the system has multiple pages sizes and
+	   it is currently running with pagesize >= PTHREAD_STACK_MIN.  */
+          puts("PTHREAD_STACK_MIN < (2 * pagesize)");
+          seen++;
+	}
+      else
+        result = 1;
+    }
+  else
+    {
+      res = pthread_join (th, NULL);
+      if (res)
+	{
+	  printf ("pthread_join failed %d\n", res);
+	  result = 1;
+	}
+    }
+    
+  /* However PTHREAD_STACK_MIN should always be valid when stackaddr is set.  */
+  
+  void *stack;
+  size_t size = PTHREAD_STACK_MIN;
+
+  
+  if (posix_memalign (&stack, getpagesize (), size) != 0)
+    {
+      puts ("out of memory while allocating the stack memory");
+      return (1);
+    }
+
+  if (pthread_attr_init (&attr) != 0)
+    {
+      puts ("attr_init failed");
+      return (1);
+    }
+
+  if (pthread_attr_setstack (&attr, stack, size) != 0)
+    {
+      puts ("attr_setstack failed");
+      return (1);
+    }
+    
+  res = pthread_create (&th, &attr, tf, NULL);
+  if (res)
+    {
+      printf ("pthread_create failed %d\n", res);
+      result = 1;
+    }
+  else
+    {
+      res = pthread_join (th, NULL);
+      if (res)
+	{
+	  printf ("pthread_join failed %d\n", res);
+	  result = 1;
+	}
+    }
+
+  /* The default pthread_attr_t should always work, even if the page
+     size is larger then expected.  */
+    
+  res = pthread_create (&th, NULL, tf, NULL);
+  if (res)
+    {
+      printf ("pthread_create failed %d\n", res);
       result = 1;
     }
   else
@@ -65,9 +140,9 @@
 	}
     }
 
-  if (seen != 1)
+  if (seen != 3)
     {
-      printf ("seen %d != 1\n", seen);
+      printf ("seen %d != 3\n", seen);
       result = 1;
     }
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]