about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCarlos O'Donell <carlos@systemhalted.org>2013-08-16 14:57:59 -0400
committerMike Frysinger <vapier@gentoo.org>2013-08-16 15:13:14 -0400
commit08c71a5db6716be0e176b0e5128bf6eb901714ad (patch)
treecaae3c70fb267b7c340bdda2c57ace40e7387f1f
parentfd8e484bf1a7cac40e6aba71fc4235aac7950eea (diff)
downloadglibc-08c71a5db6716be0e176b0e5128bf6eb901714ad.tar.gz
glibc-08c71a5db6716be0e176b0e5128bf6eb901714ad.tar.xz
glibc-08c71a5db6716be0e176b0e5128bf6eb901714ad.zip
nptl: support thread stacks that grow up
http://bugs.gentoo.org/301642
-rw-r--r--nptl/allocatestack.c22
-rw-r--r--nptl/pthread_attr_getstack.c4
-rw-r--r--nptl/pthread_attr_setstack.c8
-rw-r--r--nptl/pthread_create.c21
-rw-r--r--nptl/pthread_getattr_np.c13
5 files changed, 55 insertions, 13 deletions
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index 1e0fe1f18d..a3bfeb3fec 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -371,6 +371,15 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
   if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0))
     {
       uintptr_t adj;
+#if _STACK_GROWS_DOWN
+      char * stackaddr = (char *) attr->stackaddr;
+#else
+      /* Assume the same layout as the _STACK_GROWS_DOWN case, 
+	 with struct pthread at the top of the stack block. 
+	 Later we adjust the guard location and stack address 
+	 to match the _STACK_GROWS_UP case.  */
+      char * stackaddr = (char *) attr->stackaddr + attr->stacksize;
+#endif
 
       /* If the user also specified the size of the stack make sure it
 	 is large enough.  */
@@ -380,11 +389,11 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 
       /* Adjust stack size for alignment of the TLS block.  */
 #if TLS_TCB_AT_TP
-      adj = ((uintptr_t) attr->stackaddr - TLS_TCB_SIZE)
+      adj = ((uintptr_t) stackaddr - TLS_TCB_SIZE)
 	    & __static_tls_align_m1;
       assert (size > adj + TLS_TCB_SIZE);
 #elif TLS_DTV_AT_TP
-      adj = ((uintptr_t) attr->stackaddr - __static_tls_size)
+      adj = ((uintptr_t) stackaddr - __static_tls_size)
 	    & __static_tls_align_m1;
       assert (size > adj);
 #endif
@@ -394,10 +403,10 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 	 the stack.  It is the user's responsibility to do this if it
 	 is wanted.  */
 #if TLS_TCB_AT_TP
-      pd = (struct pthread *) ((uintptr_t) attr->stackaddr
+      pd = (struct pthread *) ((uintptr_t) stackaddr
 			       - TLS_TCB_SIZE - adj);
 #elif TLS_DTV_AT_TP
-      pd = (struct pthread *) (((uintptr_t) attr->stackaddr
+      pd = (struct pthread *) (((uintptr_t) stackaddr
 				- __static_tls_size - adj)
 			       - TLS_PRE_TCB_SIZE);
 #endif
@@ -409,7 +418,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
       pd->specific[0] = pd->specific_1stblock;
 
       /* Remember the stack-related values.  */
-      pd->stackblock = (char *) attr->stackaddr - size;
+      pd->stackblock = (char *) stackaddr - size;
       pd->stackblock_size = size;
 
       /* This is a user-provided stack.  It will not be queued in the
@@ -635,7 +644,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 	  char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
 #elif _STACK_GROWS_DOWN
 	  char *guard = mem;
-# elif _STACK_GROWS_UP
+#elif _STACK_GROWS_UP
 	  char *guard = (char *) (((uintptr_t) pd - guardsize) & ~pagesize_m1);
 #endif
 	  if (mprotect (guard, guardsize, PROT_NONE) != 0)
@@ -731,7 +740,6 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
   *stack = stacktop;
 #elif _STACK_GROWS_UP
   *stack = pd->stackblock;
-  assert (*stack > 0);
 #endif
 
   return 0;
diff --git a/nptl/pthread_attr_getstack.c b/nptl/pthread_attr_getstack.c
index 03907b7242..6bca1b56ca 100644
--- a/nptl/pthread_attr_getstack.c
+++ b/nptl/pthread_attr_getstack.c
@@ -32,7 +32,11 @@ __pthread_attr_getstack (attr, stackaddr, stacksize)
   iattr = (struct pthread_attr *) attr;
 
   /* Store the result.  */
+#ifdef _STACK_GROWS_DOWN
   *stackaddr = (char *) iattr->stackaddr - iattr->stacksize;
+#else
+  *stackaddr = (char *) iattr->stackaddr;
+#endif
   *stacksize = iattr->stacksize;
 
   return 0;
diff --git a/nptl/pthread_attr_setstack.c b/nptl/pthread_attr_setstack.c
index 4bd314e66a..7648a2a7e8 100644
--- a/nptl/pthread_attr_setstack.c
+++ b/nptl/pthread_attr_setstack.c
@@ -48,7 +48,11 @@ __pthread_attr_setstack (attr, stackaddr, stacksize)
 #endif
 
   iattr->stacksize = stacksize;
+#if _STACK_GROWS_DOWN
   iattr->stackaddr = (char *) stackaddr + stacksize;
+#else
+  iattr->stackaddr = (char *) stackaddr;
+#endif
   iattr->flags |= ATTR_FLAG_STACKADDR;
 
   return 0;
@@ -81,7 +85,11 @@ __old_pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
 #  endif
 
   iattr->stacksize = stacksize;
+#if _STACK_GROWS_DOWN
   iattr->stackaddr = (char *) stackaddr + stacksize;
+#else
+  iattr->stackaddr = (char *) stackaddr;
+#endif
   iattr->flags |= ATTR_FLAG_STACKADDR;
 
   return 0;
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 7f714f8903..736cc89a17 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -401,13 +401,26 @@ start_thread (void *arg)
 #ifdef _STACK_GROWS_DOWN
   char *sp = CURRENT_STACK_FRAME;
   size_t freesize = (sp - (char *) pd->stackblock) & ~pagesize_m1;
-#else
-# error "to do"
-#endif
   assert (freesize < pd->stackblock_size);
   if (freesize > PTHREAD_STACK_MIN)
     __madvise (pd->stackblock, freesize - PTHREAD_STACK_MIN, MADV_DONTNEED);
-
+#else
+  /* Page aligned start of memory to free (higher than or equal 
+     to current sp plus the minimum stack size).  */
+  void *freeblock = (void*)((size_t)(CURRENT_STACK_FRAME 
+				     + PTHREAD_STACK_MIN 
+				     + pagesize_m1) 
+				    & ~pagesize_m1);
+  char *free_end = (char *) (((uintptr_t) pd - pd->guardsize) & ~pagesize_m1);
+  /* Is there any space to free?  */
+  if (free_end > (char *)freeblock)
+    {
+      size_t freesize = (size_t)(free_end - (char *)freeblock);
+      assert (freesize < pd->stackblock_size);
+      __madvise (freeblock, freesize, MADV_DONTNEED);
+    }
+#endif
+ 
   /* If the thread is detached free the TCB.  */
   if (IS_DETACHED (pd))
     /* Free the TCB.  */
diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c
index 88ac072aeb..6c84f8b3c6 100644
--- a/nptl/pthread_getattr_np.c
+++ b/nptl/pthread_getattr_np.c
@@ -60,7 +60,11 @@ pthread_getattr_np (thread_id, attr)
   if (__builtin_expect (thread->stackblock != NULL, 1))
     {
       iattr->stacksize = thread->stackblock_size;
+#ifdef _STACK_GROWS_DOWN
       iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize;
+#else
+      iattr->stackaddr = (char *) thread->stackblock;
+#endif
     }
   else
     {
@@ -129,12 +133,17 @@ pthread_getattr_np (thread_id, attr)
 		         stack extension request.  */
 		      iattr->stacksize = (iattr->stacksize
 					  & -(intptr_t) GLRO(dl_pagesize));
-
+#if _STACK_GROWS_DOWN
 		      /* The limit might be too high.  */
 		      if ((size_t) iattr->stacksize
 			  > (size_t) iattr->stackaddr - last_to)
 			iattr->stacksize = (size_t) iattr->stackaddr - last_to;
-
+#else
+		      /* The limit might be too high.  */
+		      if ((size_t) iattr->stacksize
+			  > to - (size_t) iattr->stackaddr)
+			iattr->stacksize = to - (size_t) iattr->stackaddr;
+#endif
 		      /* We succeed and no need to look further.  */
 		      ret = 0;
 		      break;