mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-29 11:41:21 +03:00
2003-03-11 Jakub Jelinek <jakub@redhat.com>
* sysdeps/pthread/createthread.c (ARCH_CLONE): Define if not defined. (create_thread): Only assert PD->tcb != NULL under [TLS_TCB_AT_TP]. Use ARCH_CLONE. * allocatestack.c (ALLOCATE_STACK_PARMS): New macro. [NEED_SEPARATE_REGISTER_STACK] (STACK_VARIABLES, STACK_VARIABLES_ARGS, STACK_VARIABLES_PARMS, ALLOCATE_STACK_PARMS, ALLOCATE_STACK): New macros. (TLS_TPADJ): New macro. (get_cached_stack, queue_stack, __deallocate_stack): Use TLS_TPADJ. (allocate_stack): Handle TLS_DTV_AT_TP and NEED_SEPARATE_REGISTER_STACK. Use TLS_TPADJ. * pthread_create.c (__pthread_create_2_1) [! TLS_TCB_AT_TP]: Don't set PD->self. * init.c [__ia64__] (__NR_set_tid_address): Define.
This commit is contained in:
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NEED_SEPARATE_REGISTER_STACK
|
||||||
|
|
||||||
/* Most architectures have exactly one stack pointer. Some have more. */
|
/* Most architectures have exactly one stack pointer. Some have more. */
|
||||||
#define STACK_VARIABLES void *stackaddr
|
#define STACK_VARIABLES void *stackaddr
|
||||||
@ -39,6 +40,24 @@
|
|||||||
/* How to declare function which gets there parameters. */
|
/* How to declare function which gets there parameters. */
|
||||||
#define STACK_VARIABLES_PARMS void *stackaddr
|
#define STACK_VARIABLES_PARMS void *stackaddr
|
||||||
|
|
||||||
|
/* How to declare allocate_stack. */
|
||||||
|
#define ALLOCATE_STACK_PARMS void **stack
|
||||||
|
|
||||||
|
/* This is how the function is called. We do it this way to allow
|
||||||
|
other variants of the function to have more parameters. */
|
||||||
|
#define ALLOCATE_STACK(attr, pd) allocate_stack (attr, pd, &stackaddr)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define STACK_VARIABLES void *stackaddr; size_t stacksize
|
||||||
|
#define STACK_VARIABLES_ARGS stackaddr, stacksize
|
||||||
|
#define STACK_VARIABLES_PARMS void *stackaddr, size_t stacksize
|
||||||
|
#define ALLOCATE_STACK_PARMS void **stack, size_t *stacksize
|
||||||
|
#define ALLOCATE_STACK(attr, pd) \
|
||||||
|
allocate_stack (attr, pd, &stackaddr, &stacksize)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Default alignment of stack. */
|
/* Default alignment of stack. */
|
||||||
#ifndef STACK_ALIGN
|
#ifndef STACK_ALIGN
|
||||||
@ -58,6 +77,12 @@
|
|||||||
# define ARCH_MAP_FLAGS 0
|
# define ARCH_MAP_FLAGS 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* This yields the pointer that TLS support code calls the thread pointer. */
|
||||||
|
#if TLS_TCB_AT_TP
|
||||||
|
# define TLS_TPADJ(pd) (pd)
|
||||||
|
#elif TLS_DTV_AT_TP
|
||||||
|
# define TLS_TPADJ(pd) ((pd) + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Cache handling for not-yet free stacks. */
|
/* Cache handling for not-yet free stacks. */
|
||||||
|
|
||||||
@ -162,11 +187,13 @@ get_cached_stack (size_t *sizep, void **memp)
|
|||||||
result->nextevent = NULL;
|
result->nextevent = NULL;
|
||||||
|
|
||||||
/* Clear the DTV. */
|
/* Clear the DTV. */
|
||||||
dtv_t *dtv = GET_DTV (result);
|
dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
|
||||||
memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
|
memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
|
||||||
|
|
||||||
/* Re-initialize the TLS. */
|
/* Re-initialize the TLS. */
|
||||||
return _dl_allocate_tls_init (result);
|
_dl_allocate_tls_init (TLS_TPADJ (result));
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -203,7 +230,7 @@ queue_stack (struct pthread *stack)
|
|||||||
stack_cache_actsize -= curr->stackblock_size;
|
stack_cache_actsize -= curr->stackblock_size;
|
||||||
|
|
||||||
/* Free the memory associated with the ELF TLS. */
|
/* Free the memory associated with the ELF TLS. */
|
||||||
_dl_deallocate_tls (curr, false);
|
_dl_deallocate_tls (TLS_TPADJ (curr), false);
|
||||||
|
|
||||||
/* Remove this block. This should never fail. If it
|
/* Remove this block. This should never fail. If it
|
||||||
does something is really wrong. */
|
does something is really wrong. */
|
||||||
@ -222,11 +249,12 @@ queue_stack (struct pthread *stack)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
||||||
void **stack)
|
ALLOCATE_STACK_PARMS)
|
||||||
{
|
{
|
||||||
struct pthread *pd;
|
struct pthread *pd;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t pagesize_m1 = __getpagesize () - 1;
|
size_t pagesize_m1 = __getpagesize () - 1;
|
||||||
|
void *stacktop;
|
||||||
|
|
||||||
assert (attr != NULL);
|
assert (attr != NULL);
|
||||||
assert (powerof2 (pagesize_m1 + 1));
|
assert (powerof2 (pagesize_m1 + 1));
|
||||||
@ -248,15 +276,27 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
|||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
/* Adjust stack size for alignment of the TLS block. */
|
/* Adjust stack size for alignment of the TLS block. */
|
||||||
adj = ((uintptr_t) attr->stackaddr) & __static_tls_align_m1;
|
#if TLS_TCB_AT_TP
|
||||||
|
adj = ((uintptr_t) attr->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)
|
||||||
|
& __static_tls_align_m1;
|
||||||
assert (size > adj);
|
assert (size > adj);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The user provided some memory. Let's hope it matches the
|
/* The user provided some memory. Let's hope it matches the
|
||||||
size... We do not allocate guard pages if the user provided
|
size... We do not allocate guard pages if the user provided
|
||||||
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. */
|
||||||
pd = (struct pthread *) (((uintptr_t) attr->stackaddr - adj)
|
#if TLS_TCB_AT_TP
|
||||||
& ~(__alignof (struct pthread) - 1)) - 1;
|
pd = (struct pthread *) ((uintptr_t) attr->stackaddr
|
||||||
|
- TLS_TCB_SIZE - adj);
|
||||||
|
#elif TLS_DTV_AT_TP
|
||||||
|
pd = (struct pthread *) ((uintptr_t) attr->stackaddr
|
||||||
|
- __static_tls_size - adj) - 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The user provided stack memory needs to be cleared. */
|
/* The user provided stack memory needs to be cleared. */
|
||||||
memset (pd, '\0', sizeof (struct pthread));
|
memset (pd, '\0', sizeof (struct pthread));
|
||||||
@ -290,7 +330,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allocate the DTV for this thread. */
|
/* Allocate the DTV for this thread. */
|
||||||
if (_dl_allocate_tls (pd) == NULL)
|
if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
|
||||||
/* Something went wrong. */
|
/* Something went wrong. */
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
@ -371,7 +411,13 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Place the thread descriptor at the end of the stack. */
|
/* Place the thread descriptor at the end of the stack. */
|
||||||
|
#if TLS_TCB_AT_TP
|
||||||
pd = (struct pthread *) ((char *) mem + size - coloring) - 1;
|
pd = (struct pthread *) ((char *) mem + size - coloring) - 1;
|
||||||
|
#elif TLS_DTV_AT_TP
|
||||||
|
pd = (struct pthread *) (((uintptr_t) mem + size - coloring
|
||||||
|
- __static_tls_size)
|
||||||
|
& ~__static_tls_align_m1) - 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Remember the stack-related values. */
|
/* Remember the stack-related values. */
|
||||||
pd->stackblock = mem;
|
pd->stackblock = mem;
|
||||||
@ -400,7 +446,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allocate the DTV for this thread. */
|
/* Allocate the DTV for this thread. */
|
||||||
if (_dl_allocate_tls (pd) == NULL)
|
if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
|
||||||
{
|
{
|
||||||
/* Something went wrong. */
|
/* Something went wrong. */
|
||||||
int err = errno;
|
int err = errno;
|
||||||
@ -432,7 +478,12 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
|||||||
/* Create or resize the guard area if necessary. */
|
/* Create or resize the guard area if necessary. */
|
||||||
if (__builtin_expect (guardsize > pd->guardsize, 0))
|
if (__builtin_expect (guardsize > pd->guardsize, 0))
|
||||||
{
|
{
|
||||||
if (mprotect (mem, guardsize, PROT_NONE) != 0)
|
#ifdef NEED_SEPARATE_REGISTER_STACK
|
||||||
|
char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
|
||||||
|
#else
|
||||||
|
char *guard = mem;
|
||||||
|
#endif
|
||||||
|
if (mprotect (guard, guardsize, PROT_NONE) != 0)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
mprot_error:
|
mprot_error:
|
||||||
@ -446,7 +497,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
|||||||
lll_unlock (stack_cache_lock);
|
lll_unlock (stack_cache_lock);
|
||||||
|
|
||||||
/* Get rid of the TLS block we allocated. */
|
/* Get rid of the TLS block we allocated. */
|
||||||
_dl_deallocate_tls (pd, false);
|
_dl_deallocate_tls (TLS_TPADJ (pd), false);
|
||||||
|
|
||||||
/* Free the stack memory regardless of whether the size
|
/* Free the stack memory regardless of whether the size
|
||||||
of the cache is over the limit or not. If this piece
|
of the cache is over the limit or not. If this piece
|
||||||
@ -464,9 +515,25 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
|||||||
0))
|
0))
|
||||||
{
|
{
|
||||||
/* The old guard area is too large. */
|
/* The old guard area is too large. */
|
||||||
|
|
||||||
|
#ifdef NEED_SEPARATE_REGISTER_STACK
|
||||||
|
char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
|
||||||
|
char *oldguard = mem + (((size - pd->guardsize) / 2) & ~pagesize_m1);
|
||||||
|
|
||||||
|
if (oldguard < guard
|
||||||
|
&& mprotect (oldguard, guard - oldguard,
|
||||||
|
PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
|
||||||
|
goto mprot_error;
|
||||||
|
|
||||||
|
if (mprotect (guard + guardsize,
|
||||||
|
oldguard + pd->guardsize - guard - guardsize,
|
||||||
|
PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
|
||||||
|
goto mprot_error;
|
||||||
|
#else
|
||||||
if (mprotect ((char *) mem + guardsize, pd->guardsize - guardsize,
|
if (mprotect ((char *) mem + guardsize, pd->guardsize - guardsize,
|
||||||
PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
|
PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
|
||||||
goto mprot_error;
|
goto mprot_error;
|
||||||
|
#endif
|
||||||
|
|
||||||
pd->guardsize = guardsize;
|
pd->guardsize = guardsize;
|
||||||
}
|
}
|
||||||
@ -477,18 +544,21 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
|||||||
|
|
||||||
#if TLS_TCB_AT_TP
|
#if TLS_TCB_AT_TP
|
||||||
/* The stack begins before the TCB and the static TLS block. */
|
/* The stack begins before the TCB and the static TLS block. */
|
||||||
*stack = ((char *) (pd + 1) - __static_tls_size);
|
stacktop = ((char *) (pd + 1) - __static_tls_size);
|
||||||
|
#elif TLS_DTV_AT_TP
|
||||||
|
stacktop = (char *) (pd - 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NEED_SEPARATE_REGISTER_STACK
|
||||||
|
*stack = pd->stackblock;
|
||||||
|
*stacksize = stacktop - *stack;
|
||||||
#else
|
#else
|
||||||
# error "Implement me"
|
*stack = stacktop;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is how the function is called. We do it this way to allow
|
|
||||||
other variants of the function to have more parameters. */
|
|
||||||
#define ALLOCATE_STACK(attr, pd) allocate_stack (attr, pd, &stackaddr)
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
internal_function
|
internal_function
|
||||||
@ -508,7 +578,7 @@ __deallocate_stack (struct pthread *pd)
|
|||||||
(void) queue_stack (pd);
|
(void) queue_stack (pd);
|
||||||
else
|
else
|
||||||
/* Free the memory associated with the ELF TLS. */
|
/* Free the memory associated with the ELF TLS. */
|
||||||
_dl_deallocate_tls (pd, false);
|
_dl_deallocate_tls (TLS_TPADJ (pd), false);
|
||||||
|
|
||||||
lll_unlock (stack_cache_lock);
|
lll_unlock (stack_cache_lock);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
having the definition remove these lines. */
|
having the definition remove these lines. */
|
||||||
#if defined __s390__
|
#if defined __s390__
|
||||||
# define __NR_set_tid_address 252
|
# define __NR_set_tid_address 252
|
||||||
|
#elif defined __ia64__
|
||||||
|
# define __NR_set_tid_address 1233
|
||||||
#else
|
#else
|
||||||
# define __NR_set_tid_address 258
|
# define __NR_set_tid_address 258
|
||||||
#endif
|
#endif
|
||||||
|
@ -344,10 +344,10 @@ __pthread_create_2_1 (newthread, attr, start_routine, arg)
|
|||||||
performed in 'get_cached_stack'. This way we avoid doing this if
|
performed in 'get_cached_stack'. This way we avoid doing this if
|
||||||
the stack freshly allocated with 'mmap'. */
|
the stack freshly allocated with 'mmap'. */
|
||||||
|
|
||||||
|
#ifdef TLS_TCB_AT_TP
|
||||||
/* Reference to the TCB itself. */
|
/* Reference to the TCB itself. */
|
||||||
pd->self = pd;
|
pd->self = pd;
|
||||||
|
|
||||||
#ifdef TLS_TCB_AT_TP
|
|
||||||
/* Self-reference for TLS. */
|
/* Self-reference for TLS. */
|
||||||
pd->tcb = pd;
|
pd->tcb = pd;
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,6 +34,10 @@
|
|||||||
# define TLS_VALUE pd
|
# define TLS_VALUE pd
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARCH_CLONE
|
||||||
|
# define ARCH_CLONE __clone
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
|
create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
|
||||||
@ -42,8 +46,9 @@ create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
|
|||||||
PREPARE_CREATE;
|
PREPARE_CREATE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TLS_TCB_AT_TP
|
||||||
assert (pd->tcb != NULL);
|
assert (pd->tcb != NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
|
if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
|
||||||
{
|
{
|
||||||
@ -62,7 +67,7 @@ create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
|
|||||||
lll_lock (pd->lock);
|
lll_lock (pd->lock);
|
||||||
|
|
||||||
/* Create the thread. */
|
/* Create the thread. */
|
||||||
if (__clone (start_thread_debug, STACK_VARIABLES_ARGS,
|
if (ARCH_CLONE (start_thread_debug, STACK_VARIABLES_ARGS,
|
||||||
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
|
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
|
||||||
CLONE_SETTLS | CLONE_PARENT_SETTID |
|
CLONE_SETTLS | CLONE_PARENT_SETTID |
|
||||||
CLONE_CHILD_CLEARTID | CLONE_DETACHED | 0,
|
CLONE_CHILD_CLEARTID | CLONE_DETACHED | 0,
|
||||||
@ -135,7 +140,7 @@ create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
|
|||||||
|
|
||||||
The termination signal is chosen to be zero which means no signal
|
The termination signal is chosen to be zero which means no signal
|
||||||
is sent. */
|
is sent. */
|
||||||
if (__clone (start_thread, STACK_VARIABLES_ARGS,
|
if (ARCH_CLONE (start_thread, STACK_VARIABLES_ARGS,
|
||||||
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
|
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
|
||||||
CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
|
CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
|
||||||
CLONE_DETACHED | 0, pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
|
CLONE_DETACHED | 0, pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
|
||||||
|
Reference in New Issue
Block a user