(root)/
glibc-2.38/
mach/
setup-thread.c
       1  /* Copyright (C) 1991-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <mach.h>
      19  #include <mach/setup-thread.h>
      20  #include <thread_state.h>
      21  #include <string.h>
      22  #include <mach/machine/vm_param.h>
      23  #include <ldsodefs.h>
      24  #include "sysdep.h"		/* Defines stack direction.  */
      25  
      26  #define	STACK_SIZE	(16 * 1024 * 1024) /* 16MB, arbitrary.  */
      27  
      28  static kern_return_t
      29  mach_setup_thread_impl (task_t task, thread_t thread, int is_call,
      30  			void *pc, vm_address_t *stack_base,
      31  			vm_size_t *stack_size)
      32  {
      33    kern_return_t error;
      34    struct machine_thread_state ts;
      35    mach_msg_type_number_t tssize = MACHINE_THREAD_STATE_COUNT;
      36    vm_address_t stack, stack_start;
      37    vm_size_t size;
      38    int anywhere;
      39  
      40    memset (&ts, 0, sizeof (ts));
      41  
      42    size = stack_size ? *stack_size ? : STACK_SIZE : STACK_SIZE;
      43    stack = stack_base ? *stack_base ? : 0 : 0;
      44    anywhere = !stack_base || !*stack_base;
      45  
      46    error = __vm_allocate (task, &stack, size + __vm_page_size, anywhere);
      47    if (error)
      48      return error;
      49  
      50    if (stack_size)
      51      *stack_size = size;
      52  
      53  #ifdef STACK_GROWTH_DOWN
      54    stack_start = stack + __vm_page_size;
      55  #elif defined (STACK_GROWTH_UP)
      56    stack_start = stack;
      57    stack += size;
      58  #else
      59    #error stack direction unknown
      60  #endif
      61    if (stack_base)
      62      *stack_base = stack_start;
      63  
      64    if (is_call)
      65      MACHINE_THREAD_STATE_SETUP_CALL (&ts, stack_start, size, pc);
      66    else
      67      {
      68        MACHINE_THREAD_STATE_SET_PC (&ts, pc);
      69        MACHINE_THREAD_STATE_SET_SP (&ts, stack_start, size);
      70      }
      71  
      72    /* Create the red zone.  */
      73    if (error = __vm_protect (task, stack, __vm_page_size, 0, VM_PROT_NONE))
      74      return error;
      75  
      76    return __thread_set_state (thread, MACHINE_NEW_THREAD_STATE_FLAVOR,
      77  			     (natural_t *) &ts, tssize);
      78  }
      79  
      80  /* Give THREAD a stack and set it to run at PC when resumed.
      81     If *STACK_SIZE is nonzero, that size of stack is allocated.
      82     If *STACK_BASE is nonzero, that stack location is used.
      83     If STACK_BASE is not null it is filled in with the chosen stack base.
      84     If STACK_SIZE is not null it is filled in with the chosen stack size.
      85     Regardless, an extra page of red zone is allocated off the end; this
      86     is not included in *STACK_SIZE.  */
      87  
      88  kern_return_t
      89  __mach_setup_thread (task_t task, thread_t thread, void *pc,
      90  		     vm_address_t *stack_base, vm_size_t *stack_size)
      91  {
      92    return mach_setup_thread_impl (task, thread, 0, pc, stack_base, stack_size);
      93  }
      94  
      95  weak_alias (__mach_setup_thread, mach_setup_thread)
      96  
      97  kern_return_t
      98  __mach_setup_thread_call (task_t task, thread_t thread, void *pc,
      99  			  vm_address_t *stack_base, vm_size_t *stack_size)
     100  {
     101    return mach_setup_thread_impl (task, thread, 1, pc, stack_base, stack_size);
     102  }
     103  
     104  /* Give THREAD a TLS area.  */
     105  kern_return_t
     106  __mach_setup_tls (thread_t thread)
     107  {
     108    tcbhead_t *tcb = _dl_allocate_tls (NULL);
     109    if (tcb == NULL)
     110      return KERN_RESOURCE_SHORTAGE;
     111  
     112    return _hurd_tls_new (thread, tcb);
     113  }
     114  
     115  weak_alias (__mach_setup_tls, mach_setup_tls)