Use psynch code from libpthread-416.60.2

This not only updates our psynch code, but it also makes it easier to maintain in the future by providing only the necessary glue in terms of XNU's own functions (primarily `msleep` and `wakeup`), without any additional modifications, and thus, it should more closely resemble XNU's behavior.
This commit is contained in:
Ariel Abreu 2020-11-16 13:26:55 -05:00
parent b8621b37b4
commit 1cbb1e2457
No known key found for this signature in database
GPG Key ID: ECF8C2B9E8AD3E6B
41 changed files with 5910 additions and 4570 deletions

View File

@ -396,6 +396,14 @@ OBJS_$(MIGDIR_REL)/osfmk/device = \
OBJS_$(MIGDIR_REL)/osfmk/UserNotification = \
$(MIGDIR_REL)/osfmk/UserNotification/UNDReplyServer.o
OBJS_dthread = \
dthread/kern_synch.o \
dthread/pthread_kext.o
CFLAGS_dthread = \
-DBUILDING_DTHREAD=1 \
-I$(BUILD_ROOT)/dthread/include
#
# darling/
#
@ -410,11 +418,8 @@ OBJS_darling = \
darling/kqueue.o \
darling/module.o \
darling/procs.o \
darling/psynch_support.o \
darling/pthread_kext.o \
darling/pthread_kill.o \
darling/task_registry.o \
darling/threads.o \
darling/traps.o \
darling/uthreads.o
@ -428,6 +433,7 @@ DARLING_MACH_ALL_OBJS = \
$(OBJS_libkern) \
$(OBJS_pexpert) \
$(OBJS_$(MIGDIR_REL)/osfmk) \
$(OBJS_dthread) \
$(OBJS_darling)
#

View File

@ -9,6 +9,7 @@
#include <darling/debug_print.h>
extern void kmeminit(void);
extern void pthread_init(void);
// XNU allocates these with zalloc/kalloc
// we can just define them as variables
@ -39,4 +40,7 @@ void bsd_init(void) {
bsd_init_kprintf("calling dkqueue_init\n");
dkqueue_init();
bsd_init_kprintf("calling pthread_init\n");
pthread_init();
};

View File

@ -8,8 +8,11 @@
#include <libkern/section_keywords.h>
#include <sys/proc.h>
#include <sys/proc_internal.h>
#include <sys/systm.h>
#include <duct/duct_post_xnu.h>
#include <darling/task_registry.h>
extern proc_t current_proc(void);
// NOTE(@facekapow): i copied this function over from `bsd/uxkern/ux_exception.c` from the old LKM code,
@ -156,3 +159,11 @@ filt_signalprocess(struct knote *kn, struct kevent_qos_s *kev)
return res;
}
// </copied>
void __pthread_testcancel(int presyscall) {
thread_t thread = current_thread();
if (darling_thread_canceled()) {
unix_syscall_return(EINTR);
}
};

View File

