summaryrefslogtreecommitdiff
path: root/libpthread
diff options
context:
space:
mode:
Diffstat (limited to 'libpthread')
-rw-r--r--libpthread/linuxthreads/manager.c100
1 files changed, 88 insertions, 12 deletions
diff --git a/libpthread/linuxthreads/manager.c b/libpthread/linuxthreads/manager.c
index 78d5336d5..a00c9b13e 100644
--- a/libpthread/linuxthreads/manager.c
+++ b/libpthread/linuxthreads/manager.c
@@ -14,9 +14,12 @@
/* The "thread manager" thread: manages creation and termination of threads */
-/* mods for uClibc: getpwd and getpagesize are the syscalls */
+/* mods for uClibc */
#define __getpid getpid
#define __getpagesize getpagesize
+#define __sched_get_priority_max sched_get_priority_max
+#define __sched_getscheduler sched_getscheduler
+#define __sched_getparam sched_getparam
#include <features.h>
#define __USE_GNU
@@ -81,8 +84,13 @@ volatile pthread_descr __pthread_last_event;
static inline pthread_descr thread_segment(int seg)
{
+# ifdef _STACK_GROWS_UP
+ return (pthread_descr)(THREAD_STACK_START_ADDRESS + (seg - 1) * STACK_SIZE)
+ + 1;
+# else
return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE)
- 1;
+# endif
}
/* Flag set in signal handler to record child termination */
@@ -149,7 +157,7 @@ __pthread_manager(void *arg)
sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */
sigdelset(&manager_mask, SIGTRAP); /* for debugging purposes */
if (__pthread_threads_debug && __pthread_sig_debug > 0)
- sigdelset(&manager_mask, __pthread_sig_debug);
+ sigdelset(&manager_mask, __pthread_sig_debug);
sigprocmask(SIG_SETMASK, &manager_mask, NULL);
/* Raise our priority to match that of main thread */
__pthread_manager_adjust_prio(__pthread_main_thread->p_priority);
@@ -245,10 +253,12 @@ __pthread_manager(void *arg)
PDEBUG("got REQ_DEBUG\n");
/* Make gdb aware of new thread and gdb will restart the
new thread when it is ready to handle the new thread. */
- if (__pthread_threads_debug && __pthread_sig_debug > 0) {
- PDEBUG("about to call raise(__pthread_sig_debug)\n");
+ if (__pthread_threads_debug && __pthread_sig_debug > 0)
+ {
+ PDEBUG("about to call raise(__pthread_sig_debug)\n");
raise(__pthread_sig_debug);
}
+ break;
case REQ_KICK:
/* This is just a prod to get the manager to reap some
threads right away, avoiding a potential delay at shutdown. */
@@ -279,6 +289,7 @@ int __pthread_manager_event(void *arg)
}
/* Process creation */
+
static int
__attribute__ ((noreturn))
pthread_start_thread(void *arg)
@@ -286,10 +297,17 @@ pthread_start_thread(void *arg)
pthread_descr self = (pthread_descr) arg;
struct pthread_request request;
void * outcome;
+#if HP_TIMING_AVAIL
+ hp_timing_t tmpclock;
+#endif
/* Initialize special thread_self processing, if any. */
#ifdef INIT_THREAD_SELF
INIT_THREAD_SELF(self, self->p_nr);
#endif
+#if HP_TIMING_AVAIL
+ HP_TIMING_NOW (tmpclock);
+ THREAD_SETMEM (self, p_cpuclock_offset, tmpclock);
+#endif
PDEBUG("\n");
/* Make sure our pid field is initialized, just in case we get there
before our father has initialized it. */
@@ -363,12 +381,39 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
if (attr != NULL && attr->__stackaddr_set)
{
+#ifdef _STACK_GROWS_UP
/* The user provided a stack. */
+# ifdef USE_TLS
+ /* This value is not needed. */
+ new_thread = (pthread_descr) attr->__stackaddr;
+ new_thread_bottom = (char *) new_thread;
+# else
+ new_thread = (pthread_descr) attr->__stackaddr;
+ new_thread_bottom = (char *) (new_thread + 1);
+# endif
+ guardaddr = attr->__stackaddr + attr->__stacksize;
+ guardsize = 0;
+#else
+ /* The user provided a stack. For now we interpret the supplied
+ address as 1 + the highest addr. in the stack segment. If a
+ separate register stack is needed, we place it at the low end
+ of the segment, relying on the associated stacksize to
+ determine the low end of the segment. This differs from many
+ (but not all) other pthreads implementations. The intent is
+ that on machines with a single stack growing toward higher
+ addresses, stackaddr would be the lowest address in the stack
+ segment, so that it is consistently close to the initial sp
+ value. */
+# ifdef USE_TLS
+ new_thread = (pthread_descr) attr->__stackaddr;
+# else
new_thread =
(pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1;
+# endif
new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize;
guardaddr = NULL;
guardsize = 0;
+#endif
__pthread_nonstandard_stacks = 1;
}
else
@@ -493,7 +538,7 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
/* First check whether we have to change the policy and if yes, whether
we can do this. Normally this should be done by examining the
- return value of the sched_setscheduler call in pthread_start_thread
+ return value of the __sched_setscheduler call in pthread_start_thread
but this is hard to implement. FIXME */
if (attr != NULL && attr->__schedpolicy != SCHED_OTHER && geteuid () != 0)
return EPERM;
@@ -546,8 +591,8 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
sizeof (struct sched_param));
break;
case PTHREAD_INHERIT_SCHED:
- new_thread->p_start_args.schedpolicy = sched_getscheduler(father_pid);
- sched_getparam(father_pid, &new_thread->p_start_args.schedparam);
+ new_thread->p_start_args.schedpolicy = __sched_getscheduler(father_pid);
+ __sched_getparam(father_pid, &new_thread->p_start_args.schedparam);
break;
}
new_thread->p_priority =
@@ -588,17 +633,36 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
__pthread_lock(new_thread->p_lock, NULL);
/* We have to report this event. */
+#ifdef NEED_SEPARATE_REGISTER_STACK
+ /* Perhaps this version should be used on all platforms. But
+ this requires that __clone2 be uniformly supported
+ everywhere.
+
+ And there is some argument for changing the __clone2
+ interface to pass sp and bsp instead, making it more IA64
+ specific, but allowing stacks to grow outward from each
+ other, to get less paging and fewer mmaps. */
+ pid = __clone2(pthread_start_thread_event,
+ (void **)new_thread_bottom,
+ (char *)stack_addr - new_thread_bottom,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+ __pthread_sig_cancel, new_thread);
+#elif _STACK_GROWS_UP
+ pid = __clone(pthread_start_thread_event, (void *) new_thread_bottom,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+ __pthread_sig_cancel, new_thread);
+#else
pid = clone(pthread_start_thread_event, (void **) new_thread,
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
__pthread_sig_cancel, new_thread);
-
+#endif
saved_errno = errno;
if (pid != -1)
{
/* Now fill in the information about the new thread in
- the newly created thread's data structure. We cannot let
- the new thread do this since we don't know whether it was
- already scheduled when we send the event. */
+ the newly created thread's data structure. We cannot let
+ the new thread do this since we don't know whether it was
+ already scheduled when we send the event. */
new_thread->p_eventbuf.eventdata = new_thread;
new_thread->p_eventbuf.eventnum = TD_CREATE;
__pthread_last_event = new_thread;
@@ -619,9 +683,21 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
if (pid == 0)
{
PDEBUG("cloning new_thread = %p\n", new_thread);
+#ifdef NEED_SEPARATE_REGISTER_STACK
+ pid = __clone2(pthread_start_thread,
+ (void **)new_thread_bottom,
+ (char *)stack_addr - new_thread_bottom,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+ __pthread_sig_cancel, new_thread);
+#elif _STACK_GROWS_UP
+ pid = __clone(pthread_start_thread, (void *) new_thread_bottom,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+ __pthread_sig_cancel, new_thread);
+#else
pid = clone(pthread_start_thread, (void **) new_thread,
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
__pthread_sig_cancel, new_thread);
+#endif /* !NEED_SEPARATE_REGISTER_STACK */
saved_errno = errno;
}
/* Check if cloning succeeded */
@@ -922,7 +998,7 @@ void __pthread_manager_adjust_prio(int thread_prio)
if (thread_prio <= __pthread_manager_thread.p_priority) return;
param.sched_priority =
- thread_prio < sched_get_priority_max(SCHED_FIFO)
+ thread_prio < __sched_get_priority_max(SCHED_FIFO)
? thread_prio + 1 : thread_prio;
sched_setscheduler(__pthread_manager_thread.p_pid, SCHED_FIFO, &param);
__pthread_manager_thread.p_priority = thread_prio;