1 /* Deallocate the kernel thread resources.  Mach version.
2    Copyright (C) 2000-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library;  if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <assert.h>
20 #include <errno.h>
21 #include <mach.h>
22 
23 #include <mach/mig_support.h>
24 
25 #include <pt-internal.h>
26 
27 /* Terminate the kernel thread associated with THREAD, and deallocate its
28    right reference and its stack.  The function also drops a reference
29    on THREAD.  */
30 void
__pthread_thread_terminate(struct __pthread * thread)31 __pthread_thread_terminate (struct __pthread *thread)
32 {
33   thread_t kernel_thread, self_ktid;
34   mach_port_t wakeup_port, reply_port;
35   void *stackaddr;
36   size_t stacksize;
37   error_t err;
38 
39   kernel_thread = thread->kernel_thread;
40 
41   if (thread->stack)
42     {
43       stackaddr = thread->stackaddr;
44       stacksize = ((thread->guardsize + __vm_page_size - 1)
45 		   / __vm_page_size) * __vm_page_size + thread->stacksize;
46     }
47   else
48     {
49       stackaddr = NULL;
50       stacksize = 0;
51     }
52 
53   wakeup_port = thread->wakeupmsg.msgh_remote_port;
54 
55   /* Each thread has its own reply port, allocated from MiG stub code calling
56      __mig_get_reply_port.  Destroying it is a bit tricky because the calls
57      involved are also RPCs, causing the creation of a new reply port if
58      currently null. The __thread_terminate_release call is actually a one way
59      simple routine designed not to require a reply port.  */
60   self_ktid = __mach_thread_self ();
61   reply_port = (self_ktid == kernel_thread)
62       ? __mig_get_reply_port () : MACH_PORT_NULL;
63   __mach_port_deallocate (__mach_task_self (), self_ktid);
64 
65   /* Finally done with the thread structure.  */
66   __pthread_dealloc (thread);
67 
68   /* The wake up port is now no longer needed.  */
69   __mach_port_destroy (__mach_task_self (), wakeup_port);
70 
71   /* Terminate and release all that's left.  */
72   err = __thread_terminate_release (kernel_thread, mach_task_self (),
73 				    kernel_thread, reply_port,
74 				    (vm_address_t) stackaddr, stacksize);
75 
76   /* The kernel does not support it yet.  Leak but at least terminate
77      correctly.  */
78   err = __thread_terminate (kernel_thread);
79 
80   /* We are out of luck.  */
81   assert_perror (err);
82 }
83