@ -7,6 +7,33 @@
// <copied from="xnu://6153.61.1/bsd/kern/kern_time.c">
void
microuptime(
struct timeval *tvp)
{
clock_sec_t tv_sec;
clock_usec_t tv_usec;
clock_get_system_microtime(&tv_sec, &tv_usec);
tvp->tv_sec = tv_sec;
tvp->tv_usec = tv_usec;
}
uint64_t
tvtoabstime(
struct timeval *tvp)
{
uint64_t result, usresult;
clock_interval_to_absolutetime_interval(
tvp->tv_sec, NSEC_PER_SEC, &result);
clock_interval_to_absolutetime_interval(
tvp->tv_usec, NSEC_PER_USEC, &usresult);
return result + usresult;
}
uint64_t
tstoabstime(struct timespec *ts)
{

View File

@ -158,11 +158,13 @@ proc_get_register(struct proc *p)
return p->p_lflag & P_LREGISTER;
}
#ifndef __DARLING__
static void
proc_set_register(struct proc *p)
{
proc_setregister(p);
}
#endif
static void*
uthread_get_uukwe(struct uthread *t)
@ -188,6 +190,7 @@ qos_main_thread_active(void)
return TRUE;
}
#ifndef __DARLING__
static int
proc_usynch_get_requested_thread_qos(struct uthread *uth)
{
@ -229,6 +232,7 @@ proc_usynch_thread_qos_remove_override_for_resource(task_t task,
return proc_thread_qos_remove_override(task, thread, tid, resource,
resource_type) == 0;
}
#endif
static wait_result_t
@ -384,11 +388,7 @@ bsdthread_terminate(struct proc *p, struct bsdthread_terminate_args *uap, int32_
workq_thread_terminate(p, get_bsdthread_info(th));
}
#endif
#ifdef __DARLING__
return pthread_functions->bsdthread_terminate(p, uap->stackaddr, uap->freesize, uap->thread_right_name, uap->signal, retval);
#else
return pthread_functions->bsdthread_terminate(p, uap->stackaddr, uap->freesize, uap->port, uap->sem, retval);
#endif
}
int
@ -515,8 +515,6 @@ thread_will_park_or_terminate(__unused thread_t thread)
static const struct pthread_callbacks_s pthread_callbacks = {
.version = PTHREAD_SHIMS_VERSION,
// our pthread shim isn't a kext; it's built as a part of the LKM, so it has full access to everything and doesn't need these
#ifndef __DARLING__
.config_thread_max = CONFIG_THREAD_MAX,
.get_task_threadmax = get_task_threadmax,
@ -530,15 +528,21 @@ static const struct pthread_callbacks_s pthread_callbacks = {
.proc_get_pthhash = proc_get_pthhash,
.proc_set_pthhash = proc_set_pthhash,
.proc_get_register = proc_get_register,
#ifndef __DARLING__
.proc_set_register = proc_set_register,
#endif
/* kernel IPI interfaces */
.ipc_port_copyout_send = ipc_port_copyout_send,
#ifndef __DARLING__
.task_get_ipcspace = get_task_ipcspace,
#endif
.vm_map_page_info = vm_map_page_info,
#ifndef __DARLING__
.thread_set_wq_state32 = thread_set_wq_state32,
#if !defined(__arm__)
.thread_set_wq_state64 = thread_set_wq_state64,
#endif
#endif
.uthread_get_uukwe = uthread_get_uukwe,
@ -558,7 +562,9 @@ static const struct pthread_callbacks_s pthread_callbacks = {
.mach_port_deallocate = mach_port_deallocate,
.semaphore_signal_internal_trap = semaphore_signal_internal_trap,
.current_map = _current_map,
#ifndef __DARLING__
.thread_create = thread_create,
#endif
.thread_resume = thread_resume,
.kevent_workq_internal = kevent_workq_internal,
@ -572,15 +578,23 @@ static const struct pthread_callbacks_s pthread_callbacks = {
.proc_get_mach_thread_self_tsd_offset = proc_get_mach_thread_self_tsd_offset,
.proc_set_mach_thread_self_tsd_offset = proc_set_mach_thread_self_tsd_offset,
#ifndef __DARLING__
.thread_set_tsd_base = thread_set_tsd_base,
#endif
#ifndef __DARLING__
.proc_usynch_get_requested_thread_qos = proc_usynch_get_requested_thread_qos,
#endif
.qos_main_thread_active = qos_main_thread_active,
#ifndef __DARLING__
.thread_set_voucher_name = thread_set_voucher_name,
#endif
#ifndef __DARLING__
.proc_usynch_thread_qos_add_override_for_resource = proc_usynch_thread_qos_add_override_for_resource,
.proc_usynch_thread_qos_remove_override_for_resource = proc_usynch_thread_qos_remove_override_for_resource,
#endif
.thread_set_tag = thread_set_tag,
.thread_get_tag = thread_get_tag,
@ -598,7 +612,6 @@ static const struct pthread_callbacks_s pthread_callbacks = {
.psynch_wait_cleanup = psynch_wait_cleanup,
.psynch_wait_wakeup = psynch_wait_wakeup,
.psynch_wait_update_owner = psynch_wait_update_owner,
#endif
};
pthread_callbacks_t pthread_kern = &pthread_callbacks;

View File

@ -237,9 +237,9 @@ proc_t current_proc_EXTERNAL(void);
#ifndef __DARLING__
extern int msleep(void *chan, lck_mtx_t *mtx, int pri, const char *wmesg, struct timespec * ts );
#endif
extern void wakeup(void *chan);
extern void wakeup_one(caddr_t chan);
#endif
/* proc kpis */
/* this routine returns the pid of the current process */

View File

@ -32,6 +32,7 @@
#include <sys/user.h>
#include <kern/thread_call.h>
#ifndef BUILDING_DTHREAD
struct ksyn_waitq_element {
#if __LP64__
char opaque[48];
@ -39,6 +40,7 @@ struct ksyn_waitq_element {
char opaque[32];
#endif
};
#endif
void workq_mark_exiting(struct proc *);
void workq_exit(struct proc *);

View File

@ -85,11 +85,7 @@ struct waitq_set;
#ifdef KERNEL
#ifdef BSD_KERNEL_PRIVATE
#ifdef __DARLING__
#include <darling/pthread_internal.h>
#else
#include <sys/pthread_internal.h> /* for uu_kwe entry */
#endif
#include <sys/eventvar.h>
#endif /* BSD_KERNEL_PRIVATE */
#ifdef __APPLE_API_PRIVATE

View File

@ -36,6 +36,9 @@
#define DARLING_MACH_API_BASE 0x1000
// we pass these directly to their BSD functions; the BSD functions have their own padding format (see sysproto.h)
#define DARLING_BSD_ARG(_type, _name) _type _name; char _ ## _name ## _padding[(sizeof(uint64_t) <= sizeof(_type) ? 0 : sizeof(uint64_t) - sizeof(_type))]
#pragma pack (push, 1)
enum { NR_get_api_version = DARLING_MACH_API_BASE,
@ -331,28 +334,28 @@ struct bsd_ioctl_args
struct bsdthread_terminate_args
{
uint64_t stackaddr;
uint32_t freesize;
unsigned int thread_right_name;
unsigned int signal;
DARLING_BSD_ARG(uint64_t, stackaddr);
DARLING_BSD_ARG(uint64_t, freesize);
DARLING_BSD_ARG(uint32_t, port);
DARLING_BSD_ARG(uint32_t, sem);
};
struct psynch_mutexwait_args
{
uint64_t mutex;
uint32_t mgen;
uint32_t ugen;
uint64_t tid;
uint32_t flags;
DARLING_BSD_ARG(uint64_t, mutex);
DARLING_BSD_ARG(uint32_t, mgen);
DARLING_BSD_ARG(uint32_t, ugen);
DARLING_BSD_ARG(uint64_t, tid);
DARLING_BSD_ARG(uint32_t, flags);
};
struct psynch_mutexdrop_args
{
uint64_t mutex;
uint32_t mgen;
uint32_t ugen;
uint64_t tid;
uint32_t flags;
DARLING_BSD_ARG(uint64_t, mutex);
DARLING_BSD_ARG(uint32_t, mgen);
DARLING_BSD_ARG(uint32_t, ugen);
DARLING_BSD_ARG(uint64_t, tid);
DARLING_BSD_ARG(uint32_t, flags);
};
struct pthread_kill_args
@ -363,48 +366,48 @@ struct pthread_kill_args
struct psynch_cvwait_args
{
uint64_t cv;
uint64_t cvlsgen;
uint32_t cvugen;
uint64_t mutex;
uint64_t mugen;
uint32_t flags;
int64_t sec;
uint32_t nsec;
DARLING_BSD_ARG(uint64_t, cv);
DARLING_BSD_ARG(uint64_t, cvlsgen);
DARLING_BSD_ARG(uint32_t, cvugen);
DARLING_BSD_ARG(uint64_t, mutex);
DARLING_BSD_ARG(uint64_t, mugen);
DARLING_BSD_ARG(uint32_t, flags);
DARLING_BSD_ARG(int64_t, sec);
DARLING_BSD_ARG(uint32_t, nsec);
};
struct psynch_cvsignal_args
{
uint64_t cv;
uint64_t cvlsgen;
uint32_t cvugen;
int thread_port;
uint64_t mutex;
uint64_t mugen;
uint64_t tid;
uint32_t flags;
DARLING_BSD_ARG(uint64_t, cv);
DARLING_BSD_ARG(uint64_t, cvlsgen);
DARLING_BSD_ARG(uint32_t, cvugen);
DARLING_BSD_ARG(int, thread_port);
DARLING_BSD_ARG(uint64_t, mutex);
DARLING_BSD_ARG(uint64_t, mugen);
DARLING_BSD_ARG(uint64_t, tid);
DARLING_BSD_ARG(uint32_t, flags);
};
struct psynch_cvbroad_args
{
uint64_t cv;
uint64_t cvlsgen;
uint64_t cvudgen;
uint32_t flags;
uint64_t mutex;
uint64_t mugen;
uint64_t tid;
DARLING_BSD_ARG(uint64_t, cv);
DARLING_BSD_ARG(uint64_t, cvlsgen);
DARLING_BSD_ARG(uint64_t, cvudgen);
DARLING_BSD_ARG(uint32_t, flags);
DARLING_BSD_ARG(uint64_t, mutex);
DARLING_BSD_ARG(uint64_t, mugen);
DARLING_BSD_ARG(uint64_t, tid);
};
struct psynch_cvclrprepost_args
{
uint64_t cv;
uint32_t cvgen;
uint32_t cvugen;
uint32_t cvsgen;
uint32_t prepocnt;
uint32_t preposeq;
uint32_t flags;
DARLING_BSD_ARG(uint64_t, cv);
DARLING_BSD_ARG(uint32_t, cvgen);
DARLING_BSD_ARG(uint32_t, cvugen);
DARLING_BSD_ARG(uint32_t, cvsgen);
DARLING_BSD_ARG(uint32_t, prepocnt);
DARLING_BSD_ARG(uint32_t, preposeq);
DARLING_BSD_ARG(uint32_t, flags);
};
struct mk_timer_arm_args
@ -453,29 +456,29 @@ struct kernel_printk_args
struct psynch_rw_rdlock_args
{
uint64_t rwlock;
uint32_t lgenval;
uint32_t ugenval;
uint32_t rw_wc;
int flags;
DARLING_BSD_ARG(uint64_t, rwlock);
DARLING_BSD_ARG(uint32_t, lgenval);
DARLING_BSD_ARG(uint32_t, ugenval);
DARLING_BSD_ARG(uint32_t, rw_wc);
DARLING_BSD_ARG(int, flags);
};
struct psynch_rw_wrlock_args
{
uint64_t rwlock;
uint32_t lgenval;
uint32_t ugenval;
uint32_t rw_wc;
int flags;
DARLING_BSD_ARG(uint64_t, rwlock);
DARLING_BSD_ARG(uint32_t, lgenval);
DARLING_BSD_ARG(uint32_t, ugenval);
DARLING_BSD_ARG(uint32_t, rw_wc);
DARLING_BSD_ARG(int, flags);
};
struct psynch_rw_unlock_args
{
uint64_t rwlock;
uint32_t lgenval;
uint32_t ugenval;
uint32_t rw_wc;
int flags;
DARLING_BSD_ARG(uint64_t, rwlock);
DARLING_BSD_ARG(uint32_t, lgenval);
DARLING_BSD_ARG(uint32_t, ugenval);
DARLING_BSD_ARG(uint32_t, rw_wc);
DARLING_BSD_ARG(int, flags);
};
struct mach_vm_allocate_args
@ -582,9 +585,6 @@ struct set_thread_handles_args
unsigned long long dispatch_qaddr;
};
// we pass these directly to their BSD functions; the BSD fucntions have their own padding format (see sysproto.h)
#define DARLING_BSD_ARG(_type, _name) _type _name; char _ ## _name ## _padding[(sizeof(uint64_t) <= sizeof(_type) ? 0 : sizeof(uint64_t) - sizeof(_type))]
struct kevent_args {
DARLING_BSD_ARG(int, fd);
DARLING_BSD_ARG(uint64_t, changelist);

View File

@ -20,7 +20,6 @@
#include <libkern/OSAtomic.h>
#include <duct/duct_post_xnu.h>
#include "pthread_internal.h"
#include "kqueue.h"
extern void pth_proc_hashinit(proc_t p);

File diff suppressed because it is too large Load Diff

View File

@ -1,159 +0,0 @@
/**
* a brief rationale on why we need this
* ---
*
* so, sometime around the release of macOS 10.9 (with xnu-2422.1.72),
* Apple decided to stuff pthread support in-kernel into a kext (pthread.kext)
*
* we already have most of the functions implemented in `psync_support.c`, this file just takes care of the rest
* and the necessary plumbing for XNU's `pthread_shims.c` so that we can use XNU's own interface as much as possible
*
* ignore the following; i've actually decided against building `pthread_workqueue.c`
* (turns out its usage in `turnstile.c` only matters when workqueues are already being used for something else)
*
* > up until recently, we didn't really build any parts of XNU that needed it
* >
* > however, the new turnstile subsystem requires functions that are implemented in `pthread_workqueue.c`,
* > and it's relatively simple to build that file by adding support for the functions it calls out to
* > (and easy enough that it's better than stubbing them)
*
* so like i said, that reason is no longer valid. i decided to leave this in anyways because i had already completely
* added it in and it works so ¯\_()_/¯
*/
#include <duct/duct.h>
#include <duct/duct_pre_xnu.h>
#include <kern/kern_types.h>
#include <sys/proc.h>
#include <sys/pthread_shims.h>
#include <duct/duct_post_xnu.h>
#include "pthread_kext.h"
#include "pthread_internal.h"
#include "psynch_support.h"
#include "syscall_args.h"
/**
*
* `pthread_shims.c` plumbing
*
*/
static const struct pthread_functions_s _darling_pthread_functions = {
.pthread_init = darling_pthread_init,
.pth_proc_hashinit = darling_pth_proc_hashinit,
.pth_proc_hashdelete = darling_pth_proc_hashdelete,
.bsdthread_create = darling_bsdthread_create,
.bsdthread_register = darling_bsdthread_register,
.bsdthread_terminate = darling_bsdthread_terminate,
.thread_selfid = darling_thread_selfid,
.psynch_mutexwait = darling_psynch_mutexwait,
.psynch_mutexdrop = darling_psynch_mutexdrop,
.psynch_cvbroad = darling_psynch_cvbroad,
.psynch_cvsignal = darling_psynch_cvsignal,
.psynch_cvwait = darling_psynch_cvwait,
.psynch_cvclrprepost = darling_psynch_cvclrprepost,
.psynch_rw_longrdlock = darling_psynch_rw_longrdlock,
.psynch_rw_rdlock = darling_psynch_rw_rdlock,
.psynch_rw_unlock = darling_psynch_rw_unlock,
.psynch_rw_wrlock = darling_psynch_rw_wrlock,
.psynch_rw_yieldwrlock = darling_psynch_rw_yieldwrlock,
.pthread_find_owner = darling_pthread_find_owner,
.pthread_get_thread_kwq = darling_pthread_get_thread_kwq,
.workq_create_threadstack = darling_workq_create_threadstack,
.workq_destroy_threadstack = darling_workq_destroy_threadstack,
.workq_setup_thread = darling_workq_setup_thread,
.workq_handle_stack_events = darling_workq_handle_stack_events,
.workq_markfree_threadstack = darling_workq_markfree_threadstack,
};
// called by our kernel module during initialization
//
// this is different from `darling_pthread_init`, because this function is the one that sets up
// the pthread kext plumbing, while the `pthread_init` is only called by some BSD code after the kext has already been set up
void darling_pthread_kext_init(void) {
// we don't really need this, since we're not actually a kext and we have full access to the whole kernel,
// but `pthread_shims.c` won't take "no" for an answer (it'll panic if we give it `NULL`)
pthread_callbacks_t callbacks = NULL;
pthread_kext_register(&_darling_pthread_functions, &callbacks);
psynch_init();
};
// called by our kernel module when it's going to be unloaded
void darling_pthred_kext_exit(void) {
psynch_exit();
};
/**
* stubbed functions
*/
// called by BSD code through `pthread_init` in `pthread_shims.c`
void darling_pthread_init(void) {
// we don't really need this, but it has to exist
};
/**
* nobody really needs this next set of functions right now,
* so we can just stub them for now
*/
int darling_bsdthread_create(proc_t p, user_addr_t user_func, user_addr_t user_funcarg, user_addr_t user_stack, user_addr_t user_pthread, uint32_t flags, user_addr_t* retval) {
return ENOTSUP;
};
int darling_bsdthread_register(proc_t p, user_addr_t threadstart, user_addr_t wqthread, int pthsize, user_addr_t dummy_value, user_addr_t targetconc_ptr, uint64_t dispatchqueue_offset, int32_t* retval) {
return ENOTSUP;
};
int darling_bsdthread_terminate(proc_t p, user_addr_t stackaddr, size_t size, uint32_t kthport, uint32_t sem, int32_t* retval) {
return ENOTSUP;
};
int darling_thread_selfid(proc_t p, uint64_t* retval) {
return ENOTSUP;
};
int darling_bsdthread_register2(proc_t p, user_addr_t threadstart, user_addr_t wqthread, uint32_t flags, user_addr_t stack_addr_hint, user_addr_t targetconc_ptr, uint32_t dispatchqueue_offset, uint32_t tsd_offset, int32_t* retval) {
return ENOTSUP;
};
void darling_pthread_find_owner(thread_t thread, struct stackshot_thread_waitinfo *waitinfo) {
};
void* darling_pthread_get_thread_kwq(thread_t thread) {
return NULL;
};
/**
* now these are actually needed by `pthread_workqueue.c`
*/
int darling_workq_handle_stack_events(proc_t p, thread_t th, vm_map_t map, user_addr_t stackaddr, mach_port_name_t kport, user_addr_t events, int nevents, int upcall_flags) {
return ENOTSUP;
};
int darling_workq_create_threadstack(proc_t p, vm_map_t vmap, mach_vm_offset_t* out_addr) {
return ENOTSUP;
};
int darling_workq_destroy_threadstack(proc_t p, vm_map_t vmap, mach_vm_offset_t stackaddr) {
return ENOTSUP;
};
void darling_workq_setup_thread(proc_t p, thread_t th, vm_map_t map, user_addr_t stackaddr, mach_port_name_t kport, int th_qos, int setup_flags, int upcall_flags) {
};
void darling_workq_markfree_threadstack(proc_t p, thread_t th, vm_map_t map, user_addr_t stackaddr) {
};

View File

@ -1,51 +0,0 @@
#ifndef _DARLING_LKM_PTHREAD_KEXT_H_
#define _DARLING_LKM_PTHREAD_KEXT_H_
#include <duct/duct.h>
#include <duct/duct_pre_xnu.h>
#include <sys/proc.h>
#include <kern/thread.h>
#include <vm/vm_map.h>
#include <duct/duct_post_xnu.h>
#include "pthread_internal.h"
void darling_pthread_kext_init(void);
void darling_pthred_kext_exit(void);
extern void darling_pthread_init(void);
extern void darling_pth_proc_hashinit(proc_t p);
extern void darling_pth_proc_hashdelete(proc_t p);
extern int darling_bsdthread_create(proc_t p, user_addr_t user_func, user_addr_t user_funcarg, user_addr_t user_stack, user_addr_t user_pthread, uint32_t flags, user_addr_t* retval);
extern int darling_bsdthread_register(proc_t p, user_addr_t threadstart, user_addr_t wqthread, int pthsize, user_addr_t dummy_value, user_addr_t targetconc_ptr, uint64_t dispatchqueue_offset, int32_t* retval);
extern int darling_bsdthread_terminate(proc_t p, user_addr_t stackaddr, size_t size, uint32_t kthport, uint32_t sem, int32_t* retval);
extern int darling_thread_selfid(proc_t p, uint64_t* retval);
extern int darling_psynch_mutexwait(proc_t p, user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint64_t tid, uint32_t flags, uint32_t* retval);
extern int darling_psynch_mutexdrop(proc_t p, user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint64_t tid, uint32_t flags, uint32_t* retval);
extern int darling_psynch_cvbroad(proc_t p, user_addr_t cv, uint64_t cvlsgen, uint64_t cvudgen, uint32_t flags, user_addr_t mutex, uint64_t mugen, uint64_t tid, uint32_t* retval);
extern int darling_psynch_cvsignal(proc_t p, user_addr_t cv, uint64_t cvlsgen, uint32_t cvugen, int thread_port, user_addr_t mutex, uint64_t mugen, uint64_t tid, uint32_t flags, uint32_t* retval);
extern int darling_psynch_cvwait(proc_t p, user_addr_t cv, uint64_t cvlsgen, uint32_t cvugen, user_addr_t mutex, uint64_t mugen, uint32_t flags, int64_t sec, uint32_t nsec, uint32_t* retval);
extern int darling_psynch_cvclrprepost(proc_t p, user_addr_t cv, uint32_t cvgen, uint32_t cvugen, uint32_t cvsgen, uint32_t prepocnt, uint32_t preposeq, uint32_t flags, int* retval);
extern int darling_psynch_rw_longrdlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t* retval);
extern int darling_psynch_rw_rdlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t* retval);
extern int darling_psynch_rw_unlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t* retval);
extern int darling_psynch_rw_wrlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t* retval);
extern int darling_psynch_rw_yieldwrlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t* retval);
extern int darling_bsdthread_register2(proc_t p, user_addr_t threadstart, user_addr_t wqthread, uint32_t flags, user_addr_t stack_addr_hint, user_addr_t targetconc_ptr, uint32_t dispatchqueue_offset, uint32_t tsd_offset, int32_t* retval);
extern void darling_pthread_find_owner(thread_t thread, struct stackshot_thread_waitinfo *waitinfo);
extern void* darling_pthread_get_thread_kwq(thread_t thread);
extern int darling_workq_handle_stack_events(proc_t p, thread_t th, vm_map_t map, user_addr_t stackaddr, mach_port_name_t kport, user_addr_t events, int nevents, int upcall_flags);
extern int darling_workq_create_threadstack(proc_t p, vm_map_t vmap, mach_vm_offset_t* out_addr);
extern int darling_workq_destroy_threadstack(proc_t p, vm_map_t vmap, mach_vm_offset_t stackaddr);
extern void darling_workq_setup_thread(proc_t p, thread_t th, vm_map_t map, user_addr_t stackaddr, mach_port_name_t kport, int th_qos, int setup_flags, int upcall_flags);
extern void darling_workq_markfree_threadstack(proc_t p, thread_t, vm_map_t map, user_addr_t stackaddr);
#endif // _DARLING_LKM_PTHREAD_KEXT_H_

View File

@ -66,7 +66,7 @@
#include "commpage.h"
#include "foreign_mm.h"
#include "continuation.h"
#include "pthread_kext.h"
#include <dthread/pthread_kext.h>
#include "procs.h"
#include "kqueue.h"
@ -217,8 +217,8 @@ static int mach_init(void)
int err = 0;
darling_task_init();
darling_xnu_init();
darling_pthread_kext_init();
darling_xnu_init();
darling_procs_init();
commpage32 = commpage_setup(false);
@ -246,8 +246,8 @@ fail:
static void mach_exit(void)
{
darling_procs_exit();
darling_pthred_kext_exit();
darling_xnu_deinit();
darling_pthread_kext_exit();
misc_deregister(&mach_dev);
printk(KERN_INFO "Darling Mach: kernel emulation unloaded\n");

4
dthread/README.md Normal file
View File

@ -0,0 +1,4 @@
# dthread
This directory is home to Darling's port of Apple's pthread kext. The original source is from libpthread-416.60.2
The goal here is to have Apple's pthread code work with our LKM with as few modifications as possible.

View File

@ -0,0 +1 @@
../../kern_internal.h

View File

@ -0,0 +1 @@
../../kern_trace.h

View File

@ -0,0 +1 @@
../../synch_internal.h

View File

@ -0,0 +1 @@
../../workqueue_internal.h

View File

@ -0,0 +1,225 @@
/*
* Copyright (c) 2013-2014 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _QOS_PRIVATE_H
#define _QOS_PRIVATE_H
#include <pthread/qos.h>
#include <pthread/priority_private.h>
#include <sys/qos.h> /* qos_class_t */
#include <sys/qos_private.h>
#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
// allow __DARWIN_C_LEVEL to turn off the use of mach_port_t
#include <mach/port.h>
#endif
// redeffed here to avoid leaving __QOS_ENUM defined in the public header
#define __QOS_ENUM(name, type, ...) enum { __VA_ARGS__ }; typedef type name##_t
#define __QOS_AVAILABLE_10_10
#define __QOS_AVAILABLE_10_11
#define __QOS_AVAILABLE_10_12
#ifdef __DARLING__
// i'm pretty sure Apple should be defining this too
#define __QOS_AVAILABLE_10_15_1
#endif
#if defined(__has_feature) && defined(__has_extension)
#if __has_feature(objc_fixed_enum) || __has_extension(cxx_strong_enums)
#undef __QOS_ENUM
#define __QOS_ENUM(name, type, ...) typedef enum : type { __VA_ARGS__ } name##_t
#endif
#if __has_feature(enumerator_attributes)
#undef __QOS_AVAILABLE_10_10
#define __QOS_AVAILABLE_10_10 __API_AVAILABLE(macos(10.10), ios(8.0))
#undef __QOS_AVAILABLE_10_11
#define __QOS_AVAILABLE_10_11 __API_AVAILABLE(macos(10.11), ios(9.0), tvos(9.0), watchos(2.0))
#undef __QOS_AVAILABLE_10_12
#define __QOS_AVAILABLE_10_12 __API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0))
#undef __QOS_AVAILABLE_10_15_1
#define __QOS_AVAILABLE_10_15_1 __API_AVAILABLE(macos(10.15.1), ios(13.2), tvos(13.2), watchos(6.2))
#endif
#endif
// This enum matches workq_set_self_flags in
// xnu's workqueue_internal.h.
__QOS_ENUM(_pthread_set_flags, unsigned int,
_PTHREAD_SET_SELF_QOS_FLAG __QOS_AVAILABLE_10_10 = 0x1,
_PTHREAD_SET_SELF_VOUCHER_FLAG __QOS_AVAILABLE_10_10 = 0x2,
_PTHREAD_SET_SELF_FIXEDPRIORITY_FLAG __QOS_AVAILABLE_10_11 = 0x4,
_PTHREAD_SET_SELF_TIMESHARE_FLAG __QOS_AVAILABLE_10_11 = 0x8,
_PTHREAD_SET_SELF_WQ_KEVENT_UNBIND __QOS_AVAILABLE_10_12 = 0x10,
_PTHREAD_SET_SELF_ALTERNATE_AMX __QOS_AVAILABLE_10_15_1 = 0x20,
);
#undef __QOS_ENUM
#undef __QOS_AVAILABLE_10_10
#undef __QOS_AVAILABLE_10_11
#undef __QOS_AVAILABLE_10_12
#ifndef KERNEL
__BEGIN_DECLS
/*!
* @function pthread_set_qos_class_np
*
* @abstract
* Sets the requested QOS class and relative priority of the current thread.
*
* @discussion
* The QOS class and relative priority represent an overall combination of
* system quality of service attributes on a thread.
*
* Subsequent calls to interfaces such as pthread_setschedparam() that are
* incompatible or in conflict with the QOS class system will unset the QOS
* class requested with this interface and pthread_get_qos_class_np() will
* return QOS_CLASS_UNSPECIFIED thereafter. A thread so modified is permanently
* opted-out of the QOS class system and calls to this function to request a QOS
* class for such a thread will fail and return EPERM.
*
* @param __pthread
* The current thread as returned by pthread_self().
* EINVAL will be returned if any other thread is provided.
*
* @param __qos_class
* A QOS class value:
* - QOS_CLASS_USER_INTERACTIVE
* - QOS_CLASS_USER_INITIATED
* - QOS_CLASS_DEFAULT
* - QOS_CLASS_UTILITY
* - QOS_CLASS_BACKGROUND
* - QOS_CLASS_MAINTENANCE
* EINVAL will be returned if any other value is provided.
*
* @param __relative_priority
* A relative priority within the QOS class. This value is a negative offset
* from the maximum supported scheduler priority for the given class.
* EINVAL will be returned if the value is greater than zero or less than
* QOS_MIN_RELATIVE_PRIORITY.
*
* @return
* Zero if successful, othwerise an errno value.
*/
__API_DEPRECATED_WITH_REPLACEMENT("pthread_set_qos_class_self_np", macos(10.10, 10.10), ios(8.0, 8.0))
int
pthread_set_qos_class_np(pthread_t __pthread,
qos_class_t __qos_class,
int __relative_priority);
/* Private interfaces for libdispatch to encode/decode specific values of pthread_priority_t. */
// Encode a class+priority pair into a pthread_priority_t,
__API_AVAILABLE(macos(10.10), ios(8.0))
pthread_priority_t
_pthread_qos_class_encode(qos_class_t qos_class, int relative_priority, unsigned long flags);
// Decode a pthread_priority_t into a class+priority pair.
__API_AVAILABLE(macos(10.10), ios(8.0))
qos_class_t
_pthread_qos_class_decode(pthread_priority_t priority, int *relative_priority, unsigned long *flags);
// Encode a legacy workqueue API priority into a pthread_priority_t. This API
// is deprecated and can be removed when the simulator no longer uses it.
__API_DEPRECATED("no longer used", macos(10.10, 10.13), ios(8.0, 11.0))
pthread_priority_t
_pthread_qos_class_encode_workqueue(int queue_priority, unsigned long flags);
#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
// Set QoS or voucher, or both, on pthread_self()
__API_AVAILABLE(macos(10.10), ios(8.0))
int
_pthread_set_properties_self(_pthread_set_flags_t flags, pthread_priority_t priority, mach_port_t voucher);
// Set self to fixed priority without disturbing QoS or priority
__API_AVAILABLE(macos(10.10), ios(8.0))
int
pthread_set_fixedpriority_self(void);
// Inverse of pthread_set_fixedpriority_self()
__API_AVAILABLE(macos(10.10), ios(8.0))
int
pthread_set_timeshare_self(void);
// Set self to avoid running on the same AMX as
// other work in this group.
// Only allowed on non-workqueue pthreads
__API_AVAILABLE(macos(10.15.1), ios(13.2), tvos(13.2), watchos(6.2))
int
pthread_prefer_alternate_amx_self(void);
/*!
* @const PTHREAD_MAX_PARALLELISM_PHYSICAL
* Flag that can be used with pthread_qos_max_parallelism() and
* pthread_time_constraint_max_parallelism() to ask for a count of physical
* compute units available for parallelism (default is logical).
*/
#define PTHREAD_MAX_PARALLELISM_PHYSICAL 0x1
/*!
* @function pthread_qos_max_parallelism
*
* @abstract
* Returns the number of compute units available for parallel computation at
* a specified QoS class.
*
* @param qos
* The specified QoS class.
*
* @param flags
* 0 or PTHREAD_MAX_PARALLELISM_PHYSICAL.
*
* @return
* The number of compute units available for parallel computation for the
* specified QoS, or -1 on failure (with errno set accordingly).
*/
__API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0))
int
pthread_qos_max_parallelism(qos_class_t qos, unsigned long flags);
/*!
* @function pthread_time_constraint_max_parallelism()
*
* @abstract
* Returns the number of compute units available for parallel computation on
* realtime threads.
*
* @param flags
* 0 or PTHREAD_MAX_PARALLELISM_PHYSICAL.
*
* @return
* The number of compute units available for parallel computation on realtime
* threads, or -1 on failure (with errno set accordingly).
*/
__API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0))
int
pthread_time_constraint_max_parallelism(unsigned long flags);
#endif // __DARWIN_C_LEVEL >= __DARWIN_C_FULL
__END_DECLS
#endif // KERNEL
#endif //_QOS_PRIVATE_H

