summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--pthread/pt-alloc.c22
-rw-r--r--pthread/pt-create.c69
-rw-r--r--pthread/pt-dealloc.c5
-rw-r--r--pthread/pt-detach.c24
-rw-r--r--pthread/pt-exit.c35
-rw-r--r--pthread/pt-internal.h36
-rw-r--r--pthread/pt-join.c18
-rw-r--r--sysdeps/mach/hurd/pt-sigstate-destroy.c2
-rw-r--r--sysdeps/mach/hurd/pt-sigstate-init.c18
-rw-r--r--sysdeps/mach/hurd/pt-sysdep.c5
-rw-r--r--sysdeps/mach/hurd/pt-sysdep.h3
-rw-r--r--sysdeps/mach/pt-thread-alloc.c31
-rw-r--r--sysdeps/mach/pt-thread-dealloc.c3
-rw-r--r--sysdeps/mach/pt-thread-halt.c37
-rw-r--r--sysdeps/mach/pt-thread-start.c4
-rw-r--r--sysdeps/mach/pt-thread-terminate.c72
17 files changed, 194 insertions, 192 deletions
diff --git a/Makefile b/Makefile
index c57f1a0..61e59fc 100644
--- a/Makefile
+++ b/Makefile
@@ -121,7 +121,7 @@ libpthread-routines := pt-attr pt-attr-destroy pt-attr-getdetachstate \
pt-thread-alloc \
pt-thread-dealloc \
pt-thread-start \
- pt-thread-halt \
+ pt-thread-terminate \
pt-startup \
\
pt-getconcurrency pt-setconcurrency \
diff --git a/pthread/pt-alloc.c b/pthread/pt-alloc.c
index 604d376..af544c5 100644
--- a/pthread/pt-alloc.c
+++ b/pthread/pt-alloc.c
@@ -47,7 +47,7 @@ struct __pthread *__pthread_free_threads;
pthread_mutex_t __pthread_free_threads_lock;
static inline error_t
-initialize_pthread (struct __pthread *new, int recycling)
+initialize_pthread (struct __pthread *new)
{
error_t err;
@@ -55,6 +55,7 @@ initialize_pthread (struct __pthread *new, int recycling)
if (err)
return err;
+ new->nr_refs = 1;
new->cancel_lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
new->cancel_hook = NULL;
new->cancel_hook_arg = NULL;
@@ -62,14 +63,6 @@ initialize_pthread (struct __pthread *new, int recycling)
new->cancel_type = PTHREAD_CANCEL_DEFERRED;
new->cancel_pending = 0;
- if (recycling)
- /* Since we are recycling PTHREAD, we can assume certains things
- about PTHREAD's current state and save some cycles by not
- rewriting the memory. */
- return 0;
-
- new->stack = 0;
-
new->state_lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
new->state_cond = (pthread_cond_t) PTHREAD_COND_INITIALIZER;
@@ -117,22 +110,15 @@ __pthread_alloc (struct __pthread **pthread)
if (new)
{
- /* The thread may still be running. Make sure it is stopped.
- If this is the case, then the thread is either at the end of
- __pthread_dealloc or in __pthread_thread_halt. In both
- cases, we are interrupt it. */
- __pthread_thread_halt (new);
-
#ifdef ENABLE_TLS
if (new->tcb)
{
/* Drop old values */
_dl_deallocate_tls (new->tcb, 1);
- new->tcb = NULL;
}
#endif /* ENABLE_TLS */
- err = initialize_pthread (new, 1);
+ err = initialize_pthread (new);
if (! err)
*pthread = new;
return err;
@@ -143,7 +129,7 @@ __pthread_alloc (struct __pthread **pthread)
if (new == NULL)
return ENOMEM;
- err = initialize_pthread (new, 0);
+ err = initialize_pthread (new);
if (err)
{
free (new);
diff --git a/pthread/pt-create.c b/pthread/pt-create.c
index fd6800f..99d1b47 100644
--- a/pthread/pt-create.c
+++ b/pthread/pt-create.c
@@ -103,47 +103,30 @@ __pthread_create_internal (struct __pthread **thread,
pthread->state = (setup->detachstate == PTHREAD_CREATE_DETACHED
? PTHREAD_DETACHED : PTHREAD_JOINABLE);
- /* If the user supplied a stack, it is not our responsibility to
- setup a stack guard. */
if (setup->stackaddr)
- pthread->guardsize = 0;
- else
- pthread->guardsize = (setup->guardsize <= setup->stacksize
- ? setup->guardsize : setup->stacksize);
-
- /* Find a stack. There are several scenarios: if a detached thread
- kills itself, it has no way to deallocate its stack, thus it
- leaves PTHREAD->stack set to true. We try to reuse it here,
- however, if the user supplied a stack or changes the size,
- we cannot use the old one. Right now, we simply deallocate it. */
- if (pthread->stack)
{
- if ((setup->stackaddr && setup->stackaddr != pthread->stackaddr)
- || (setup->stacksize != pthread->stacksize))
- {
- __pthread_stack_dealloc (pthread->stackaddr,
- pthread->stacksize);
- pthread->stackaddr = setup->stackaddr;
- pthread->stacksize = setup->stacksize;
- }
+ pthread->stackaddr = setup->stackaddr;
+
+ /* If the user supplied a stack, it is not our responsibility to
+ setup a stack guard. */
+ pthread->guardsize = 0;
+ pthread->stack = 0;
}
else
{
- pthread->stacksize = setup->stacksize;
-
- if (setup->stackaddr)
- pthread->stackaddr = setup->stackaddr;
- else
- {
- err = __pthread_stack_alloc (&pthread->stackaddr,
- setup->stacksize);
- if (err)
- goto failed_stack_alloc;
-
- pthread->stack = 1;
- }
+ /* Allocate a stack. */
+ err = __pthread_stack_alloc (&pthread->stackaddr,
+ setup->stacksize);
+ if (err)
+ goto failed_stack_alloc;
+
+ pthread->guardsize = (setup->guardsize <= setup->stacksize
+ ? setup->guardsize : setup->stacksize);
+ pthread->stack = 1;
}
+ pthread->stacksize = setup->stacksize;
+
/* Allocate the kernel thread and other required resources. */
err = __pthread_thread_alloc (pthread);
if (err)
@@ -169,6 +152,10 @@ __pthread_create_internal (struct __pthread **thread,
if (err)
goto failed_sigstate;
+ /* If the new thread is joinable, add a reference for the caller. */
+ if (pthread->state == PTHREAD_JOINABLE)
+ pthread->nr_refs++;
+
/* Set the new thread's signal mask and set the pending signals to
empty. POSIX says: "The signal mask shall be inherited from the
creating thread. The set of signals pending for the new thread
@@ -216,6 +203,10 @@ __pthread_create_internal (struct __pthread **thread,
return 0;
failed_starting:
+ /* If joinable, a reference was added for the caller. */
+ if (pthread->state == PTHREAD_JOINABLE)
+ __pthread_dealloc (pthread);
+
__pthread_setid (pthread->thread, NULL);
__atomic_dec (&__pthread_total);
failed_sigstate:
@@ -227,10 +218,14 @@ __pthread_create_internal (struct __pthread **thread,
failed_thread_tls_alloc:
#endif /* ENABLE_TLS */
__pthread_thread_dealloc (pthread);
- __pthread_thread_halt (pthread);
+ __pthread_thread_terminate (pthread);
+
+ /* __pthread_thread_terminate has taken care of deallocating the stack and
+ the thread structure. */
+ goto failed;
failed_thread_alloc:
- __pthread_stack_dealloc (pthread->stackaddr, pthread->stacksize);
- pthread->stack = 0;
+ if (pthread->stack)
+ __pthread_stack_dealloc (pthread->stackaddr, pthread->stacksize);
failed_stack_alloc:
__pthread_dealloc (pthread);
failed:
diff --git a/pthread/pt-dealloc.c b/pthread/pt-dealloc.c
index 92fe1fd..e324800 100644
--- a/pthread/pt-dealloc.c
+++ b/pthread/pt-dealloc.c
@@ -23,6 +23,8 @@
#include <pt-internal.h>
+#include <bits/pt-atomic.h>
+
/* List of thread structures corresponding to free thread IDs. */
extern struct __pthread *__pthread_free_threads;
extern pthread_mutex_t __pthread_free_threads_lock;
@@ -34,6 +36,9 @@ __pthread_dealloc (struct __pthread *pthread)
{
assert (pthread->state != PTHREAD_TERMINATED);
+ if (! __atomic_dec_and_test (&pthread->nr_refs))
+ return;
+
/* Withdraw this thread from the thread ID lookup table. */
__pthread_setid (pthread->thread, NULL);
diff --git a/pthread/pt-detach.c b/pthread/pt-detach.c
index 4ed8d2c..3431f1b 100644
--- a/pthread/pt-detach.c
+++ b/pthread/pt-detach.c
@@ -50,30 +50,16 @@ pthread_detach (pthread_t thread)
consequences instead of blocking indefinitely. */
pthread_cond_broadcast (&pthread->state_cond);
__pthread_mutex_unlock (&pthread->state_lock);
+
+ __pthread_dealloc (pthread);
break;
case PTHREAD_EXITED:
- /* THREAD has already exited. Make sure that nobody can
- reference it anymore, and mark it as terminated. */
-
__pthread_mutex_unlock (&pthread->state_lock);
- /* Make sure the thread is not running before we remove its
- stack. (The only possibility is that it is in a call to
- __pthread_thread_halt itself, but that is enough to cause a
- sigsegv.) */
- __pthread_thread_halt (pthread);
-
- /* Destroy the stack, the kernel resources and the control
- block. */
- if (pthread->stack)
- {
- __pthread_stack_dealloc (pthread->stackaddr, pthread->stacksize);
- pthread->stack = 0;
- }
-
- __pthread_thread_dealloc (pthread);
-
+ /* THREAD has already exited. PTHREAD remained after the thread
+ exited in order to provide the exit status, but it turns out
+ it won't be needed. */
__pthread_dealloc (pthread);
break;
diff --git a/pthread/pt-exit.c b/pthread/pt-exit.c
index 8468b80..ea61732 100644
--- a/pthread/pt-exit.c
+++ b/pthread/pt-exit.c
@@ -48,12 +48,6 @@ __pthread_exit (void *status)
pthread_setcancelstate (oldstate, &oldstate);
- /* Destory any thread specific data. */
- __pthread_destroy_specific (self);
-
- /* Destroy any signal state. */
- __pthread_sigstate_destroy (self);
-
/* Decrease the number of threads. We use an atomic operation to
make sure that only the last thread calls `exit'. */
if (__atomic_dec_and_test (&__pthread_total))
@@ -77,15 +71,8 @@ __pthread_exit (void *status)
break;
case PTHREAD_DETACHED:
- /* Make sure that nobody can reference this thread anymore, and
- mark it as terminated. Our thread ID will immediately become
- available for re-use. For obvious reasons, we cannot
- deallocate our own stack and TLS. However, it will eventually be
- reused when this thread structure is recycled. */
__pthread_mutex_unlock (&self->state_lock);
- __pthread_dealloc (self);
-
break;
case PTHREAD_JOINABLE:
@@ -105,12 +92,22 @@ __pthread_exit (void *status)
break;
}
- /* Note that after this point the resources used by this thread can
- be freed at any moment if another thread joins or detaches us.
- This means that before freeing any resources, such a thread
- should make sure that this thread is really halted. */
-
- __pthread_thread_halt (self);
+ /* Destroy any thread specific data. */
+ __pthread_destroy_specific (self);
+
+ /* Destroy any signal state. */
+ __pthread_sigstate_destroy (self);
+
+ /* Kernel resources may be used to implement synchronization objects,
+ release them late. */
+ __pthread_thread_dealloc (self);
+
+ /* Self terminating requires TLS, so defer the release of the TCB until
+ the thread structure is reused. */
+
+ /* Terminate the kernel thread, release the stack and drop the
+ self reference. */
+ __pthread_thread_terminate (self);
/* NOTREACHED */
abort ();
diff --git a/pthread/pt-internal.h b/pthread/pt-internal.h
index aeac009..9e0bbe9 100644
--- a/pthread/pt-internal.h
+++ b/pthread/pt-internal.h
@@ -72,6 +72,12 @@ struct __pthread
/* Thread ID. */
pthread_t thread;
+ __atomic_t nr_refs; /* Detached threads have a self reference only,
+ while joinable threads have two references.
+ These are used to keep the structure valid at
+ thread destruction. Detaching/joining a thread
+ drops a reference. */
+
/* Cancellation. */
pthread_mutex_t cancel_lock; /* Protect cancel_xxx members. */
void (*cancel_hook)(void *); /* Called to unblock a thread blocking
@@ -208,12 +214,13 @@ extern int __pthread_create_internal (struct __pthread **__restrict pthread,
void *__restrict arg);
/* Allocate a new thread structure and a pthread thread ID (but not a
- kernel thread or a stack). */
+ kernel thread or a stack). THREAD has one reference. */
extern int __pthread_alloc (struct __pthread **thread);
/* Deallocate the thread structure. This is the dual of
- __pthread_alloc (N.B. it does not call __pthread_stack_alloc nor
- __pthread_thread_halt). */
+ __pthread_alloc (N.B. it does not call __pthread_stack_dealloc nor
+ __pthread_thread_terminate). THREAD loses one reference and is
+ released if the reference counter drops to 0. */
extern void __pthread_dealloc (struct __pthread *thread);
@@ -238,22 +245,23 @@ extern int __pthread_setup (struct __pthread *__restrict thread,
resources) for THREAD; it must not be placed on the run queue. */
extern int __pthread_thread_alloc (struct __pthread *thread);
-/* Deallocate any kernel resources associated with THREAD. The thread
- must not be running (that is, if __pthread_thread_start was called,
- __pthread_thread_halt must first be called). This function will
- never be called by a thread on itself. In the case that a thread
- exits, its thread structure will be cached and cleaned up
- later. */
+/* Deallocate any kernel resources associated with THREAD. */
extern void __pthread_thread_dealloc (struct __pthread *thread);
/* Start THREAD making it eligible to run. */
extern int __pthread_thread_start (struct __pthread *thread);
-/* Stop the kernel thread associated with THREAD. This function may
- be called by two threads in parallel. In particular, by the thread
- itself and another thread trying to join it. This function must be
- implemented such that this is safe. */
-extern void __pthread_thread_halt (struct __pthread *thread);
+/* Terminate the kernel thread associated with THREAD, and deallocate its
+ stack. In addition, THREAD loses one reference.
+
+ This function can be called by any thread, including the target thread.
+ Since some resources that are destroyed along the kernel thread are
+ stored in thread-local variables, the conditions required for this
+ function to behave correctly are a bit unusual : as long as the target
+ thread hasn't been started, any thread can terminate it, but once it
+ has started, no other thread can terminate it, so that thread-local
+ variables created by that thread are correctly released. */
+extern void __pthread_thread_terminate (struct __pthread *thread);
/* Called by a thread just before it calls the provided start
diff --git a/pthread/pt-join.c b/pthread/pt-join.c
index 417f433..122d130 100644
--- a/pthread/pt-join.c
+++ b/pthread/pt-join.c
@@ -50,27 +50,11 @@ pthread_join (pthread_t thread, void **status)
switch (pthread->state)
{
case PTHREAD_EXITED:
- __pthread_mutex_unlock (&pthread->state_lock);
-
/* THREAD has already exited. Salvage its exit status. */
if (status)
*status = pthread->status;
- /* Make sure the thread is not running before we remove its
- stack. (The only possibility is that it is in a call to
- __pthread_thread_halt itself, but that is enough to cause a
- sigsegv.) */
- __pthread_thread_halt (pthread);
-
- /* Destroy the stack, the kernel resources and the control
- block. */
- if (pthread->stack)
- {
- __pthread_stack_dealloc (pthread->stackaddr, pthread->stacksize);
- pthread->stack = 0;
- }
-
- __pthread_thread_dealloc (pthread);
+ __pthread_mutex_unlock (&pthread->state_lock);
__pthread_dealloc (pthread);
break;
diff --git a/sysdeps/mach/hurd/pt-sigstate-destroy.c b/sysdeps/mach/hurd/pt-sigstate-destroy.c
index 8e56c5c..d5e28d2 100644
--- a/sysdeps/mach/hurd/pt-sigstate-destroy.c
+++ b/sysdeps/mach/hurd/pt-sigstate-destroy.c
@@ -24,5 +24,5 @@
void
__pthread_sigstate_destroy (struct __pthread *thread)
{
- /* Nothing to do. */
+ _hurd_sigstate_delete (thread->kernel_thread);
}
diff --git a/sysdeps/mach/hurd/pt-sigstate-init.c b/sysdeps/mach/hurd/pt-sigstate-init.c
index dd56d90..500b4d4 100644
--- a/sysdeps/mach/hurd/pt-sigstate-init.c
+++ b/sysdeps/mach/hurd/pt-sigstate-init.c
@@ -23,6 +23,22 @@
error_t
__pthread_sigstate_init (struct __pthread *thread)
{
- /* Nothing to do. */
+ static int do_init_global;
+
+ /* Mark the thread as a global signal receiver so as to conform with
+ the pthread semantics. However, we must be careful. The first
+ pthread created is the main thread, during libpthread initialization.
+ We must not mark it, otherwise the sigprocmask call in
+ __pthread_create would try to access _hurd_global_sigstate,
+ which is not initialized yet. When glibc runs _hurdsig_init later
+ on, the message thread is created, which must not be marked either. */
+ if (do_init_global)
+ {
+ struct hurd_sigstate *ss = _hurd_thread_sigstate (thread->kernel_thread);
+ _hurd_sigstate_set_global_rcv (ss);
+ }
+ else if (__pthread_num_threads >= 2)
+ do_init_global = 1;
+
return 0;
}
diff --git a/sysdeps/mach/hurd/pt-sysdep.c b/sysdeps/mach/hurd/pt-sysdep.c
index 09f0dcb..fd71aba 100644
--- a/sysdeps/mach/hurd/pt-sysdep.c
+++ b/sysdeps/mach/hurd/pt-sysdep.c
@@ -65,6 +65,11 @@ init_routine (void)
err = __pthread_create_internal (&thread, 0, 0, 0);
assert_perror (err);
+ /* XXX The caller copies the command line arguments and the environment
+ to the new stack. Pretend it wasn't allocated so that it remains
+ valid if the main thread terminates. */
+ thread->stack = 0;
+
___pthread_self = thread;
/* Decrease the number of threads, to take into account that the
diff --git a/sysdeps/mach/hurd/pt-sysdep.h b/sysdeps/mach/hurd/pt-sysdep.h
index 89592f9..35912a3 100644
--- a/sysdeps/mach/hurd/pt-sysdep.h
+++ b/sysdeps/mach/hurd/pt-sysdep.h
@@ -30,8 +30,7 @@
#define PTHREAD_SYSDEP_MEMBERS \
thread_t kernel_thread; \
- mach_msg_header_t wakeupmsg; \
- int have_kernel_resources;
+ mach_msg_header_t wakeupmsg;
extern __thread struct __pthread *___pthread_self;
#define _pthread_self() \
diff --git a/sysdeps/mach/pt-thread-alloc.c b/sysdeps/mach/pt-thread-alloc.c
index 794f63e..77aa933 100644
--- a/sysdeps/mach/pt-thread-alloc.c
+++ b/sysdeps/mach/pt-thread-alloc.c
@@ -67,44 +67,29 @@ create_wakeupmsg (struct __pthread *thread)
int
__pthread_thread_alloc (struct __pthread *thread)
{
- if (thread->have_kernel_resources)
- return 0;
-
+ static int do_create;
error_t err;
err = create_wakeupmsg (thread);
if (err)
return err;
- /* If there are no pthreads in the system then the pthread library
- is bootstrapping and the main thread must create initialize
- itself. The thread itself is already running, it just has not
- pthread context. We want to reuse what it already has (including
- the kernel thread), however, we must determine which thread is
- the main thread.
-
- We cannot test if __pthread_total is one as we later decrement
- before creating the signal thread. Currently, we check if
- __pthread_num_threads--the number of allocated thread
- structures--is one. __pthread_alloc has already been called in
- __pthread_create_internal for us. This predicate could be improved,
- however, it is sufficient for now. */
- if (__pthread_num_threads == 1)
+ if (! do_create)
{
assert (__pthread_total == 0);
thread->kernel_thread = __mach_thread_self ();
- /* We implicitly hold a reference drop the one that we just
- acquired. */
- __mach_port_deallocate (__mach_task_self (), thread->kernel_thread);
+ do_create = 1;
}
else
{
err = __thread_create (__mach_task_self (), &thread->kernel_thread);
if (err)
- return EAGAIN;
+ {
+ __mach_port_destroy (__mach_task_self (),
+ thread->wakeupmsg.msgh_remote_port);
+ return EAGAIN;
+ }
}
- thread->have_kernel_resources = 1;
-
return 0;
}
diff --git a/sysdeps/mach/pt-thread-dealloc.c b/sysdeps/mach/pt-thread-dealloc.c
index 55d8c4d..e977c3f 100644
--- a/sysdeps/mach/pt-thread-dealloc.c
+++ b/sysdeps/mach/pt-thread-dealloc.c
@@ -24,8 +24,7 @@
#include <pt-internal.h>
/* Deallocate any kernel resources associated with THREAD except don't
- halt the thread itself. On return, the thread will be marked as
- dead and __pthread_halt will be called. */
+ terminate the thread itself. */
void
__pthread_thread_dealloc (struct __pthread *thread)
{
diff --git a/sysdeps/mach/pt-thread-halt.c b/sysdeps/mach/pt-thread-halt.c
deleted file mode 100644
index 973cde1..0000000
--- a/sysdeps/mach/pt-thread-halt.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Deallocate the kernel thread resources. Mach version.
- Copyright (C) 2000, 2002, 2005 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 <mach.h>
-
-#include <pt-internal.h>
-
-/* Stop the kernel thread associated with THREAD. If NEED_DEALLOC is
- true, the function must call __pthread_dealloc on THREAD.
-
- NB: The thread executing this function may be the thread which is
- being halted, thus the last action should be halting the thread
- itself. */
-void
-__pthread_thread_halt (struct __pthread *thread)
-{
- error_t err = __thread_terminate (thread->kernel_thread);
- assert_perror (err);
-}
diff --git a/sysdeps/mach/pt-thread-start.c b/sysdeps/mach/pt-thread-start.c
index 11b017f..df490ab 100644
--- a/sysdeps/mach/pt-thread-start.c
+++ b/sysdeps/mach/pt-thread-start.c
@@ -27,9 +27,10 @@
int
__pthread_thread_start (struct __pthread *thread)
{
+ static int do_start;
error_t err;
- if (__pthread_num_threads == 1)
+ if (! do_start)
{
/* The main thread is already running: do nothing. */
assert (__pthread_total == 1);
@@ -38,6 +39,7 @@ __pthread_thread_start (struct __pthread *thread)
__mach_port_deallocate (__mach_task_self (),
thread->kernel_thread);
ok; }));
+ do_start = 1;
}
else
{
diff --git a/sysdeps/mach/pt-thread-terminate.c b/sysdeps/mach/pt-thread-terminate.c
new file mode 100644
index 0000000..a89e505
--- /dev/null
+++ b/sysdeps/mach/pt-thread-terminate.c
@@ -0,0 +1,72 @@
+/* Deallocate the kernel thread resources. Mach version.
+ Copyright (C) 2000, 2002, 2005 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 <mach.h>
+
+#include <mach/mig_support.h>
+
+#include <pt-internal.h>
+
+/* Terminate the kernel thread associated with THREAD, and deallocate its
+ right reference and its stack. The function also drops a reference
+ on THREAD. */
+void
+__pthread_thread_terminate (struct __pthread *thread)
+{
+ thread_t kernel_thread, self_ktid;
+ mach_port_t reply_port;
+ void *stackaddr;
+ size_t stacksize;
+ error_t err;
+
+ kernel_thread = thread->kernel_thread;
+
+ if (thread->stack)
+ {
+ stackaddr = thread->stackaddr;
+ stacksize = thread->stacksize;
+ }
+ else
+ {
+ stackaddr = NULL;
+ stacksize = 0;
+ }
+
+ /* Each thread has its own reply port, allocated from MiG stub code calling
+ __mig_get_reply_port. Destroying it is a bit tricky because the calls
+ involved are also RPCs, causing the creation of a new reply port if
+ currently null. The __thread_terminate_release call is actually a one way
+ simple routine designed not to require a reply port. */
+ self_ktid = __mach_thread_self ();
+ reply_port = (self_ktid == kernel_thread)
+ ? __mig_get_reply_port ()
+ : MACH_PORT_NULL;
+ __mach_port_deallocate (__mach_task_self (), self_ktid);
+
+ /* Finally done with the thread structure. */
+ __pthread_dealloc (thread);
+
+ /* Terminate and release all that's left. */
+ err = __thread_terminate_release (kernel_thread, mach_task_self (),
+ kernel_thread, reply_port,
+ stackaddr, stacksize);
+ assert_perror (err);
+}