1  /* Deallocate the kernel thread resources.  Mach version.
       2     Copyright (C) 2000-2023 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  }