View File

@ -0,0 +1,304 @@
/*
* Copyright (c) 2013-2014 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _PTHREAD_QOS_H
#define _PTHREAD_QOS_H
#include <sys/cdefs.h>
#include <sys/_pthread/_pthread_attr_t.h> /* pthread_attr_t */
#include <sys/_pthread/_pthread_t.h> /* pthread_t */
#include <Availability.h>
#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
#include <sys/qos.h>
#ifndef KERNEL
#if __has_feature(assume_nonnull)
_Pragma("clang assume_nonnull begin")
#endif
__BEGIN_DECLS
/*!
* @function pthread_attr_set_qos_class_np
*
* @abstract
* Sets the QOS class and relative priority of a pthread attribute structure
* which may be used to specify the requested QOS class of newly created
* threads.
*
* @discussion
* The QOS class and relative priority represent an overall combination of
* system quality of service attributes on a thread.
*
* Subsequent calls to interfaces such as pthread_attr_setschedparam() that are
* incompatible or in conflict with the QOS class system will unset the QOS
* class requested with this interface and pthread_attr_get_qos_class_np() will
* return QOS_CLASS_UNSPECIFIED.
*
* @param __attr
* The pthread attribute structure to modify.
*
* @param __qos_class
* A QOS class value:
* - QOS_CLASS_USER_INTERACTIVE
* - QOS_CLASS_USER_INITIATED
* - QOS_CLASS_DEFAULT
* - QOS_CLASS_UTILITY
* - QOS_CLASS_BACKGROUND
* EINVAL will be returned if any other value is provided.
*
* @param __relative_priority
* A relative priority within the QOS class. This value is a negative offset
* from the maximum supported scheduler priority for the given class.
* EINVAL will be returned if the value is greater than zero or less than
* QOS_MIN_RELATIVE_PRIORITY.
*
* @return
* Zero if successful, otherwise an errno value.
*/
__API_AVAILABLE(macos(10.10), ios(8.0))
int
pthread_attr_set_qos_class_np(pthread_attr_t *__attr,
qos_class_t __qos_class, int __relative_priority);
/*!
* @function pthread_attr_get_qos_class_np
*
* @abstract
* Gets the QOS class and relative priority of a pthread attribute structure.
*
* @param __attr
* The pthread attribute structure to inspect.
*
* @param __qos_class
* On output, a QOS class value:
* - QOS_CLASS_USER_INTERACTIVE
* - QOS_CLASS_USER_INITIATED
* - QOS_CLASS_DEFAULT
* - QOS_CLASS_UTILITY
* - QOS_CLASS_BACKGROUND
* - QOS_CLASS_UNSPECIFIED
* This value may be NULL in which case no value is returned.
*
* @param __relative_priority
* On output, a relative priority offset within the QOS class.
* This value may be NULL in which case no value is returned.
*
* @return
* Zero if successful, otherwise an errno value.
*/
__API_AVAILABLE(macos(10.10), ios(8.0))
int
pthread_attr_get_qos_class_np(pthread_attr_t * __restrict __attr,
qos_class_t * _Nullable __restrict __qos_class,
int * _Nullable __restrict __relative_priority);
/*!
* @function pthread_set_qos_class_self_np
*
* @abstract
* Sets the requested QOS class and relative priority of the current thread.
*
* @discussion
* The QOS class and relative priority represent an overall combination of
* system quality of service attributes on a thread.
*
* Subsequent calls to interfaces such as pthread_setschedparam() that are
* incompatible or in conflict with the QOS class system will unset the QOS
* class requested with this interface and pthread_get_qos_class_np() will
* return QOS_CLASS_UNSPECIFIED thereafter. A thread so modified is permanently
* opted-out of the QOS class system and calls to this function to request a QOS
* class for such a thread will fail and return EPERM.
*
* @param __qos_class
* A QOS class value:
* - QOS_CLASS_USER_INTERACTIVE
* - QOS_CLASS_USER_INITIATED
* - QOS_CLASS_DEFAULT
* - QOS_CLASS_UTILITY
* - QOS_CLASS_BACKGROUND
* EINVAL will be returned if any other value is provided.
*
* @param __relative_priority
* A relative priority within the QOS class. This value is a negative offset
* from the maximum supported scheduler priority for the given class.
* EINVAL will be returned if the value is greater than zero or less than
* QOS_MIN_RELATIVE_PRIORITY.
*
* @return
* Zero if successful, otherwise an errno value.
*/
__API_AVAILABLE(macos(10.10), ios(8.0))
int
pthread_set_qos_class_self_np(qos_class_t __qos_class,
int __relative_priority);
/*!
* @function pthread_get_qos_class_np
*
* @abstract
* Gets the requested QOS class and relative priority of a thread.
*
* @param __pthread
* The target thread to inspect.
*
* @param __qos_class
* On output, a QOS class value:
* - QOS_CLASS_USER_INTERACTIVE
* - QOS_CLASS_USER_INITIATED
* - QOS_CLASS_DEFAULT
* - QOS_CLASS_UTILITY
* - QOS_CLASS_BACKGROUND
* - QOS_CLASS_UNSPECIFIED
* This value may be NULL in which case no value is returned.
*
* @param __relative_priority
* On output, a relative priority offset within the QOS class.
* This value may be NULL in which case no value is returned.
*
* @return
* Zero if successful, otherwise an errno value.
*/
__API_AVAILABLE(macos(10.10), ios(8.0))
int
pthread_get_qos_class_np(pthread_t __pthread,
qos_class_t * _Nullable __restrict __qos_class,
int * _Nullable __restrict __relative_priority);
/*!
* @typedef pthread_override_t
*
* @abstract
* An opaque object representing a QOS class override of a thread.
*
* @discussion
* A QOS class override of a target thread expresses that an item of pending
* work classified with a specific QOS class and relative priority depends on
* the completion of the work currently being executed by the thread (e.g. due
* to ordering requirements).
*
* While overrides are in effect, the target thread will execute at the maximum
* QOS class and relative priority of all overrides and of the QOS class
* requested by the thread itself.
*
* A QOS class override does not modify the target thread's requested QOS class
* value and the effect of an override is not visible to the qos_class_self()
* and pthread_get_qos_class_np() interfaces.
*/
typedef struct pthread_override_s* pthread_override_t;
/*!
* @function pthread_override_qos_class_start_np
*
* @abstract
* Starts a QOS class override of the specified target thread.
*
* @discussion
* Starting a QOS class override of the specified target thread expresses that
* an item of pending work classified with the specified QOS class and relative
* priority depends on the completion of the work currently being executed by
* the thread (e.g. due to ordering requirements).
*
* While overrides are in effect, the specified target thread will execute at
* the maximum QOS class and relative priority of all overrides and of the QOS
* class requested by the thread itself.
*
* Starting a QOS class override does not modify the target thread's requested
* QOS class value and the effect of an override is not visible to the
* qos_class_self() and pthread_get_qos_class_np() interfaces.
*
* The returned newly allocated override object is intended to be associated
* with the item of pending work in question. Once the dependency has been
* satisfied and enabled that work to begin executing, the QOS class override
* must be ended by passing the associated override object to
* pthread_override_qos_class_end_np(). Failure to do so will result in the
* associated resources to be leaked and the target thread to be permanently
* executed at an inappropriately elevated QOS class.
*
* @param __pthread
* The target thread to modify.
*
* @param __qos_class
* A QOS class value:
* - QOS_CLASS_USER_INTERACTIVE
* - QOS_CLASS_USER_INITIATED
* - QOS_CLASS_DEFAULT
* - QOS_CLASS_UTILITY
* - QOS_CLASS_BACKGROUND
* NULL will be returned if any other value is provided.
*
* @param __relative_priority
* A relative priority within the QOS class. This value is a negative offset
* from the maximum supported scheduler priority for the given class.
* NULL will be returned if the value is greater than zero or less than
* QOS_MIN_RELATIVE_PRIORITY.
*
* @return
* A newly allocated override object if successful, or NULL if the override
* could not be started.
*/
__API_AVAILABLE(macos(10.10), ios(8.0))
pthread_override_t
pthread_override_qos_class_start_np(pthread_t __pthread,
qos_class_t __qos_class, int __relative_priority);
/*!
* @function pthread_override_qos_class_end_np
*
* @abstract
* Ends a QOS class override.
*
* @discussion
* Passing an override object returned by pthread_override_qos_class_start_np()
* ends the QOS class override started by that call and deallocates all
* associated resources as well as the override object itself.
*
* The thread starting and the thread ending a QOS class override need not be
* identical. If the thread ending the override is the the target thread of the
* override itself, it should take care to elevate its requested QOS class
* appropriately with pthread_set_qos_class_self_np() before ending the
* override.
*
* @param __override
* An override object returned by pthread_override_qos_class_start_np().
*
* @return
* Zero if successful, otherwise an errno value.
*/
__API_AVAILABLE(macos(10.10), ios(8.0))
int
pthread_override_qos_class_end_np(pthread_override_t __override);
__END_DECLS
#if __has_feature(assume_nonnull)
_Pragma("clang assume_nonnull end")
#endif
#endif // KERNEL
#endif // __DARWIN_C_LEVEL >= __DARWIN_C_FULL
#endif // _PTHREAD_QOS_H

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2003-2012 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef _PTHREAD_ATTR_T
#define _PTHREAD_ATTR_T
#include <sys/_pthread/_pthread_types.h> /* __darwin_pthread_attr_t */
typedef __darwin_pthread_attr_t pthread_attr_t;
#endif /* _PTHREAD_ATTR_T */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
* Copyright (c) 2003-2012 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
@ -25,38 +25,8 @@
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef _SYS_PTHREAD_INTERNAL_H_
#define _SYS_PTHREAD_INTERNAL_H_
#include <linux/list.h>
#include <linux/semaphore.h>
#include <stdint.h>
struct ksyn_waitq_element {
struct list_head kwe_list; /* link to other list members */
void * kwe_kwqqueue; /* queue blocked on */
uint32_t kwe_flags; /* flags */
uint32_t kwe_lockseq; /* the sequence of the entry */
uint32_t kwe_count; /* upper bound on number of matches still pending */
uint32_t kwe_psynchretval; /* thread retval */
void *kwe_uth; /* uthread */
#if defined (__DARLING__)
struct linux_semaphore linux_sem;
#endif
};
typedef struct ksyn_waitq_element * ksyn_waitq_element_t;
/* kew_flags defns */
#define KWE_THREAD_INWAIT 1
#define KWE_THREAD_PREPOST 2
#define KWE_THREAD_BROADCAST 4
void
pth_global_hashinit(void);
void
pth_global_hashexit(void);
#endif /* _SYS_PTHREAD_INTERNAL_H_ */
#ifndef _PTHREAD_T
#define _PTHREAD_T
#include <sys/_pthread/_pthread_types.h> /* __darwin_pthread_t */
typedef __darwin_pthread_t pthread_t;
#endif /* _PTHREAD_T */

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2003-2013 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef _SYS__PTHREAD_TYPES_H_
#define _SYS__PTHREAD_TYPES_H_
#include <sys/cdefs.h>
// pthread opaque structures
#if defined(__LP64__)
#define __PTHREAD_SIZE__ 8176
#define __PTHREAD_ATTR_SIZE__ 56
#define __PTHREAD_MUTEXATTR_SIZE__ 8
#define __PTHREAD_MUTEX_SIZE__ 56
#define __PTHREAD_CONDATTR_SIZE__ 8
#define __PTHREAD_COND_SIZE__ 40
#define __PTHREAD_ONCE_SIZE__ 8
#define __PTHREAD_RWLOCK_SIZE__ 192
#define __PTHREAD_RWLOCKATTR_SIZE__ 16
#else // !__LP64__
#define __PTHREAD_SIZE__ 4088
#define __PTHREAD_ATTR_SIZE__ 36
#define __PTHREAD_MUTEXATTR_SIZE__ 8
#define __PTHREAD_MUTEX_SIZE__ 40
#define __PTHREAD_CONDATTR_SIZE__ 4
#define __PTHREAD_COND_SIZE__ 24
#define __PTHREAD_ONCE_SIZE__ 4
#define __PTHREAD_RWLOCK_SIZE__ 124
#define __PTHREAD_RWLOCKATTR_SIZE__ 12
#endif // !__LP64__
struct __darwin_pthread_handler_rec {
void (*__routine)(void *); // Routine to call
void *__arg; // Argument to pass
struct __darwin_pthread_handler_rec *__next;
};
struct _opaque_pthread_attr_t {
long __sig;
char __opaque[__PTHREAD_ATTR_SIZE__];
};
struct _opaque_pthread_cond_t {
long __sig;
char __opaque[__PTHREAD_COND_SIZE__];
};
struct _opaque_pthread_condattr_t {
long __sig;
char __opaque[__PTHREAD_CONDATTR_SIZE__];
};
struct _opaque_pthread_mutex_t {
long __sig;
char __opaque[__PTHREAD_MUTEX_SIZE__];
};
struct _opaque_pthread_mutexattr_t {
long __sig;
char __opaque[__PTHREAD_MUTEXATTR_SIZE__];
};
struct _opaque_pthread_once_t {
long __sig;
char __opaque[__PTHREAD_ONCE_SIZE__];
};
struct _opaque_pthread_rwlock_t {
long __sig;
char __opaque[__PTHREAD_RWLOCK_SIZE__];
};
struct _opaque_pthread_rwlockattr_t {
long __sig;
char __opaque[__PTHREAD_RWLOCKATTR_SIZE__];
};
struct _opaque_pthread_t {
long __sig;
struct __darwin_pthread_handler_rec *__cleanup_stack;
char __opaque[__PTHREAD_SIZE__];
};
typedef struct _opaque_pthread_attr_t __darwin_pthread_attr_t;
typedef struct _opaque_pthread_cond_t __darwin_pthread_cond_t;
typedef struct _opaque_pthread_condattr_t __darwin_pthread_condattr_t;
typedef unsigned long __darwin_pthread_key_t;
typedef struct _opaque_pthread_mutex_t __darwin_pthread_mutex_t;
typedef struct _opaque_pthread_mutexattr_t __darwin_pthread_mutexattr_t;
typedef struct _opaque_pthread_once_t __darwin_pthread_once_t;
typedef struct _opaque_pthread_rwlock_t __darwin_pthread_rwlock_t;
typedef struct _opaque_pthread_rwlockattr_t __darwin_pthread_rwlockattr_t;
typedef struct _opaque_pthread_t *__darwin_pthread_t;
#endif // _SYS__PTHREAD_TYPES_H_

