-static int pthread_setschedparam_internal(pthread_t, mach_port_t, int, const struct sched_param *);
-extern pthread_t __bsdthread_create(void *(*func)(void *), void * func_arg, void * stack, pthread_t thread, unsigned int flags);
-extern int __bsdthread_register(void (*)(pthread_t, mach_port_t, void *(*)(void *), void *, size_t, unsigned int), void (*)(pthread_t, mach_port_t, void *, void *, int), int,void (*)(pthread_t, mach_port_t, void *(*)(void *), void *, size_t, unsigned int), int32_t *,__uint64_t);
-extern int __bsdthread_terminate(void * freeaddr, size_t freesize, mach_port_t kport, mach_port_t joinsem);
-extern __uint64_t __thread_selfid( void );
-extern int __pthread_canceled(int);
-extern int __pthread_kill(mach_port_t, int);
-
-extern int __workq_open(void);
-extern int __workq_kernreturn(int, void *, int, int);
-
-#if defined(__i386__) || defined(__x86_64__)
-static const mach_vm_address_t PTHREAD_STACK_HINT = 0xB0000000;
-#else
-#error no PTHREAD_STACK_HINT for this architecture
-#endif
-
-#if defined(__i386__) && defined(static_assert)
-// Check for regression of <rdar://problem/13249323>
-static_assert(offsetof(struct _pthread, err_no) == 68);
-#endif
-
-// Allocate a thread structure, stack and guard page.
-//
-// The thread structure may optionally be placed in the same allocation as the
-// stack, residing above the top of the stack. This cannot be done if a
-// custom stack address is provided.
-//
-// Similarly the guard page cannot be allocated if a custom stack address is
-// provided.
-//
-// The allocated thread structure is initialized with values that indicate how
-// it should be freed.
-
-static int
-_pthread_allocate(pthread_t *thread, const pthread_attr_t *attrs, void **stack)
-{
- int res;
- kern_return_t kr;
- pthread_t t = NULL;
- mach_vm_address_t allocaddr = PTHREAD_STACK_HINT;
- size_t allocsize = 0;
- size_t guardsize = 0;
- size_t stacksize = 0;
-
- PTHREAD_ASSERT(attrs->stacksize >= PTHREAD_STACK_MIN);
-
- *thread = NULL;
- *stack = NULL;
-
- // Allocate a pthread structure if necessary
-
- if (attrs->stackaddr != NULL) {
- PTHREAD_ASSERT(((uintptr_t)attrs->stackaddr % vm_page_size) == 0);
- *stack = attrs->stackaddr;
- allocsize = pthreadsize;
- } else {
- guardsize = attrs->guardsize;
- stacksize = attrs->stacksize;
- allocsize = stacksize + guardsize + pthreadsize;
- }
-
- kr = mach_vm_map(mach_task_self(),
- &allocaddr,
- allocsize,
- vm_page_size - 1,
- VM_MAKE_TAG(VM_MEMORY_STACK)| VM_FLAGS_ANYWHERE,
- MEMORY_OBJECT_NULL,
- 0,
- FALSE,
- VM_PROT_DEFAULT,
- VM_PROT_ALL,
- VM_INHERIT_DEFAULT);
-
- if (kr != KERN_SUCCESS) {
- kr = mach_vm_allocate(mach_task_self(),
- &allocaddr,
- allocsize,
- VM_MAKE_TAG(VM_MEMORY_STACK)| VM_FLAGS_ANYWHERE);
- }
-
- if (kr == KERN_SUCCESS) {
- // The stack grows down.
- // Set the guard page at the lowest address of the
- // newly allocated stack. Return the highest address
- // of the stack.
- if (guardsize) {
- (void)mach_vm_protect(mach_task_self(), allocaddr, guardsize, FALSE, VM_PROT_NONE);
- }
-
- // Thread structure resides at the top of the stack.
- t = (void *)(allocaddr + stacksize + guardsize);
- if (stacksize) {
- // Returns the top of the stack.
- *stack = t;
- }
- }
-
- if (t != NULL) {
- _pthread_struct_init(t, attrs, *stack, attrs->stacksize, 0);
- t->freeaddr = (void *)allocaddr;
- t->freesize = allocsize;
- *thread = t;
- res = 0;
- } else {
- res = EAGAIN;
- }
- return res;
-}
-
-static int
-_pthread_deallocate(pthread_t t)
-{
- // Don't free the main thread.
- if (t != &_thread) {
- kern_return_t ret;
- ret = mach_vm_deallocate(mach_task_self(), t->freeaddr, t->freesize);
- PTHREAD_ASSERT(ret == KERN_SUCCESS);
- }
- return 0;
-}
-
-// Terminates the thread if called from the currently running thread.
-PTHREAD_NORETURN
-static void
-_pthread_terminate(pthread_t t)
-{
- PTHREAD_ASSERT(t == pthread_self());
-
- uintptr_t freeaddr = (uintptr_t)t->freeaddr;
- size_t freesize = t->freesize;
-
- mach_port_t kport = _pthread_kernel_thread(t);
- semaphore_t joinsem = t->joiner_notify;
-
- _pthread_dealloc_reply_port(t);
-
- // If the pthread_t sticks around after the __bsdthread_terminate, we'll
- // need to free it later
-
- // After the call to __pthread_remove_thread, it is only safe to
- // dereference the pthread_t structure if EBUSY has been returned.
-
- bool destroy, should_exit;
- destroy = (__pthread_remove_thread(t, true, &should_exit) != EBUSY);
-
- if (t == &_thread) {
- // Don't free the main thread.
- freesize = 0;
- } else if (!destroy) {
- // We were told to keep the pthread_t structure around. In the common
- // case, the pthread structure itself is part of the allocation
- // described by freeaddr/freesize, in which case we need to split and
- // only deallocate the area below the pthread structure. In the event
- // of a custom stack, the freeaddr/size will be the pthread structure
- // itself, in which case we shouldn't free anything.
- if ((void*)t > t->freeaddr && (void*)t < t->freeaddr + t->freesize){
- freesize = trunc_page((uintptr_t)t - (uintptr_t)freeaddr);
- t->freeaddr += freesize;
- t->freesize -= freesize;
- } else {
- freesize = 0;
- }
- }
- if (freesize == 0) {
- freeaddr = 0;
- }
- _pthread_introspection_thread_terminate(t, freeaddr, freesize, destroy);
- if (should_exit) {
- exitf(0);
- }
-
- __bsdthread_terminate((void *)freeaddr, freesize, kport, joinsem);
- PTHREAD_ABORT("thread %p didn't terminate", t);
-}