1 | /* Deallocate the kernel thread resources. Mach version. |
2 | Copyright (C) 2000-2022 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 |
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 | int self; |
39 | |
40 | kernel_thread = thread->kernel_thread; |
41 | |
42 | if (thread->stack) |
43 | { |
44 | stackaddr = thread->stackaddr; |
45 | stacksize = ((thread->guardsize + __vm_page_size - 1) |
46 | / __vm_page_size) * __vm_page_size + thread->stacksize; |
47 | } |
48 | else |
49 | { |
50 | stackaddr = NULL; |
51 | stacksize = 0; |
52 | } |
53 | |
54 | wakeup_port = thread->wakeupmsg.msgh_remote_port; |
55 | |
56 | self_ktid = __mach_thread_self (); |
57 | self = self_ktid == kernel_thread; |
58 | __mach_port_deallocate (__mach_task_self (), self_ktid); |
59 | |
60 | /* The kernel thread won't be there any more. */ |
61 | thread->kernel_thread = MACH_PORT_DEAD; |
62 | |
63 | /* Release thread resources. */ |
64 | __pthread_dealloc (thread); |
65 | |
66 | /* The wake up port (needed for locks in __pthread_dealloc) is now no longer |
67 | needed. */ |
68 | __mach_port_destroy (__mach_task_self (), wakeup_port); |
69 | |
70 | /* Each thread has its own reply port, allocated from MiG stub code calling |
71 | __mig_get_reply_port. Destroying it is a bit tricky because the calls |
72 | involved are also RPCs, causing the creation of a new reply port if |
73 | currently null. The __thread_terminate_release call is actually a one way |
74 | simple routine designed not to require a reply port. */ |
75 | reply_port = self ? __mig_get_reply_port () : MACH_PORT_NULL; |
76 | /* From here we shall not use a MIG reply port any more. */ |
77 | |
78 | /* Finally done with the thread structure (we still needed it to access the |
79 | reply port). */ |
80 | __pthread_dealloc_finish (thread); |
81 | |
82 | /* Terminate and release all that's left. */ |
83 | err = __thread_terminate_release (kernel_thread, mach_task_self (), |
84 | kernel_thread, reply_port, |
85 | (vm_address_t) stackaddr, stacksize); |
86 | |
87 | /* The kernel does not support it yet. Leak but at least terminate |
88 | correctly. */ |
89 | err = __thread_terminate (kernel_thread); |
90 | |
91 | /* We are out of luck. */ |
92 | assert_perror (err); |
93 | } |
94 | |