200
dthread/include/sys/qos.h Normal file
View File

@ -0,0 +1,200 @@
/*
* Copyright (c) 2013-2014 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _SYS_QOS_H
#define _SYS_QOS_H
#include <sys/cdefs.h>
#include <Availability.h>
/*!
* @typedef qos_class_t
*
* @abstract
* An abstract thread quality of service (QOS) classification.
*
* @discussion
* Thread quality of service (QOS) classes are ordered abstract representations
* of the nature of work that is expected to be performed by a pthread, dispatch
* queue, or NSOperation. Each class specifies a maximum thread scheduling
* priority for that band (which may be used in combination with a relative
* priority offset within the band), as well as quality of service
* characteristics for timer latency, CPU throughput, I/O throughput, network
* socket traffic management behavior and more.
*
* A best effort is made to allocate available system resources to every QOS
* class. Quality of service degredation only occurs during system resource
* contention, proportionally to the QOS class. That said, QOS classes
* representing user-initiated work attempt to achieve peak throughput while
* QOS classes for other work attempt to achieve peak energy and thermal
* efficiency, even in the absence of contention. Finally, the use of QOS
* classes does not allow threads to supersede any limits that may be applied
* to the overall process.
*/
/*!
* @constant QOS_CLASS_USER_INTERACTIVE
* @abstract A QOS class which indicates work performed by this thread
* is interactive with the user.
* @discussion Such work is requested to run at high priority relative to other
* work on the system. Specifying this QOS class is a request to run with
* nearly all available system CPU and I/O bandwidth even under contention.
* This is not an energy-efficient QOS class to use for large tasks. The use of
* this QOS class should be limited to critical interaction with the user such
* as handling events on the main event loop, view drawing, animation, etc.
*
* @constant QOS_CLASS_USER_INITIATED
* @abstract A QOS class which indicates work performed by this thread
* was initiated by the user and that the user is likely waiting for the
* results.
* @discussion Such work is requested to run at a priority below critical user-
* interactive work, but relatively higher than other work on the system. This
* is not an energy-efficient QOS class to use for large tasks. Its use
* should be limited to operations of short enough duration that the user is
* unlikely to switch tasks while waiting for the results. Typical
* user-initiated work will have progress indicated by the display of
* placeholder content or modal user interface.
*
* @constant QOS_CLASS_DEFAULT
* @abstract A default QOS class used by the system in cases where more specific
* QOS class information is not available.
* @discussion Such work is requested to run at a priority below critical user-
* interactive and user-initiated work, but relatively higher than utility and
* background tasks. Threads created by pthread_create() without an attribute
* specifying a QOS class will default to QOS_CLASS_DEFAULT. This QOS class
* value is not intended to be used as a work classification, it should only be
* set when propagating or restoring QOS class values provided by the system.
*
* @constant QOS_CLASS_UTILITY
* @abstract A QOS class which indicates work performed by this thread
* may or may not be initiated by the user and that the user is unlikely to be
* immediately waiting for the results.
* @discussion Such work is requested to run at a priority below critical user-
* interactive and user-initiated work, but relatively higher than low-level
* system maintenance tasks. The use of this QOS class indicates the work
* should be run in an energy and thermally-efficient manner. The progress of
* utility work may or may not be indicated to the user, but the effect of such
* work is user-visible.
*
* @constant QOS_CLASS_BACKGROUND
* @abstract A QOS class which indicates work performed by this thread was not
* initiated by the user and that the user may be unaware of the results.
* @discussion Such work is requested to run at a priority below other work.
* The use of this QOS class indicates the work should be run in the most energy
* and thermally-efficient manner.
*
* @constant QOS_CLASS_UNSPECIFIED
* @abstract A QOS class value which indicates the absence or removal of QOS
* class information.
* @discussion As an API return value, may indicate that threads or pthread
* attributes were configured with legacy API incompatible or in conflict with
* the QOS class system.
*/
#define __QOS_ENUM(name, type, ...) enum { __VA_ARGS__ }; typedef type name##_t
#define __QOS_CLASS_AVAILABLE(...)
#if defined(__cplusplus) || defined(__OBJC__) || __LP64__
#if defined(__has_feature) && defined(__has_extension)
#if __has_feature(objc_fixed_enum) || __has_extension(cxx_strong_enums)
#undef __QOS_ENUM
#define __QOS_ENUM(name, type, ...) typedef enum : type { __VA_ARGS__ } name##_t
#endif
#endif
#if __has_feature(enumerator_attributes)
#undef __QOS_CLASS_AVAILABLE
#define __QOS_CLASS_AVAILABLE __API_AVAILABLE
#endif
#endif
__QOS_ENUM(qos_class, unsigned int,
QOS_CLASS_USER_INTERACTIVE
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x21,
QOS_CLASS_USER_INITIATED
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x19,
QOS_CLASS_DEFAULT
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x15,
QOS_CLASS_UTILITY
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x11,
QOS_CLASS_BACKGROUND
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x09,
QOS_CLASS_UNSPECIFIED
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x00,
);
#undef __QOS_ENUM
/*!
* @constant QOS_MIN_RELATIVE_PRIORITY
* @abstract The minimum relative priority that may be specified within a
* QOS class. These priorities are relative only within a given QOS class
* and meaningful only for the current process.
*/
#define QOS_MIN_RELATIVE_PRIORITY (-15)
/* Userspace (only) definitions */
#ifndef KERNEL
__BEGIN_DECLS
/*!
* @function qos_class_self
*
* @abstract
* Returns the requested QOS class of the current thread.
*
* @return
* One of the QOS class values in qos_class_t.
*/
__API_AVAILABLE(macos(10.10), ios(8.0))
qos_class_t
qos_class_self(void);
/*!
* @function qos_class_main
*
* @abstract
* Returns the initial requested QOS class of the main thread.
*
* @discussion
* The QOS class that the main thread of a process is created with depends on
* the type of process (e.g. application or daemon) and on how it has been
* launched.
*
* This function returns that initial requested QOS class value chosen by the
* system to enable propagation of that classification to matching work not
* executing on the main thread.
*
* @return
* One of the QOS class values in qos_class_t.
*/
__API_AVAILABLE(macos(10.10), ios(8.0))
qos_class_t
qos_class_main(void);
__END_DECLS
#endif // KERNEL
#endif // _SYS_QOS_H

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2014 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _QOS_SYS_PRIVATE_H
#define _QOS_SYS_PRIVATE_H
/*!
* @constant QOS_CLASS_MAINTENANCE
* @abstract A QOS class which indicates work performed by this thread was not
* initiated by the user and that the user may be unaware of the results.
* @discussion Such work is requested to run at a priority far below other work
* including significant I/O throttling. The use of this QOS class indicates
* the work should be run in the most energy and thermally-efficient manner
* possible, and may be deferred for a long time in order to preserve
* system responsiveness for the user.
* This is SPI for use by Spotlight and Time Machine only.
*/
#define QOS_CLASS_MAINTENANCE ((qos_class_t)0x05)
#endif //_QOS_SYS_PRIVATE_H

