diff options
author | Neal H. Walfield <neal@gnu.org> | 2007-11-23 13:47:05 +0000 |
---|---|---|
committer | Thomas Schwinge <tschwinge@gnu.org> | 2009-04-07 23:10:46 +0200 |
commit | d438eed871f875dcf4676b83c3d3ae62f32f491a (patch) | |
tree | e61d5bfa021e57e153e7d1cd1b1ba4511774a9b0 | |
parent | 96d719679962ea3f765b3e3f23672af130de9c1d (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.am | 1 | ||||
-rw-r--r-- | pthread/pt-create.c | 2 | ||||
-rw-r--r-- | pthread/pt-internal.h | 4 | ||||
-rw-r--r-- | sysdeps/l4/hurd/ia32/pt-setup.c | 14 | ||||
-rw-r--r-- | sysdeps/l4/hurd/pt-startup.c | 30 | ||||
-rw-r--r-- | sysdeps/l4/hurd/pt-sysdep.h | 10 | ||||
-rw-r--r-- | sysdeps/l4/hurd/pt-thread-alloc.c | 74 | ||||
-rw-r--r-- | sysdeps/l4/hurd/pt-thread-halt.c | 87 | ||||
-rw-r--r-- | sysdeps/l4/hurd/pt-thread-start.c | 80 | ||||
-rw-r--r-- | sysdeps/l4/pt-block.c | 17 | ||||
-rw-r--r-- | sysdeps/l4/pt-stack-alloc.c | 1 | ||||
-rw-r--r-- | sysdeps/l4/pt-wakeup.c | 20 |
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)); } |