summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@gnu.org>2007-11-23 13:47:05 +0000
committerThomas Schwinge <tschwinge@gnu.org>2009-04-07 23:10:46 +0200
commitd438eed871f875dcf4676b83c3d3ae62f32f491a (patch)
treee61d5bfa021e57e153e7d1cd1b1ba4511774a9b0
parent96d719679962ea3f765b3e3f23672af130de9c1d (diff)
2007-11-23 Neal H. Walfield <neal@gnu.org>
* pthread/pt-internal.h (__pthread_startup): Add declaration. * pthread/pt-create.c (entry_point): Call __pthread_startup. * sysdeps/l4/hurd/pt-sysdep.h: Include <hurd/storage.h> and <sys/mman.h>. (PTHREAD_SYSDEP_MEMBERS): Add fields object, exception_handler_stack and exception_handler_sp. (__attribute__): Call munmap. * sysdeps/l4/hurd/ia32/pt-setup.c (__pthread_setup): Set up thread->exception_handler_sp. Don't set the user define handle here. * sysdeps/l4/hurd/pt-startup.c: New file. Do it here. * sysdeps/l4/hurd/pt-thread-alloc.c: New file. * sysdeps/l4/hurd/pt-thread-halt.c: New file. * sysdeps/l4/hurd/pt-thread-start.c: New file. * Makefile.am (libpthread_a_SOURCES): Add pt-startup.c. * sysdeps/l4/pt-block.c: Include <hurd/stddef.h>. (__pthread_block): Detect IPC failure. Add debugging output. * sysdeps/l4/pt-wakeup.c: Include <hurd/stddef.h>. (__pthread_wakeup): Detect IPC failure. Add debugging output.
-rw-r--r--Makefile.am1
-rw-r--r--pthread/pt-create.c2
-rw-r--r--pthread/pt-internal.h4
-rw-r--r--sysdeps/l4/hurd/ia32/pt-setup.c14
-rw-r--r--sysdeps/l4/hurd/pt-startup.c30
-rw-r--r--sysdeps/l4/hurd/pt-sysdep.h10
-rw-r--r--sysdeps/l4/hurd/pt-thread-alloc.c74
-rw-r--r--sysdeps/l4/hurd/pt-thread-halt.c87
-rw-r--r--sysdeps/l4/hurd/pt-thread-start.c80
-rw-r--r--sysdeps/l4/pt-block.c17
-rw-r--r--sysdeps/l4/pt-stack-alloc.c1
-rw-r--r--sysdeps/l4/pt-wakeup.c20
12 files changed, 330 insertions, 10 deletions
diff --git a/Makefile.am b/Makefile.am
index 9249d937..9698b88e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -110,6 +110,7 @@ libpthread_a_SOURCES = pt-attr.c pt-attr-destroy.c pt-attr-getdetachstate.c \
pt-thread-dealloc.c \
pt-thread-start.c \
pt-thread-halt.c \
+ pt-startup.c \
pt-getconcurrency.c pt-setconcurrency.c \
pt-block.c \
pt-timedblock.c \
diff --git a/pthread/pt-create.c b/pthread/pt-create.c
index 4f8d043f..5bb9f1f9 100644
--- a/pthread/pt-create.c
+++ b/pthread/pt-create.c
@@ -45,6 +45,8 @@ entry_point (void *(*start_routine)(void *), void *arg)
uselocale (LC_GLOBAL_LOCALE);
#endif
+ __pthread_startup ();
+
pthread_exit (start_routine (arg));
}
diff --git a/pthread/pt-internal.h b/pthread/pt-internal.h
index 0dd4e9a8..6d34be13 100644
--- a/pthread/pt-internal.h
+++ b/pthread/pt-internal.h
@@ -218,6 +218,10 @@ extern void __pthread_thread_halt (struct __pthread *thread,
int need_dealloc);
+/* Called by a thread just before it calls the provided start
+ routine. */
+extern void __pthread_startup (void);
+
/* Block THREAD. */
extern void __pthread_block (struct __pthread *thread);
diff --git a/sysdeps/l4/hurd/ia32/pt-setup.c b/sysdeps/l4/hurd/ia32/pt-setup.c
index e244dc16..a179bdfd 100644
--- a/sysdeps/l4/hurd/ia32/pt-setup.c
+++ b/sysdeps/l4/hurd/ia32/pt-setup.c
@@ -63,10 +63,14 @@ __pthread_setup (struct __pthread *thread,
thread->mcontext.pc = entry_point;
thread->mcontext.sp = stack_setup (thread, start_routine, arg);
- if (l4_same_threads (thread->threadid, l4_myself ()))
- l4_set_user_defined_handle ((l4_word_t) thread);
- else
- l4_set_user_defined_handle_of (thread->threadid,
- (l4_word_t) thread);
+
+ if (__pthread_num_threads != 1)
+ {
+ assert (! ADDR_IS_VOID (thread->exception_handler_stack.addr));
+ thread->exception_handler_sp
+ = ADDR_TO_PTR (addr_extend (thread->exception_handler_stack.addr,
+ 0, PAGESIZE_LOG2));
+ }
+
return 0;
}
diff --git a/sysdeps/l4/hurd/pt-startup.c b/sysdeps/l4/hurd/pt-startup.c
new file mode 100644
index 00000000..b6461de7
--- /dev/null
+++ b/sysdeps/l4/hurd/pt-startup.c
@@ -0,0 +1,30 @@
+/* Thread initialization. Hurd/L4 version.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <l4.h>
+#include <pt-internal.h>
+
+#include <hurd/exceptions.h>
+
+void
+__pthread_startup (void)
+{
+ struct __pthread *pthread = _pthread_self ();
+ pthread->threadid = l4_myself ();
+}
diff --git a/sysdeps/l4/hurd/pt-sysdep.h b/sysdeps/l4/hurd/pt-sysdep.h
index ca2c9015..1c51731c 100644
--- a/sysdeps/l4/hurd/pt-sysdep.h
+++ b/sysdeps/l4/hurd/pt-sysdep.h
@@ -1,5 +1,5 @@
/* Internal defenitions for pthreads library.
- Copyright (C) 2000, 2002, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2002, 2005, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -21,6 +21,8 @@
#define _PT_SYSDEP_H 1
#include <l4.h>
+#include <hurd/storage.h>
+#include <sys/mman.h>
/* XXX */
#define _POSIX_THREAD_THREADS_MAX 64
@@ -29,7 +31,10 @@
#define PTHREAD_STACK_DEFAULT (2 * 1024 * 1024)
#define PTHREAD_SYSDEP_MEMBERS \
+ struct storage object; \
l4_thread_id_t threadid; \
+ struct storage exception_handler_stack; \
+ l4_word_t exception_handler_sp; \
l4_word_t my_errno;
extern inline struct __pthread *
@@ -43,8 +48,7 @@ extern inline void
__attribute__((__always_inline__))
__pthread_stack_dealloc (void *stackaddr, size_t stacksize)
{
- /* XXX: can only implement this once we have a working memory manager. */
- return;
+ munmap (stackaddr, stacksize);
}
#endif /* pt-sysdep.h */
diff --git a/sysdeps/l4/hurd/pt-thread-alloc.c b/sysdeps/l4/hurd/pt-thread-alloc.c
new file mode 100644
index 00000000..2a421995
--- /dev/null
+++ b/sysdeps/l4/hurd/pt-thread-alloc.c
@@ -0,0 +1,74 @@
+/* Allocate kernel thread. Hurd/L4 version.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <hurd/startup.h>
+#include <hurd/storage.h>
+
+#include <pt-internal.h>
+
+extern struct hurd_startup_data *__hurd_startup_data;
+
+extern addr_t meta_data_activity;
+
+int
+__pthread_thread_alloc (struct __pthread *thread)
+{
+ /* The main thread is already running of course. */
+ if (__pthread_num_threads == 1)
+ {
+ thread->object.addr = __hurd_startup_data->thread;
+ /* If the main thread exits, then we wait. Thus, we don't need
+ the shadow cap. */
+ thread->object.cap = NULL;
+ thread->threadid = l4_myself ();
+ return 0;
+ }
+ else
+ {
+ struct storage storage;
+
+ /* We can't don't use mmap as when the exception thread starts
+ running and it accesses its stack, it will fault, which we
+ naturally cannot handle. */
+ storage = storage_alloc (ADDR_VOID, cap_page,
+ STORAGE_UNKNOWN, ADDR_VOID);
+ if (ADDR_IS_VOID (storage.addr))
+ return EAGAIN;
+
+ thread->exception_handler_stack = storage;
+
+
+ storage = storage_alloc (meta_data_activity, cap_thread,
+ /* Threads are rarely shortly lived. */
+ STORAGE_MEDIUM_LIVED, ADDR_VOID);
+ if (ADDR_IS_VOID (storage.addr))
+ {
+ storage_free (thread->exception_handler_stack.addr, false);
+ return EAGAIN;
+ }
+
+ thread->object = storage;
+ }
+
+ return 0;
+}
diff --git a/sysdeps/l4/hurd/pt-thread-halt.c b/sysdeps/l4/hurd/pt-thread-halt.c
new file mode 100644
index 00000000..c6ae76f5
--- /dev/null
+++ b/sysdeps/l4/hurd/pt-thread-halt.c
@@ -0,0 +1,87 @@
+/* Deallocate the kernel thread resources. L4/Hurd version.
+ Copyright (C) 2007 Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <pt-internal.h>
+
+/* If we try to deallocate our self, we will end up causing a
+ deadlock. Thus, when a thread tries to free itself, we add it
+ here. The next thread to free a thread will free it. */
+static struct storage saved_object;
+
+void
+__pthread_thread_halt (struct __pthread *thread, int need_dealloc)
+{
+ struct storage exception_handler_stack = thread->exception_handler_stack;
+ thread->exception_handler_stack.addr = ADDR_VOID;
+
+ struct storage object = thread->object;
+ l4_thread_id_t tid = thread->threadid;
+
+ if (need_dealloc)
+ __pthread_dealloc (thread);
+
+ if (! ADDR_IS_VOID (saved_object.addr))
+ {
+ storage_free (saved_object.addr, false);
+ saved_object.cap->type = cap_void;
+ saved_object.addr = ADDR_VOID;
+ }
+
+ /* Stop the exception handler thread. */
+ l4_word_t dummy = 0;
+ error_t err = rm_thread_exregs (ADDR_VOID, object.addr,
+ HURD_EXREGS_EXCEPTION_THREAD
+ | HURD_EXREGS_STOP | HURD_EXREGS_ABORT_IPC,
+ ADDR_VOID,
+ 0, (struct cap_addr_trans) CAP_ADDR_TRANS_VOID,
+ ADDR_VOID,
+ 0, 0, 0, 0,
+ ADDR_VOID, ADDR_VOID,
+ &dummy, &dummy, &dummy, &dummy);
+ if (err)
+ panic ("Error stopping exception thread.");
+
+ /* Free its stack. */
+ assert (! ADDR_IS_VOID (exception_handler_stack.addr));
+ storage_free (exception_handler_stack.addr, false);
+ exception_handler_stack.addr = ADDR_VOID;
+
+ if (tid == l4_myself ())
+ /* If we try to storage_free (storage.addr), we will freeze in the
+ middle. That's no good. Thus, we add ourself to the pool of
+ available objects. */
+ saved_object = object;
+ else
+ {
+ storage_free (object.addr, false);
+ object.cap->type = cap_void;
+ }
+
+ if (tid == l4_myself ())
+ {
+ l4_send_timeout (l4_myself (), L4_NEVER);
+ panic ("Failed to stop thread %x.%x!",
+ l4_thread_no (l4_myself ()), l4_version (l4_myself ()));
+ }
+ else
+ thread_stop (object.addr);
+}
diff --git a/sysdeps/l4/hurd/pt-thread-start.c b/sysdeps/l4/hurd/pt-thread-start.c
new file mode 100644
index 00000000..ae5dfa8c
--- /dev/null
+++ b/sysdeps/l4/hurd/pt-thread-start.c
@@ -0,0 +1,80 @@
+/* Start thread. L4 version.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <hurd/thread.h>
+#include <hurd/exceptions.h>
+
+#include <pt-internal.h>
+
+int
+__pthread_thread_start (struct __pthread *thread)
+{
+ error_t err;
+
+ if (__pthread_num_threads == 1)
+ /* The main thread is already running of course. */
+ {
+ assert (__pthread_total == 1);
+ assert (l4_is_thread_equal (l4_myself (), thread->threadid));
+ l4_set_user_defined_handle_of (hurd_exception_thread (l4_myself ()),
+ (l4_word_t) thread);
+ l4_set_user_defined_handle ((l4_word_t) thread);
+ }
+ else
+ {
+ struct cap_addr_trans addr_trans = CAP_ADDR_TRANS_VOID;
+
+ /* First, start the exception thread. */
+ l4_word_t dummy;
+ err = rm_thread_exregs (ADDR_VOID, thread->object.addr,
+ HURD_EXREGS_EXCEPTION_THREAD
+ | HURD_EXREGS_SET_SP_IP
+ | HURD_EXREGS_SET_USER_HANDLE
+ | HURD_EXREGS_START
+ | HURD_EXREGS_ABORT_IPC,
+ ADDR_VOID, 0, addr_trans, ADDR_VOID,
+ (l4_word_t) thread->exception_handler_sp,
+ (l4_word_t) exception_handler_loop, 0,
+ thread,
+ ADDR_VOID, ADDR_VOID,
+ &dummy, &dummy, &dummy, &dummy);
+ assert (err == 0);
+
+ err = rm_thread_exregs (ADDR_VOID, thread->object.addr,
+ HURD_EXREGS_SET_ASPACE
+ | HURD_EXREGS_SET_ACTIVITY
+ | HURD_EXREGS_SET_SP_IP
+ | HURD_EXREGS_SET_USER_HANDLE
+ | HURD_EXREGS_START
+ | HURD_EXREGS_ABORT_IPC,
+ ADDR (0, 0),
+ CAP_COPY_COPY_SOURCE_GUARD, addr_trans,
+ ADDR_VOID,
+ (l4_word_t) thread->mcontext.sp,
+ (l4_word_t) thread->mcontext.pc, 0,
+ thread,
+ ADDR_VOID, ADDR_VOID,
+ &dummy, &dummy, &dummy, &dummy);
+ assert (err == 0);
+ }
+ return 0;
+}
diff --git a/sysdeps/l4/pt-block.c b/sysdeps/l4/pt-block.c
index 933cc285..df3fe85b 100644
--- a/sysdeps/l4/pt-block.c
+++ b/sysdeps/l4/pt-block.c
@@ -21,9 +21,24 @@
#include <pt-internal.h>
+#include <hurd/stddef.h>
+
/* Block THREAD. */
void
__pthread_block (struct __pthread *thread)
{
- L4_Receive (L4_anylocalthread);
+ debug (5, "%x.%x blocking",
+ l4_thread_no (thread->threadid), l4_version (thread->threadid));
+
+ l4_msg_tag_t tag = l4_receive (l4_anythread);
+ if (l4_ipc_failed (tag))
+ {
+ int err = l4_error_code ();
+ debug (1, "%x.%x failed to block: %s (%d)",
+ l4_thread_no (l4_myself ()), l4_version (l4_myself ()),
+ l4_strerror (err), err);
+ }
+ else
+ debug (5, "%x.%x unblocked",
+ l4_thread_no (thread->threadid), l4_version (thread->threadid));
}
diff --git a/sysdeps/l4/pt-stack-alloc.c b/sysdeps/l4/pt-stack-alloc.c
index 2ede58fd..b7ec12b4 100644
--- a/sysdeps/l4/pt-stack-alloc.c
+++ b/sysdeps/l4/pt-stack-alloc.c
@@ -38,5 +38,6 @@ __pthread_stack_alloc (void **stackaddr, size_t stacksize)
return EAGAIN;
*stackaddr = buffer;
+
return 0;
}
diff --git a/sysdeps/l4/pt-wakeup.c b/sysdeps/l4/pt-wakeup.c
index 342a2204..7ecc938d 100644
--- a/sysdeps/l4/pt-wakeup.c
+++ b/sysdeps/l4/pt-wakeup.c
@@ -21,9 +21,27 @@
#include <pt-internal.h>
+#include <hurd/stddef.h>
+
/* Wakeup THREAD. */
void
__pthread_wakeup (struct __pthread *thread)
{
- l4_send (thread->threadid);
+ debug (5, "%x.%x waking %x.%x",
+ l4_thread_no (l4_myself ()), l4_version (l4_myself ()),
+ l4_thread_no (thread->threadid), l4_version (thread->threadid));
+
+ l4_msg_tag_t tag = l4_send (thread->threadid);
+ if (l4_ipc_failed (tag))
+ {
+ int err = l4_error_code ();
+ debug (1, "%x.%x failed to wake %x.%x: %s (%d)",
+ l4_thread_no (l4_myself ()), l4_version (l4_myself ()),
+ l4_thread_no (thread->threadid), l4_version (thread->threadid),
+ l4_strerror (err), err);
+ }
+ else
+ debug (5, "%x.%x woke %x.%x",
+ l4_thread_no (l4_myself ()), l4_version (l4_myself ()),
+ l4_thread_no (thread->threadid), l4_version (thread->threadid));
}