65
dthread/kern_init.c Normal file
View File

@ -0,0 +1,65 @@
//
// pthread.c
// pthread
//
// Created by Matt Wright on 9/13/12.
// Copyright (c) 2012 Matt Wright. All rights reserved.
//
#include <kern/thread.h>
#include <kern/debug.h>
#include "kern_internal.h"
kern_return_t pthread_start(kmod_info_t * ki, void *d);
kern_return_t pthread_stop(kmod_info_t *ki, void *d);
pthread_callbacks_t pthread_kern;
const struct pthread_functions_s pthread_internal_functions = {
.pthread_init = _pthread_init,
.pth_proc_hashinit = _pth_proc_hashinit,
.pth_proc_hashdelete = _pth_proc_hashdelete,
.bsdthread_create = _bsdthread_create,
.bsdthread_register = _bsdthread_register,
.bsdthread_terminate = _bsdthread_terminate,
.thread_selfid = _thread_selfid,
.psynch_mutexwait = _psynch_mutexwait,
.psynch_mutexdrop = _psynch_mutexdrop,
.psynch_cvbroad = _psynch_cvbroad,
.psynch_cvsignal = _psynch_cvsignal,
.psynch_cvwait = _psynch_cvwait,
.psynch_cvclrprepost = _psynch_cvclrprepost,
.psynch_rw_longrdlock = _psynch_rw_longrdlock,
.psynch_rw_rdlock = _psynch_rw_rdlock,
.psynch_rw_unlock = _psynch_rw_unlock,
.psynch_rw_wrlock = _psynch_rw_wrlock,
.psynch_rw_yieldwrlock = _psynch_rw_yieldwrlock,
.pthread_find_owner = _pthread_find_owner,
.pthread_get_thread_kwq = _pthread_get_thread_kwq,
.workq_create_threadstack = workq_create_threadstack,
.workq_destroy_threadstack = workq_destroy_threadstack,
.workq_setup_thread = workq_setup_thread,
.workq_handle_stack_events = workq_handle_stack_events,
.workq_markfree_threadstack = workq_markfree_threadstack,
};
kern_return_t pthread_start(__unused kmod_info_t * ki, __unused void *d)
{
pthread_kext_register((pthread_functions_t)&pthread_internal_functions, &pthread_kern);
return KERN_SUCCESS;
}
kern_return_t pthread_stop(__unused kmod_info_t *ki, __unused void *d)
{
return KERN_FAILURE;
}
struct uthread*
current_uthread(void)
{
thread_t th = current_thread();
return pthread_kern->get_bsdthread_info(th);
}

227
dthread/kern_internal.h Normal file
View File

