Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
nptl: support thread stacks that grow up
Gentoo has been carrying this for all arches since 2.17.

URL: http://bugs.gentoo.org/301642
  • Loading branch information
Carlos O'Donell authored and Mike Frysinger committed Feb 19, 2016
1 parent 11fca96 commit d615a47
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 12 deletions.
11 changes: 11 additions & 0 deletions ChangeLog
@@ -1,3 +1,14 @@
2016-02-19 Carlos O'Donell <carlos@systemhalted.org>

* nptl/allocatestack.c (allocate_stack): Declare new stackaddr,
assign attr->stackaddr to it, and adjust it down when
_STACK_GROWS_UP. Change all attr->stackaddr to stackaddr.
[_STACK_GROWS_UP]: Delete assert.
* nptl/pthread_create.c (START_THREAD_DEFN) [!_STACK_GROWS_DOWN]:
Implement stack grows up logic.
* nptl/pthread_getattr_np.c (pthread_getattr_np): Implement
stack grows up logic.

2016-02-19 Adhemerval Zanella <adhemerval.zanella@linaro.org> 2016-02-19 Adhemerval Zanella <adhemerval.zanella@linaro.org>


* NEWS: Update with 2.24 template. * NEWS: Update with 2.24 template.
Expand Down
20 changes: 13 additions & 7 deletions nptl/allocatestack.c
Expand Up @@ -372,6 +372,13 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
if (__glibc_unlikely (attr->flags & ATTR_FLAG_STACKADDR)) if (__glibc_unlikely (attr->flags & ATTR_FLAG_STACKADDR))
{ {
uintptr_t adj; uintptr_t adj;
char *stackaddr = (char *) attr->stackaddr;

/* 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. */
if (_STACK_GROWS_UP)
stackaddr += attr->stacksize;


/* If the user also specified the size of the stack make sure it /* If the user also specified the size of the stack make sure it
is large enough. */ is large enough. */
Expand All @@ -381,11 +388,11 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,


/* Adjust stack size for alignment of the TLS block. */ /* Adjust stack size for alignment of the TLS block. */
#if TLS_TCB_AT_TP #if TLS_TCB_AT_TP
adj = ((uintptr_t) attr->stackaddr - TLS_TCB_SIZE) adj = ((uintptr_t) stackaddr - TLS_TCB_SIZE)
& __static_tls_align_m1; & __static_tls_align_m1;
assert (size > adj + TLS_TCB_SIZE); assert (size > adj + TLS_TCB_SIZE);
#elif TLS_DTV_AT_TP #elif TLS_DTV_AT_TP
adj = ((uintptr_t) attr->stackaddr - __static_tls_size) adj = ((uintptr_t) stackaddr - __static_tls_size)
& __static_tls_align_m1; & __static_tls_align_m1;
assert (size > adj); assert (size > adj);
#endif #endif
Expand All @@ -395,10 +402,10 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
the stack. It is the user's responsibility to do this if it the stack. It is the user's responsibility to do this if it
is wanted. */ is wanted. */
#if TLS_TCB_AT_TP #if TLS_TCB_AT_TP
pd = (struct pthread *) ((uintptr_t) attr->stackaddr pd = (struct pthread *) ((uintptr_t) stackaddr
- TLS_TCB_SIZE - adj); - TLS_TCB_SIZE - adj);
#elif TLS_DTV_AT_TP #elif TLS_DTV_AT_TP
pd = (struct pthread *) (((uintptr_t) attr->stackaddr pd = (struct pthread *) (((uintptr_t) stackaddr
- __static_tls_size - adj) - __static_tls_size - adj)
- TLS_PRE_TCB_SIZE); - TLS_PRE_TCB_SIZE);
#endif #endif
Expand All @@ -410,7 +417,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
pd->specific[0] = pd->specific_1stblock; pd->specific[0] = pd->specific_1stblock;


/* Remember the stack-related values. */ /* Remember the stack-related values. */
pd->stackblock = (char *) attr->stackaddr - size; pd->stackblock = (char *) stackaddr - size;
pd->stackblock_size = size; pd->stackblock_size = size;


/* This is a user-provided stack. It will not be queued in the /* This is a user-provided stack. It will not be queued in the
Expand Down Expand Up @@ -634,7 +641,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1); char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
#elif _STACK_GROWS_DOWN #elif _STACK_GROWS_DOWN
char *guard = mem; char *guard = mem;
# elif _STACK_GROWS_UP #elif _STACK_GROWS_UP
char *guard = (char *) (((uintptr_t) pd - guardsize) & ~pagesize_m1); char *guard = (char *) (((uintptr_t) pd - guardsize) & ~pagesize_m1);
#endif #endif
if (mprotect (guard, guardsize, PROT_NONE) != 0) if (mprotect (guard, guardsize, PROT_NONE) != 0)
Expand Down Expand Up @@ -734,7 +741,6 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
# endif # endif
#else #else
*stack = pd->stackblock; *stack = pd->stackblock;
assert (*stack > 0);
#endif #endif


return 0; return 0;
Expand Down
19 changes: 16 additions & 3 deletions nptl/pthread_create.c
Expand Up @@ -427,12 +427,25 @@ START_THREAD_DEFN
#ifdef _STACK_GROWS_DOWN #ifdef _STACK_GROWS_DOWN
char *sp = CURRENT_STACK_FRAME; char *sp = CURRENT_STACK_FRAME;
size_t freesize = (sp - (char *) pd->stackblock) & ~pagesize_m1; size_t freesize = (sp - (char *) pd->stackblock) & ~pagesize_m1;
#else
# error "to do"
#endif
assert (freesize < pd->stackblock_size); assert (freesize < pd->stackblock_size);
if (freesize > PTHREAD_STACK_MIN) if (freesize > PTHREAD_STACK_MIN)
__madvise (pd->stackblock, freesize - PTHREAD_STACK_MIN, MADV_DONTNEED); __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 the thread is detached free the TCB. */
if (IS_DETACHED (pd)) if (IS_DETACHED (pd))
Expand Down
17 changes: 15 additions & 2 deletions nptl/pthread_getattr_np.c
Expand Up @@ -58,7 +58,11 @@ pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
if (__glibc_likely (thread->stackblock != NULL)) if (__glibc_likely (thread->stackblock != NULL))
{ {
iattr->stacksize = thread->stackblock_size; iattr->stacksize = thread->stackblock_size;
#if _STACK_GROWS_DOWN
iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize; iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize;
#else
iattr->stackaddr = (char *) thread->stackblock;
#endif
} }
else else
{ {
Expand Down Expand Up @@ -103,7 +107,9 @@ pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)


char *line = NULL; char *line = NULL;
size_t linelen = 0; size_t linelen = 0;
#if _STACK_GROWS_DOWN
uintptr_t last_to = 0; uintptr_t last_to = 0;
#endif


while (! feof_unlocked (fp)) while (! feof_unlocked (fp))
{ {
Expand All @@ -127,17 +133,24 @@ pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
stack extension request. */ stack extension request. */
iattr->stacksize = (iattr->stacksize iattr->stacksize = (iattr->stacksize
& -(intptr_t) GLRO(dl_pagesize)); & -(intptr_t) GLRO(dl_pagesize));

#if _STACK_GROWS_DOWN
/* The limit might be too high. */ /* The limit might be too high. */
if ((size_t) iattr->stacksize if ((size_t) iattr->stacksize
> (size_t) iattr->stackaddr - last_to) > (size_t) iattr->stackaddr - last_to)
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. */ /* We succeed and no need to look further. */
ret = 0; ret = 0;
break; break;
} }
#if _STACK_GROWS_DOWN
last_to = to; last_to = to;
#endif
} }


free (line); free (line);
Expand Down

0 comments on commit d615a47

Please sign in to comment.