@ -0,0 +1,227 @@
/*
* Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
// header name modified for Darling
#ifndef _DTHREAD_KERN_INTERNAL_H
#define _DTHREAD_KERN_INTERNAL_H
#include <pthread/bsdthread_private.h>
#include <pthread/priority_private.h>
#include <pthread/workqueue_syscalls.h>
#ifdef KERNEL
struct ksyn_waitq_element;
#include <stdatomic.h>
#include <kern/thread_call.h>
#include <kern/kcdata.h>
#ifdef __DARLING__
#include <kern/thread.h>
#else
#include <sys/pthread_shims.h>
#endif
#include <sys/queue.h>
#include <sys/proc_info.h>
#ifdef __arm64__
#define PTHREAD_INLINE_RMW_ATOMICS 0
#else
#define PTHREAD_INLINE_RMW_ATOMICS 1
#endif
#endif // KERNEL
#include "kern/synch_internal.h"
#include "kern/workqueue_internal.h"
#include "kern/kern_trace.h"
#include "pthread/qos.h"
#include "private/qos_private.h"
/* pthread userspace SPI feature checking, these constants are returned from bsdthread_register,
* as a bitmask, to inform userspace of the supported feature set. Old releases of OS X return
* from this call either zero or -1, allowing us to return a positive number for feature bits.
*/
#define PTHREAD_FEATURE_DISPATCHFUNC 0x01 /* same as WQOPS_QUEUE_NEWSPISUPP, checks for dispatch function support */
#define PTHREAD_FEATURE_FINEPRIO 0x02 /* are fine grained prioirities available */
#define PTHREAD_FEATURE_BSDTHREADCTL 0x04 /* is the bsdthread_ctl syscall available */
#define PTHREAD_FEATURE_SETSELF 0x08 /* is the BSDTHREAD_CTL_SET_SELF command of bsdthread_ctl available */
#define PTHREAD_FEATURE_QOS_MAINTENANCE 0x10 /* is QOS_CLASS_MAINTENANCE available */
#define PTHREAD_FEATURE_RESERVED 0x20 /* burnt, shipped in OSX 10.11 & iOS 9 with partial kevent delivery support */
#define PTHREAD_FEATURE_KEVENT 0x40 /* supports direct kevent delivery */
#define PTHREAD_FEATURE_WORKLOOP 0x80 /* supports workloops */
#define PTHREAD_FEATURE_QOS_DEFAULT 0x40000000 /* the kernel supports QOS_CLASS_DEFAULT */
/* userspace <-> kernel registration struct, for passing data to/from the kext during main thread init. */
struct _pthread_registration_data {
/*
* version == sizeof(struct _pthread_registration_data)
*
* The structure can only grow, so we use its size as the version.
* Userspace initializes this to the size of its structure and the kext
* will copy out the version that was actually consumed.
*
* n.b. you must make sure the size of this structure isn't LP64-dependent
*/
uint64_t version;
uint64_t dispatch_queue_offset; /* copy-in */
uint64_t /* pthread_priority_t */ main_qos; /* copy-out */
uint32_t tsd_offset; /* copy-in */
uint32_t return_to_kernel_offset; /* copy-in */
uint32_t mach_thread_self_offset; /* copy-in */
mach_vm_address_t stack_addr_hint; /* copy-out */
uint32_t mutex_default_policy; /* copy-out */
} __attribute__ ((packed));
/*
* "error" flags returned by fail condvar syscalls
*/
#define ECVCLEARED 0x100
#define ECVPREPOST 0x200
#ifdef KERNEL
/* The set of features, from the feature bits above, that we support. */
#define PTHREAD_FEATURE_SUPPORTED ( \
PTHREAD_FEATURE_DISPATCHFUNC | \
PTHREAD_FEATURE_FINEPRIO | \
PTHREAD_FEATURE_BSDTHREADCTL | \
PTHREAD_FEATURE_SETSELF | \
PTHREAD_FEATURE_QOS_MAINTENANCE | \
PTHREAD_FEATURE_QOS_DEFAULT | \
PTHREAD_FEATURE_KEVENT | \
PTHREAD_FEATURE_WORKLOOP )
#ifdef __DARLING__
// since we had to move the `pthread_shims.h` include down, we need to declare this differently
struct pthread_callbacks_s;
extern const struct pthread_callbacks_s* pthread_kern;
#else
extern pthread_callbacks_t pthread_kern;
#endif
struct ksyn_waitq_element {
TAILQ_ENTRY(ksyn_waitq_element) kwe_list; /* link to other list members */
void * kwe_kwqqueue; /* queue blocked on */
thread_t kwe_thread;
uint16_t kwe_state; /* state */
uint16_t kwe_flags;
uint32_t kwe_lockseq; /* the sequence of the entry */
uint32_t kwe_count; /* upper bound on number of matches still pending */
uint32_t kwe_psynchretval; /* thread retval */
void *kwe_uth; /* uthread */
};
typedef struct ksyn_waitq_element * ksyn_waitq_element_t;
#define PTH_DEFAULT_STACKSIZE 512*1024
#define MAX_PTHREAD_SIZE 64*1024
/* exported from the kernel but not present in any headers. */
extern thread_t port_name_to_thread(mach_port_name_t port_name);
/* function declarations for pthread_kext.c */
void pthread_init(void);
void psynch_zoneinit(void);
void _pth_proc_hashinit(proc_t p);
void _pth_proc_hashdelete(proc_t p);
void pth_global_hashinit(void);
void psynch_wq_cleanup(void*, void*);
void _pthread_init(void);
int _fill_procworkqueue(proc_t p, struct proc_workqueueinfo * pwqinfo);
uint32_t _get_pwq_state_kdp(proc_t p);
void _workqueue_exit(struct proc *p);
void _workqueue_mark_exiting(struct proc *p);
void _workqueue_thread_yielded(void);
sched_call_t _workqueue_get_sched_callback(void);
int _bsdthread_create(struct proc *p, user_addr_t user_func, user_addr_t user_funcarg, user_addr_t user_stack, user_addr_t user_pthread, uint32_t flags, user_addr_t *retval);
int _bsdthread_register(struct proc *p, user_addr_t threadstart, user_addr_t wqthread, int pthsize, user_addr_t dummy_value, user_addr_t targetconc_ptr, uint64_t dispatchqueue_offset, int32_t *retval);
int _bsdthread_terminate(struct proc *p, user_addr_t stackaddr, size_t size, uint32_t kthport, uint32_t sem, int32_t *retval);
int _bsdthread_ctl_set_qos(struct proc *p, user_addr_t cmd, mach_port_name_t kport, user_addr_t tsd_priority_addr, user_addr_t arg3, int *retval);
int _bsdthread_ctl_set_self(struct proc *p, user_addr_t cmd, pthread_priority_t priority, mach_port_name_t voucher, _pthread_set_flags_t flags, int *retval);
int _bsdthread_ctl_qos_override_start(struct proc *p, user_addr_t cmd, mach_port_name_t kport, pthread_priority_t priority, user_addr_t resource, int *retval);
int _bsdthread_ctl_qos_override_end(struct proc *p, user_addr_t cmd, mach_port_name_t kport, user_addr_t resource, user_addr_t arg3, int *retval);
int _bsdthread_ctl_qos_override_dispatch(struct proc __unused *p, user_addr_t __unused cmd, mach_port_name_t kport, pthread_priority_t priority, user_addr_t arg3, int __unused *retval);
int _bsdthread_ctl_qos_override_reset(struct proc __unused *p, user_addr_t __unused cmd, user_addr_t arg1, user_addr_t arg2, user_addr_t arg3, int __unused *retval);
int _bsdthread_ctl_qos_dispatch_asynchronous_override_add(struct proc __unused *p, user_addr_t __unused cmd, mach_port_name_t kport, pthread_priority_t priority, user_addr_t resource, int __unused *retval);
int _bsdthread_ctl_qos_dispatch_asynchronous_override_reset(struct proc __unused *p, user_addr_t __unused cmd, int reset_all, user_addr_t resource, user_addr_t arg3, int __unused *retval);
int _bsdthread_ctl(struct proc *p, user_addr_t cmd, user_addr_t arg1, user_addr_t arg2, user_addr_t arg3, int *retval);
int _thread_selfid(__unused struct proc *p, uint64_t *retval);
int _workq_kernreturn(struct proc *p, int options, user_addr_t item, int arg2, int arg3, int32_t *retval);
int _workq_open(struct proc *p, int32_t *retval);
int _psynch_mutexwait(proc_t p, user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint64_t tid, uint32_t flags, uint32_t * retval);
int _psynch_mutexdrop(proc_t p, user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint64_t tid, uint32_t flags, uint32_t * retval);
int _psynch_cvbroad(proc_t p, user_addr_t cv, uint64_t cvlsgen, uint64_t cvudgen, uint32_t flags, user_addr_t mutex, uint64_t mugen, uint64_t tid, uint32_t *retval);
int _psynch_cvsignal(proc_t p, user_addr_t cv, uint64_t cvlsgen, uint32_t cvugen, int thread_port, user_addr_t mutex, uint64_t mugen, uint64_t tid, uint32_t flags, uint32_t * retval);
int _psynch_cvwait(proc_t p, user_addr_t cv, uint64_t cvlsgen, uint32_t cvugen, user_addr_t mutex, uint64_t mugen, uint32_t flags, int64_t sec, uint32_t nsec, uint32_t * retval);
int _psynch_cvclrprepost(proc_t p, user_addr_t cv, uint32_t cvgen, uint32_t cvugen, uint32_t cvsgen, uint32_t prepocnt, uint32_t preposeq, uint32_t flags, int *retval);
int _psynch_rw_longrdlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t * retval);
int _psynch_rw_rdlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t *retval);
int _psynch_rw_unlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t *retval);
int _psynch_rw_wrlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t *retval);
int _psynch_rw_yieldwrlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t *retval);
void _pthread_find_owner(thread_t thread, struct stackshot_thread_waitinfo *waitinfo);
void * _pthread_get_thread_kwq(thread_t thread);
extern lck_grp_attr_t *pthread_lck_grp_attr;
extern lck_grp_t *pthread_lck_grp;
extern lck_attr_t *pthread_lck_attr;
extern lck_mtx_t *pthread_list_mlock;
extern thread_call_t psynch_thcall;
struct uthread* current_uthread(void);
int
workq_create_threadstack(proc_t p, vm_map_t vmap, mach_vm_offset_t *out_addr);
int
workq_destroy_threadstack(proc_t p, vm_map_t vmap, mach_vm_offset_t stackaddr);
void
workq_setup_thread(proc_t p, thread_t th, vm_map_t map, user_addr_t stackaddr,
mach_port_name_t kport, int th_qos, int setup_flags, int upcall_flags);
int
workq_handle_stack_events(proc_t p, thread_t th, vm_map_t map,
user_addr_t stackaddr, mach_port_name_t kport,
user_addr_t events, int nevents, int upcall_flags);
void
workq_markfree_threadstack(proc_t p, thread_t th, vm_map_t vmap,
user_addr_t stackaddr);
#ifdef __DARLING__
// move it down here because it needs `struct ksyn_waitq_element` to be defined
#include <sys/pthread_shims.h>
#endif
#endif // KERNEL
#endif // _DTHREAD_KERN_INTERNAL_H

1020
dthread/kern_support.c Normal file

File diff suppressed because it is too large Load Diff

2827
dthread/kern_synch.c Normal file

File diff suppressed because it is too large Load Diff

164
dthread/kern_trace.h Normal file
View File

@ -0,0 +1,164 @@
/*
* Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef _KERN_TRACE_H_
#define _KERN_TRACE_H_
/* pthread kext, or userspace, kdebug trace points. Defined here and output to
* /usr/share/misc/pthread.codes during build.
*/
// userspace trace points force slow-paths, so must be compiled in
#define ENABLE_USERSPACE_TRACE 0
// pthread tracing subclasses
# define _TRACE_SUB_DEFAULT 0
# define _TRACE_SUB_WORKQUEUE 1
// WQ_TRACE_REQUESTS_SUBCLASS is 2, in xnu
# define _TRACE_SUB_MUTEX 3
# define _TRACE_SUB_CONDVAR 4
#ifndef _PTHREAD_BUILDING_CODES_
#include <sys/kdebug.h>
#ifndef DBG_PTHREAD
#define DBG_PTHREAD DBG_WORKQUEUE
#endif
#if KERNEL
#include <vm/vm_kern.h>
extern uint32_t pthread_debug_tracing;
static __unused void*
VM_UNSLIDE(void* ptr)
{
vm_offset_t unslid_ptr;
vm_kernel_unslide_or_perm_external(ptr, &unslid_ptr);
return (void*)unslid_ptr;
}
# define PTHREAD_TRACE(x,a,b,c,d) \
{ if (pthread_debug_tracing) { KERNEL_DEBUG_CONSTANT(TRACE_##x, a, b, c, d, 0); } }
# define PTHREAD_TRACE_WQ(x,a,b,c,d) \
{ if (pthread_debug_tracing) { KERNEL_DEBUG_CONSTANT(TRACE_##x, VM_UNSLIDE(a), b, c, d, 0); } }
# define PTHREAD_TRACE_WQ_REQ(x,a,b,c,d,e) \
{ if (pthread_debug_tracing) { KERNEL_DEBUG_CONSTANT(TRACE_##x, VM_UNSLIDE(a), VM_UNSLIDE(b), c, d, e); } }
#else // KERNEL
#if ENABLE_USERSPACE_TRACE
# include <sys/kdebug.h>
# define PTHREAD_TRACE(x, a, b, c, d) kdebug_trace(TRACE_##x, a, b, c, d)
#else // ENABLE_USERSPACE_TRACE
# define PTHREAD_TRACE(x, a, b, c, d) do { } while(0)
#endif // ENABLE_USERSPACE_TRACE
#endif // KERNEL
# define TRACE_CODE(name, subclass, code) \
static const int TRACE_##name = KDBG_CODE(DBG_PTHREAD, subclass, code)
#else // _PTHREAD_BUILDING_CODES_
/* When not included as a header, this file is pre-processed into perl source to generate
* the pthread.codes file during build.
*/
# define DBG_PTHREAD 9
# define STR(x) #x
# define TRACE_CODE(name, subclass, code) \
printf("0x%x\t%s\n", ((DBG_PTHREAD << 24) | ((subclass & 0xff) << 16) | ((code & 0x3fff) << 2)), STR(name))
#endif // _PTHREAD_BUILDING_CODES_
/* These defines translate into TRACE_<name> when used in source code, and are
* pre-processed out to a codes file by the build system.
*/
// "default" trace points
TRACE_CODE(pthread_thread_create, _TRACE_SUB_DEFAULT, 0x10);
TRACE_CODE(pthread_thread_terminate, _TRACE_SUB_DEFAULT, 0x20);
TRACE_CODE(pthread_set_qos_self, _TRACE_SUB_DEFAULT, 0x30);
// workqueue trace points
TRACE_CODE(wq_pthread_exit, _TRACE_SUB_WORKQUEUE, 0x01);
TRACE_CODE(wq_workqueue_exit, _TRACE_SUB_WORKQUEUE, 0x02);
TRACE_CODE(wq_runthread, _TRACE_SUB_WORKQUEUE, 0x03);
TRACE_CODE(wq_runitem, _TRACE_SUB_WORKQUEUE, 0x04);
TRACE_CODE(wq_thread_block, _TRACE_SUB_WORKQUEUE, 0x9);
TRACE_CODE(wq_thactive_update, _TRACE_SUB_WORKQUEUE, 0xa);
TRACE_CODE(wq_add_timer, _TRACE_SUB_WORKQUEUE, 0xb);
TRACE_CODE(wq_start_add_timer, _TRACE_SUB_WORKQUEUE, 0x0c);
TRACE_CODE(wq_override_start, _TRACE_SUB_WORKQUEUE, 0x12);
TRACE_CODE(wq_override_end, _TRACE_SUB_WORKQUEUE, 0x13);
TRACE_CODE(wq_override_dispatch, _TRACE_SUB_WORKQUEUE, 0x14);
TRACE_CODE(wq_override_reset, _TRACE_SUB_WORKQUEUE, 0x15);
TRACE_CODE(wq_thread_create_failed, _TRACE_SUB_WORKQUEUE, 0x1d);
TRACE_CODE(wq_thread_create, _TRACE_SUB_WORKQUEUE, 0x1f);
TRACE_CODE(wq_run_threadreq, _TRACE_SUB_WORKQUEUE, 0x20);
TRACE_CODE(wq_run_threadreq_mgr_merge, _TRACE_SUB_WORKQUEUE, 0x21);
TRACE_CODE(wq_run_threadreq_req_select, _TRACE_SUB_WORKQUEUE, 0x22);
TRACE_CODE(wq_run_threadreq_thread_select, _TRACE_SUB_WORKQUEUE, 0x23);
TRACE_CODE(wq_thread_reset_priority, _TRACE_SUB_WORKQUEUE, 0x24);
TRACE_CODE(wq_constrained_admission, _TRACE_SUB_WORKQUEUE, 0x25);
TRACE_CODE(wq_wqops_reqthreads, _TRACE_SUB_WORKQUEUE, 0x26);
TRACE_CODE(wq_kevent_reqthreads, _TRACE_SUB_WORKQUEUE, 0x27);
TRACE_CODE(wq_thread_park, _TRACE_SUB_WORKQUEUE, 0x28);
TRACE_CODE(wq_thread_squash, _TRACE_SUB_WORKQUEUE, 0x29);
// synch trace points
TRACE_CODE(psynch_mutex_ulock, _TRACE_SUB_MUTEX, 0x0);
TRACE_CODE(psynch_mutex_utrylock_failed, _TRACE_SUB_MUTEX, 0x1);
TRACE_CODE(psynch_mutex_uunlock, _TRACE_SUB_MUTEX, 0x2);
TRACE_CODE(psynch_ksyn_incorrect_owner, _TRACE_SUB_MUTEX, 0x3);
TRACE_CODE(psynch_mutex_lock_updatebits, _TRACE_SUB_MUTEX, 0x4);
TRACE_CODE(psynch_mutex_unlock_updatebits, _TRACE_SUB_MUTEX, 0x5);
TRACE_CODE(psynch_mutex_clearprepost, _TRACE_SUB_MUTEX, 0x6);
TRACE_CODE(psynch_mutex_kwqallocate, _TRACE_SUB_MUTEX, 0x7);
TRACE_CODE(psynch_mutex_kwqdeallocate, _TRACE_SUB_MUTEX, 0x8);
TRACE_CODE(psynch_mutex_kwqprepost, _TRACE_SUB_MUTEX, 0x9);
TRACE_CODE(psynch_mutex_markprepost, _TRACE_SUB_MUTEX, 0x10);
TRACE_CODE(psynch_mutex_kwqcollision, _TRACE_SUB_MUTEX, 0x11);
TRACE_CODE(psynch_ffmutex_lock_updatebits, _TRACE_SUB_MUTEX, 0x12);
TRACE_CODE(psynch_ffmutex_unlock_updatebits, _TRACE_SUB_MUTEX, 0x13);
TRACE_CODE(psynch_ffmutex_wake, _TRACE_SUB_MUTEX, 0x14);
TRACE_CODE(psynch_mutex_kwqsignal, _TRACE_SUB_MUTEX, 0x15);
TRACE_CODE(psynch_ffmutex_wait, _TRACE_SUB_MUTEX, 0x16);
TRACE_CODE(psynch_mutex_kwqwait, _TRACE_SUB_MUTEX, 0x17);
TRACE_CODE(psynch_cvar_kwait, _TRACE_SUB_CONDVAR, 0x0);
TRACE_CODE(psynch_cvar_clrprepost, _TRACE_SUB_CONDVAR, 0x1);
TRACE_CODE(psynch_cvar_freeitems, _TRACE_SUB_CONDVAR, 0x2);
TRACE_CODE(psynch_cvar_signal, _TRACE_SUB_CONDVAR, 0x3);
TRACE_CODE(psynch_cvar_broadcast, _TRACE_SUB_CONDVAR, 0x5);
TRACE_CODE(psynch_cvar_zeroed, _TRACE_SUB_CONDVAR, 0x6);
TRACE_CODE(psynch_cvar_updateval, _TRACE_SUB_CONDVAR, 0x7);
#endif // _KERN_TRACE_H_

201
dthread/pthread_kext.c Normal file
View File

@ -0,0 +1,201 @@
/**
* a brief rationale on why we need this
* ---
*
* so, sometime around the release of macOS 10.9 (with xnu-2422.1.72),
* Apple decided to stuff pthread support in-kernel into a kext (pthread.kext)
*
* we already have most of the functions implemented in `psync_support.c`, this file just takes care of the rest
* and the necessary plumbing for XNU's `pthread_shims.c` so that we can use XNU's own interface as much as possible
*
* ignore the following; i've actually decided against building `pthread_workqueue.c`
* (turns out its usage in `turnstile.c` only matters when workqueues are already being used for something else)
*
* > up until recently, we didn't really build any parts of XNU that needed it
* >
* > however, the new turnstile subsystem requires functions that are implemented in `pthread_workqueue.c`,
* > and it's relatively simple to build that file by adding support for the functions it calls out to
* > (and easy enough that it's better than stubbing them)
*
* so like i said, that reason is no longer valid. i decided to leave this in anyways because i had already completely
* added it in and it works so ¯\_()_/¯
*/
#include <duct/duct.h>
#include <duct/duct_pre_xnu.h>
#include <kern/kern_types.h>
#include <sys/proc.h>
#include "kern_internal.h"
#include <duct/duct_post_xnu.h>
#include "pthread_kext.h"
/**
*
* `pthread_shims.c` plumbing
*
*/
static const struct pthread_functions_s _darling_pthread_functions = {
.pthread_init = _pthread_init,
.pth_proc_hashinit = _pth_proc_hashinit,
.pth_proc_hashdelete = _pth_proc_hashdelete,
.bsdthread_create = _bsdthread_create,
.bsdthread_register = _bsdthread_register,
.bsdthread_terminate = _bsdthread_terminate,
.thread_selfid = _thread_selfid,
.psynch_mutexwait = _psynch_mutexwait,
.psynch_mutexdrop = _psynch_mutexdrop,
.psynch_cvbroad = _psynch_cvbroad,
.psynch_cvsignal = _psynch_cvsignal,
.psynch_cvwait = _psynch_cvwait,
.psynch_cvclrprepost = _psynch_cvclrprepost,
.psynch_rw_longrdlock = _psynch_rw_longrdlock,
.psynch_rw_rdlock = _psynch_rw_rdlock,
.psynch_rw_unlock = _psynch_rw_unlock,
.psynch_rw_wrlock = _psynch_rw_wrlock,
.psynch_rw_yieldwrlock = _psynch_rw_yieldwrlock,
.pthread_find_owner = _pthread_find_owner,
.pthread_get_thread_kwq = _pthread_get_thread_kwq,
.workq_create_threadstack = workq_create_threadstack,
.workq_destroy_threadstack = workq_destroy_threadstack,
.workq_setup_thread = workq_setup_thread,
.workq_handle_stack_events = workq_handle_stack_events,
.workq_markfree_threadstack = workq_markfree_threadstack,
};
// called by our kernel module during initialization
//
// this is different from `darling_pthread_init`, because this function is the one that sets up
// the pthread kext plumbing, while the `pthread_init` is only called by some BSD code after the kext has already been set up
void darling_pthread_kext_init(void) {
// we don't really need the callbacks, since we're not actually a kext and we have full access to the whole kernel,
// but it's easier to provide the callbacks than it is to modify every instance of `pthread_kern->whatever(...)`.
// plus, `pthread_shims.c` won't take "no" for an answer (it'll panic if we give it `NULL`).
// we have this a local variable though, because since we *aren't* a kext, we have `pthread_kern` already defined in `pthread_shims.c`
pthread_callbacks_t callbacks = NULL;
pthread_kext_register(&_darling_pthread_functions, &callbacks);
};
// called by our kernel module when it's going to be unloaded
void darling_pthread_kext_exit(void) {};
// temporarily copied over from kern_support.c (until we start building that file)
// <copied from="libpthread://416.60.2/kern/kern_support.c" modified="true">
#ifdef __DARLING__
uint32_t pthread_debug_tracing = 0;
#else
uint32_t pthread_debug_tracing = 1;
#endif
#ifdef __DARLING__
static lck_grp_attr_t the_real_pthread_lck_grp_attr;
static lck_grp_t the_real_pthread_lck_grp;
static lck_attr_t the_real_pthread_lck_attr;
static lck_mtx_t the_real_pthread_list_mlock;
lck_grp_attr_t* pthread_lck_grp_attr = &the_real_pthread_lck_grp_attr;
lck_grp_t* pthread_lck_grp = &the_real_pthread_lck_grp;
lck_attr_t* pthread_lck_attr = &the_real_pthread_lck_attr;
#else
lck_grp_attr_t *pthread_lck_grp_attr;
lck_grp_t *pthread_lck_grp;
lck_attr_t *pthread_lck_attr;
#endif
void
_pthread_init(void)
{
#ifdef __DARLING__
lck_grp_attr_setdefault(pthread_lck_grp_attr);
lck_grp_init(pthread_lck_grp, "pthread", pthread_lck_grp_attr);
lck_attr_setdefault(pthread_lck_attr);
pthread_list_mlock = &the_real_pthread_list_mlock;
lck_mtx_init(pthread_list_mlock, pthread_lck_grp, pthread_lck_attr);
#else
pthread_lck_grp_attr = lck_grp_attr_alloc_init();
pthread_lck_grp = lck_grp_alloc_init("pthread", pthread_lck_grp_attr);
/*
* allocate the lock attribute for pthread synchronizers
*/
pthread_lck_attr = lck_attr_alloc_init();
pthread_list_mlock = lck_mtx_alloc_init(pthread_lck_grp, pthread_lck_attr);
#endif
pth_global_hashinit();
psynch_thcall = thread_call_allocate(psynch_wq_cleanup, NULL);
psynch_zoneinit();
#ifndef __DARLING__
int policy_bootarg;
if (PE_parse_boot_argn("pthread_mutex_default_policy", &policy_bootarg, sizeof(policy_bootarg))) {
pthread_mutex_default_policy = policy_bootarg;
}
sysctl_register_oid(&sysctl__kern_pthread_mutex_default_policy);
#endif
}
// </copied>
/**
* stubbed functions
*/
/**
* nobody really needs this next set of functions right now,
* so we can just stub them for now
*/
int _bsdthread_create(proc_t p, user_addr_t user_func, user_addr_t user_funcarg, user_addr_t user_stack, user_addr_t user_pthread, uint32_t flags, user_addr_t* retval) {
return ENOTSUP;
};
int _bsdthread_register(proc_t p, user_addr_t threadstart, user_addr_t wqthread, int pthsize, user_addr_t dummy_value, user_addr_t targetconc_ptr, uint64_t dispatchqueue_offset, int32_t* retval) {
return ENOTSUP;
};
int _bsdthread_terminate(proc_t p, user_addr_t stackaddr, size_t size, uint32_t kthport, uint32_t sem, int32_t* retval) {
return ENOTSUP;
};
int _thread_selfid(proc_t p, uint64_t* retval) {
return ENOTSUP;
};
int _bsdthread_register2(proc_t p, user_addr_t threadstart, user_addr_t wqthread, uint32_t flags, user_addr_t stack_addr_hint, user_addr_t targetconc_ptr, uint32_t dispatchqueue_offset, uint32_t tsd_offset, int32_t* retval) {
return ENOTSUP;
};
/**
* now these are actually needed by `pthread_workqueue.c`
*/
int workq_handle_stack_events(proc_t p, thread_t th, vm_map_t map, user_addr_t stackaddr, mach_port_name_t kport, user_addr_t events, int nevents, int upcall_flags) {
return ENOTSUP;
};
int workq_create_threadstack(proc_t p, vm_map_t vmap, mach_vm_offset_t* out_addr) {
return ENOTSUP;
};
int workq_destroy_threadstack(proc_t p, vm_map_t vmap, mach_vm_offset_t stackaddr) {
return ENOTSUP;
};
void workq_setup_thread(proc_t p, thread_t th, vm_map_t map, user_addr_t stackaddr, mach_port_name_t kport, int th_qos, int setup_flags, int upcall_flags) {
};
void workq_markfree_threadstack(proc_t p, thread_t th, vm_map_t map, user_addr_t stackaddr) {
};

7
dthread/pthread_kext.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _DARLING_LKM_PTHREAD_KEXT_H_
#define _DARLING_LKM_PTHREAD_KEXT_H_
void darling_pthread_kext_init(void);
void darling_pthread_kext_exit(void);
#endif // _DARLING_LKM_PTHREAD_KEXT_H_

173
dthread/synch_internal.h Normal file
View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 2000-2013 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef __SYNCH_INTERNAL_H__
#define __SYNCH_INTERNAL_H__
// kwe_state
enum {
KWE_THREAD_INWAIT = 1,
KWE_THREAD_PREPOST,
KWE_THREAD_BROADCAST,
};
#define _PTHREAD_MTX_OPT_PSHARED 0x010
#define _PTHREAD_MTX_OPT_NOTIFY 0x1000 /* notify to drop mutex handling in cvwait */
#define _PTHREAD_MTX_OPT_MUTEX 0x2000 /* this is a mutex type */
#define PTHRW_COUNT_SHIFT 8
#define PTHRW_INC (1 << PTHRW_COUNT_SHIFT)
#define PTHRW_BIT_MASK ((1 << PTHRW_COUNT_SHIFT) - 1)
#define PTHRW_COUNT_MASK ((uint32_t)~PTHRW_BIT_MASK)
#define PTHRW_MAX_READERS PTHRW_COUNT_MASK
// L word
#define PTH_RWL_KBIT 0x01 // cannot acquire in user mode
#define PTH_RWL_EBIT 0x02 // exclusive lock in progress
#define PTH_RWL_WBIT 0x04 // write waiters pending in kernel
#define PTH_RWL_PBIT 0x04 // prepost (cv) pending in kernel
#define PTH_RWL_MTX_WAIT 0x20 // in cvar in mutex wait
#define PTH_RWL_UBIT 0x40 // lock is unlocked (no readers or writers)
#define PTH_RWL_MBIT 0x40 // overlapping grants from kernel (only in updateval)
#define PTH_RWL_IBIT 0x80 // lock reset, held until first successful unlock
#define PTHRW_RWL_INIT PTH_RWL_IBIT // reset on the lock bits (U)
#define PTHRW_RWLOCK_INIT (PTH_RWL_IBIT | PTH_RWL_UBIT) // reset on the lock bits (U)
// S word
#define PTH_RWS_SBIT 0x01 // kernel transition seq not set yet
#define PTH_RWS_IBIT 0x02 // Sequence is not set on return from kernel
#define PTH_RWS_CV_CBIT PTH_RWS_SBIT // kernel has cleared all info w.r.s.t CV
#define PTH_RWS_CV_PBIT PTH_RWS_IBIT // kernel has prepost/fake structs only,no waiters
#define PTH_RWS_CV_BITSALL (PTH_RWS_CV_CBIT | PTH_RWS_CV_PBIT)
#define PTH_RWS_CV_MBIT PTH_RWL_MBIT // to indicate prepost return from kernel
#define PTH_RWS_CV_RESET_PBIT ((uint32_t)~PTH_RWS_CV_PBIT)
#define PTH_RWS_WSVBIT 0x04 // save W bit
#define PTHRW_RWS_SAVEMASK (PTH_RWS_WSVBIT) // save bits mask
#define PTHRW_RWS_INIT PTH_RWS_SBIT // reset on the lock bits (U)
// rw_flags
#define PTHRW_KERN_PROCESS_SHARED 0x10
#define PTHRW_KERN_PROCESS_PRIVATE 0x20
#define PTHREAD_MTX_TID_SWITCHING (uint64_t)-1
// L word tests
#define is_rwl_ebit_set(x) (((x) & PTH_RWL_EBIT) != 0)
#define is_rwl_wbit_set(x) (((x) & PTH_RWL_WBIT) != 0)
#define is_rwl_ebit_clear(x) (((x) & PTH_RWL_EBIT) == 0)
#define is_rwl_readoverlap(x) (((x) & PTH_RWL_MBIT) != 0)
// S word tests
#define is_rws_sbit_set(x) (((x) & PTH_RWS_SBIT) != 0)
#define is_rws_unlockinit_set(x) (((x) & PTH_RWS_IBIT) != 0)
#define is_rws_savemask_set(x) (((x) & PTHRW_RWS_SAVEMASK) != 0)
#define is_rws_pbit_set(x) (((x) & PTH_RWS_CV_PBIT) != 0)
// kwe_flags
#define KWE_FLAG_LOCKPREPOST 0x1 // cvwait caused a lock prepost
static inline int
is_seqlower(uint32_t x, uint32_t y)
{
x &= PTHRW_COUNT_MASK;
y &= PTHRW_COUNT_MASK;
if (x < y) {
return ((y - x) < (PTHRW_MAX_READERS / 2));
} else {
return ((x - y) > (PTHRW_MAX_READERS / 2));
}
}
static inline int
is_seqlower_eq(uint32_t x, uint32_t y)
{
if ((x & PTHRW_COUNT_MASK) == (y & PTHRW_COUNT_MASK)) {
return 1;
} else {
return is_seqlower(x, y);
}
}
static inline int
is_seqhigher(uint32_t x, uint32_t y)
{
x &= PTHRW_COUNT_MASK;
y &= PTHRW_COUNT_MASK;
if (x > y) {
return ((x - y) < (PTHRW_MAX_READERS / 2));
} else {
return ((y - x) > (PTHRW_MAX_READERS / 2));
}
}
static inline int
is_seqhigher_eq(uint32_t x, uint32_t y)
{
if ((x & PTHRW_COUNT_MASK) == (y & PTHRW_COUNT_MASK)) {
return 1;
} else {
return is_seqhigher(x,y);
}
}
static inline int
diff_genseq(uint32_t x, uint32_t y)
{
x &= PTHRW_COUNT_MASK;
y &= PTHRW_COUNT_MASK;
if (x == y) {
return 0;
} else if (x > y) {
return x - y;
} else {
return ((PTHRW_MAX_READERS - y) + x + PTHRW_INC);
}
}
static inline int
find_diff(uint32_t upto, uint32_t lowest)
{
uint32_t diff;
if (upto == lowest)
return(0);
#if 0
diff = diff_genseq(upto, lowest);
#else
if (is_seqlower(upto, lowest) != 0)
diff = diff_genseq(lowest, upto);
else
diff = diff_genseq(upto, lowest);
#endif
diff = (diff >> PTHRW_COUNT_SHIFT);
return(diff);
}
#endif /* __SYNCH_INTERNAL_H__ */

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2014 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef DTHREAD_WORKQUEUE_INTERNAL_H // header name changed for Darling
#define DTHREAD_WORKQUEUE_INTERNAL_H
#ifdef __DARLING__
#include <pthread/workqueue_internal.h>
#endif
/* These definitions are shared between the kext and userspace inside the pthread project. Consolidating
* duplicate definitions that used to exist in both projects, when separate.
*/
// Sometimes something gets passed a bucket number and we need a way to express
// that it's actually the event manager. Use the (0)th bucket for that.
#define WORKQ_THREAD_QOS_MIN (THREAD_QOS_MAINTENANCE)
#define WORKQ_THREAD_QOS_MAX (THREAD_QOS_LAST - 1)
#define WORKQ_THREAD_QOS_CLEANUP (THREAD_QOS_LEGACY)
#define WORKQ_THREAD_QOS_MANAGER (THREAD_QOS_LAST) // outside of MIN/MAX
#define WORKQ_NUM_QOS_BUCKETS (WORKQ_THREAD_QOS_MAX)
#define WORKQ_NUM_BUCKETS (WORKQ_THREAD_QOS_MAX + 1)
#define WORKQ_IDX(qos) ((qos) - 1) // 0 based index
// magical `nkevents` values for _pthread_wqthread
#define WORKQ_EXIT_THREAD_NKEVENT (-1)
#endif // DTHREAD_WORKQUEUE_INTERNAL_H

View File

@ -1031,6 +1031,7 @@ task_reference(
kprintf("not implemented: task_reference()\n");
}
#if 0
/*
* This routine is called always with task lock held.
* And it returns a thread handle without reference as the caller
@ -1042,6 +1043,7 @@ task_findtid(task_t task, uint64_t tid)
kprintf("not implemented: task_findtid()\n");
return 0;
}
#endif
#if CONFIG_MACF_MACH

View File

@ -522,6 +522,7 @@ thread_static_param(
kprintf("not implemented: thread_static_param()\n");
}
#if 0
uint64_t
thread_tid(
thread_t thread)
@ -542,6 +543,7 @@ thread_get_tag(thread_t th)
kprintf("not implemented: thread_get_tag()\n");
return 0;
}
#endif
/*
uint64_t

View File

@ -40,4 +40,39 @@ assert_wait_queue(
return global_eventq(event);
}
wait_result_t
assert_wait_deadline_with_leeway(
event_t event,
wait_interrupt_t interruptible,
wait_timeout_urgency_t urgency,
uint64_t deadline,
uint64_t leeway)
{
thread_t thread = current_thread();
wait_result_t wresult;
spl_t s;
if (__improbable(event == NO_EVENT)) {
panic("%s() called with NO_EVENT", __func__);
}
struct waitq *waitq;
waitq = global_eventq(event);
s = splsched();
waitq_lock(waitq);
KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
MACHDBG_CODE(DBG_MACH_SCHED, MACH_WAIT) | DBG_FUNC_NONE,
VM_KERNEL_UNSLIDE_OR_PERM(event), interruptible, deadline, 0, 0);
wresult = waitq_assert_wait64_locked(waitq, CAST_EVENT64_T(event),
interruptible,
urgency, deadline, leeway,
thread);
waitq_unlock(waitq);
splx(s);
return wresult;
}
// </copied>

View File

@ -1309,4 +1309,44 @@ task_set_exc_guard_behavior(
return KERN_SUCCESS;
}
/*
* This routine finds a thread in a task by its unique id
* Returns a referenced thread or THREAD_NULL if the thread was not found
*
* TODO: This is super inefficient - it's an O(threads in task) list walk!
* We should make a tid hash, or transition all tid clients to thread ports
*
* Precondition: No locks held (will take task lock)
*/
thread_t
task_findtid(task_t task, uint64_t tid)
{
thread_t self = current_thread();
thread_t found_thread = THREAD_NULL;
thread_t iter_thread = THREAD_NULL;
/* Short-circuit the lookup if we're looking up ourselves */
if (tid == self->thread_id || tid == TID_NULL) {
assert(self->task == task);
thread_reference(self);
return self;
}
task_lock(task);
queue_iterate(&task->threads, iter_thread, thread_t, task_threads) {
if (iter_thread->thread_id == tid) {
found_thread = iter_thread;
thread_reference(found_thread);
break;
}
}
task_unlock(task);
return (found_thread);
}
// </copied>

View File

@ -899,6 +899,25 @@ thread_inspect_deallocate(
return thread_deallocate((thread_t)thread_inspect);
}
uint16_t
thread_set_tag(thread_t th, uint16_t tag)
{
return thread_set_tag_internal(th, tag);
}
uint16_t
thread_get_tag(thread_t th)
{
return thread_get_tag_internal(th);
}
uint64_t
thread_tid(
thread_t thread)
{
return thread != THREAD_NULL? thread->thread_id: 0;
}
// </copied>
#if THREAD_LOCK_DEBUG

View File

@ -98,10 +98,6 @@
#include <sys/cdefs.h>
#ifdef __DARLING__
#include <darling/pthread_internal.h>
#endif
#ifdef MACH_KERNEL_PRIVATE
#include <mach_assert.h>