#define C_32_STK_ALIGN 16
#define C_64_STK_ALIGN 16
-#define C_64_REDZONE_LEN 128
// WORKQ use the largest alignment any platform needs
#define C_WORKQ_STK_ALIGN 16
+#if defined(__arm64__)
+/* Pull the pthread_t into the same page as the top of the stack so we dirty one less page.
+ * <rdar://problem/19941744> The _pthread struct at the top of the stack shouldn't be page-aligned
+ */
+#define PTHREAD_T_OFFSET (12*1024)
+#else
#define PTHREAD_T_OFFSET 0
+#endif
/*
* Flags filed passed to bsdthread_create and back in pthread_start
mach_vm_offset_t stackaddr;
mach_vm_offset_t aslr_offset;
bool proc64bit = proc_is64bit(p);
+ bool proc64bit_data = proc_is64bit_data(p);
// We can't safely take random values % something unless its a power-of-two
_Static_assert(powerof2(PTH_DEFAULT_STACKSIZE), "PTH_DEFAULT_STACKSIZE is a power-of-two");
#if defined(__i386__) || defined(__x86_64__)
+ (void)proc64bit_data;
if (proc64bit) {
// Matches vm_map_get_max_aslr_slide_pages's image shift in xnu
aslr_offset = random() % (1 << 28); // about 512 stacks
stackaddr = SHARED_REGION_BASE_ARM64 - 64 * PTH_DEFAULT_STACKSIZE - aslr_offset;
} else {
// If you try to slide down from this point, you risk ending up in memory consumed by malloc
- stackaddr = SHARED_REGION_BASE_ARM - 32 * PTH_DEFAULT_STACKSIZE + aslr_offset;
+ if (proc64bit_data) {
+ stackaddr = SHARED_REGION_BASE_ARM64_32;
+ } else {
+ stackaddr = SHARED_REGION_BASE_ARM;
+ }
+
+ stackaddr -= 32 * PTH_DEFAULT_STACKSIZE + aslr_offset;
}
}
#else
.r8 = (uint64_t)user_stack, /* golang wants this */
.r9 = (uint64_t)flags,
- .rsp = (uint64_t)(user_stack - C_64_REDZONE_LEN)
+ .rsp = (uint64_t)user_stack,
};
(void)pthread_kern->thread_set_wq_state64(th, (thread_state_t)&state);
.edi = (uint32_t)user_stack, /* golang wants this */
.esi = (uint32_t)flags,
- .esp = (int)((vm_offset_t)(user_stack - C_32_STK_ALIGN))
+ .esp = (uint32_t)user_stack,
+ };
+
+ (void)pthread_kern->thread_set_wq_state32(th, (thread_state_t)&state);
+ }
+#elif defined(__arm__) || defined(__arm64__)
+ if (proc_is64bit_data(p)) {
+#ifdef __arm64__
+ arm_thread_state64_t state = {
+ .pc = (uint64_t)pthread_kern->proc_get_threadstart(p),
+ .x[0] = (uint64_t)user_pthread,
+ .x[1] = (uint64_t)th_thport,
+ .x[2] = (uint64_t)user_func, /* golang wants this */
+ .x[3] = (uint64_t)user_funcarg, /* golang wants this */
+ .x[4] = (uint64_t)user_stack, /* golang wants this */
+ .x[5] = (uint64_t)flags,
+
+ .sp = (uint64_t)user_stack,
+ };
+
+ (void)pthread_kern->thread_set_wq_state64(th, (thread_state_t)&state);
+#else
+ panic("Shouldn't have a 64-bit thread on a 32-bit kernel...");
+#endif // defined(__arm64__)
+ } else {
+ arm_thread_state_t state = {
+ .pc = (uint32_t)pthread_kern->proc_get_threadstart(p),
+ .r[0] = (uint32_t)user_pthread,
+ .r[1] = (uint32_t)th_thport,
+ .r[2] = (uint32_t)user_func, /* golang wants this */
+ .r[3] = (uint32_t)user_funcarg, /* golang wants this */
+ .r[4] = (uint32_t)user_stack, /* golang wants this */
+ .r[5] = (uint32_t)flags,
+
+ .sp = (uint32_t)user_stack,
};
(void)pthread_kern->thread_set_wq_state32(th, (thread_state_t)&state);
panic(__func__ ": thread_set_wq_state failed: %d", error);
}
}
+#elif defined(__arm__) || defined(__arm64__)
+ if (!proc_is64bit_data(p)) {
+ arm_thread_state_t state = {
+ .pc = (int)wqstart_fnptr,
+ .r[0] = (unsigned int)addrs->self,
+ .r[1] = (unsigned int)kport,
+ .r[2] = (unsigned int)addrs->stack_bottom,
+ .r[3] = (unsigned int)kevent_list,
+ // will be pushed onto the stack as arg4/5
+ .r[4] = (unsigned int)upcall_flags,
+ .r[5] = (unsigned int)kevent_count,
+
+ .sp = (int)(addrs->stack_top)
+ };
+
+ int error = pthread_kern->thread_set_wq_state32(th, (thread_state_t)&state);
+ if (error != KERN_SUCCESS) {
+ panic(__func__ ": thread_set_wq_state failed: %d", error);
+ }
+ } else {
+#if defined(__arm64__)
+ arm_thread_state64_t state = {
+ .pc = (uint64_t)wqstart_fnptr,
+ .x[0] = (uint64_t)addrs->self,
+ .x[1] = (uint64_t)kport,
+ .x[2] = (uint64_t)addrs->stack_bottom,
+ .x[3] = (uint64_t)kevent_list,
+ .x[4] = (uint64_t)upcall_flags,
+ .x[5] = (uint64_t)kevent_count,
+
+ .sp = (uint64_t)((vm_offset_t)addrs->stack_top),
+ };
+
+ int error = pthread_kern->thread_set_wq_state64(th, (thread_state_t)&state);
+ if (error != KERN_SUCCESS) {
+ panic(__func__ ": thread_set_wq_state failed: %d", error);
+ }
+#else /* defined(__arm64__) */
+ panic("Shouldn't have a 64-bit thread on a 32-bit kernel...");
+#endif /* defined(__arm64__) */
+ }
#else
#error setup_wqthread not defined for this architecture
#endif
}
-static int
-workq_kevent(proc_t p, struct workq_thread_addrs *th_addrs, int upcall_flags,
+static inline int
+workq_kevent(proc_t p, struct workq_thread_addrs *th_addrs,
user_addr_t eventlist, int nevents, int kevent_flags,
user_addr_t *kevent_list_out, int *kevent_count_out)
{
- bool workloop = upcall_flags & WQ_FLAG_THREAD_WORKLOOP;
- int kevent_count = WQ_KEVENT_LIST_LEN;
- user_addr_t kevent_list = th_addrs->self - WQ_KEVENT_LIST_LEN * sizeof(struct kevent_qos_s);
- user_addr_t kevent_id_addr = kevent_list;
- kqueue_id_t kevent_id = -1;
int ret;
- if (workloop) {
- /*
- * The kevent ID goes just below the kevent list. Sufficiently new
- * userspace will know to look there. Old userspace will just
- * ignore it.
- */
- kevent_id_addr -= sizeof(kqueue_id_t);
- }
+ user_addr_t kevent_list = th_addrs->self -
+ WQ_KEVENT_LIST_LEN * sizeof(struct kevent_qos_s);
+ user_addr_t data_buf = kevent_list - WQ_KEVENT_DATA_SIZE;
+ user_size_t data_available = WQ_KEVENT_DATA_SIZE;
- user_addr_t kevent_data_buf = kevent_id_addr - WQ_KEVENT_DATA_SIZE;
- user_size_t kevent_data_available = WQ_KEVENT_DATA_SIZE;
-
- if (workloop) {
- kevent_flags |= KEVENT_FLAG_WORKLOOP;
- ret = kevent_id_internal(p, &kevent_id,
- eventlist, nevents, kevent_list, kevent_count,
- kevent_data_buf, &kevent_data_available,
- kevent_flags, &kevent_count);
- copyout(&kevent_id, kevent_id_addr, sizeof(kevent_id));
- } else {
- kevent_flags |= KEVENT_FLAG_WORKQ;
- ret = kevent_qos_internal(p, -1, eventlist, nevents, kevent_list,
- kevent_count, kevent_data_buf, &kevent_data_available,
- kevent_flags, &kevent_count);
- }
+ ret = pthread_kern->kevent_workq_internal(p, eventlist, nevents,
+ kevent_list, WQ_KEVENT_LIST_LEN,
+ data_buf, &data_available,
+ kevent_flags, kevent_count_out);
// squash any errors into just empty output
- if (ret != 0 || kevent_count == -1) {
+ if (ret != 0 || *kevent_count_out == -1) {
*kevent_list_out = NULL;
*kevent_count_out = 0;
return ret;
}
- if (kevent_data_available == WQ_KEVENT_DATA_SIZE) {
- workq_thread_set_top_addr(th_addrs, kevent_id_addr);
- } else {
- workq_thread_set_top_addr(th_addrs,
- kevent_data_buf + kevent_data_available);
- }
- *kevent_count_out = kevent_count;
+ workq_thread_set_top_addr(th_addrs, data_buf + data_available);
*kevent_list_out = kevent_list;
return ret;
}
* |pthread_t | th_stackaddr + DEFAULT_STACKSIZE + guardsize + PTHREAD_STACK_OFFSET
* |kevent list| optionally - at most WQ_KEVENT_LIST_LEN events
* |kevent data| optionally - at most WQ_KEVENT_DATA_SIZE bytes
- * |stack gap | bottom aligned to 16 bytes, and at least as big as stack_gap_min
+ * |stack gap | bottom aligned to 16 bytes
* | STACK |
* | ⇓ |
* | |
kevent_count = WORKQ_EXIT_THREAD_NKEVENT;
} else if (upcall_flags & WQ_FLAG_THREAD_KEVENT) {
unsigned int flags = KEVENT_FLAG_STACK_DATA | KEVENT_FLAG_IMMEDIATE;
- workq_kevent(p, &th_addrs, upcall_flags, NULL, 0, flags,
- &kevent_list, &kevent_count);
+ workq_kevent(p, &th_addrs, NULL, 0, flags, &kevent_list, &kevent_count);
}
workq_set_register_state(p, th, &th_addrs, kport,
unsigned int flags = KEVENT_FLAG_STACK_DATA | KEVENT_FLAG_IMMEDIATE |
KEVENT_FLAG_PARKING;
- error = workq_kevent(p, &th_addrs, upcall_flags, events, nevents, flags,
+ error = workq_kevent(p, &th_addrs, events, nevents, flags,
&kevent_list, &kevent_count);
if (error || kevent_count == 0) {
#define KW_UNLOCK_PREPOST_READLOCK 0x08
#define KW_UNLOCK_PREPOST_WRLOCK 0x20
-static int ksyn_wq_hash_lookup(user_addr_t uaddr, proc_t p, int flags, ksyn_wait_queue_t *kwq, struct pthhashhead **hashptr, uint64_t *object, uint64_t *offset);
+static int ksyn_wq_hash_lookup(user_addr_t uaddr, proc_t p, int flags, ksyn_wait_queue_t *kwq, struct pthhashhead **hashptr, uint64_t object, uint64_t offset);
static int ksyn_wqfind(user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint32_t rw_wc, int flags, int wqtype , ksyn_wait_queue_t *wq);
static void ksyn_wqrelease(ksyn_wait_queue_t mkwq, int qfreenow, int wqtype);
static int ksyn_findobj(user_addr_t uaddr, uint64_t *objectp, uint64_t *offsetp);
static void
pthread_list_lock(void)
{
- lck_mtx_lock(pthread_list_mlock);
+ lck_mtx_lock_spin(pthread_list_mlock);
}
static void
static int
ksyn_wq_hash_lookup(user_addr_t uaddr, proc_t p, int flags,
ksyn_wait_queue_t *out_kwq, struct pthhashhead **out_hashptr,
- uint64_t *out_object, uint64_t *out_offset)
+ uint64_t object, uint64_t offset)
{
int res = 0;
ksyn_wait_queue_t kwq;
- uint64_t object = 0, offset = 0;
struct pthhashhead *hashptr;
if ((flags & PTHREAD_PSHARED_FLAGS_MASK) == PTHREAD_PROCESS_SHARED) {
hashptr = pth_glob_hashtbl;
- res = ksyn_findobj(uaddr, &object, &offset);
- if (res == 0) {
- LIST_FOREACH(kwq, &hashptr[object & pthhash], kw_hash) {
- if (kwq->kw_object == object && kwq->kw_offset == offset) {
- break;
- }
+ LIST_FOREACH(kwq, &hashptr[object & pthhash], kw_hash) {
+ if (kwq->kw_object == object && kwq->kw_offset == offset) {
+ break;
}
- } else {
- kwq = NULL;
}
} else {
hashptr = pthread_kern->proc_get_pthhash(p);
}
}
*out_kwq = kwq;
- *out_object = object;
- *out_offset = offset;
*out_hashptr = hashptr;
return res;
}
while (res == 0) {
pthread_list_lock();
res = ksyn_wq_hash_lookup(uaddr, current_proc(), flags, &kwq, &hashptr,
- &object, &offset);
+ object, offset);
if (res != 0) {
pthread_list_unlock();
break;
name = Tests;
productName = Tests;
};
+ C900AEA7215AF7170011B58C /* Introspection */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = C900AEAA215AF7170011B58C /* Build configuration list for PBXAggregateTarget "Introspection" */;
+ buildPhases = (
+ );
+ dependencies = (
+ C900AEAE215AF7290011B58C /* PBXTargetDependency */,
+ );
+ name = Introspection;
+ productName = Introspection;
+ };
C90E7AAC15DC3D3300A06D48 /* All */ = {
isa = PBXAggregateTarget;
buildConfigurationList = C90E7AAD15DC3D3300A06D48 /* Build configuration list for PBXAggregateTarget "All" */;
buildPhases = (
);
dependencies = (
- 6E8C16821B14F11800C8987C /* PBXTargetDependency */,
C90E7AB015DC3D3D00A06D48 /* PBXTargetDependency */,
C04545BC1C58510F006A53B3 /* PBXTargetDependency */,
C90E7AB215DC3D3D00A06D48 /* PBXTargetDependency */,
buildPhases = (
);
dependencies = (
- 6E8C16841B14F11B00C8987C /* PBXTargetDependency */,
C98832C615DEB44B00B3308E /* PBXTargetDependency */,
C04545BE1C585487006A53B3 /* PBXTargetDependency */,
C98832C815DEB44B00B3308E /* PBXTargetDependency */,
name = Embedded;
productName = Embedded;
};
+ E4B7FCA822000AF50010A840 /* libpthread_driverkit */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = E4B7FCAF22000AF50010A840 /* Build configuration list for PBXAggregateTarget "libpthread_driverkit" */;
+ buildPhases = (
+ );
+ dependencies = (
+ E4B7FCA922000AF50010A840 /* PBXTargetDependency */,
+ );
+ name = libpthread_driverkit;
+ productName = All;
+ };
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
6E8C16601B14F08A00C8987C /* pthread_cond_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5D615C9CECA0098ECD8 /* pthread_cond_legacy.c */; };
6E8C16611B14F08A00C8987C /* pthread_mutex_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5D815C9CEEA0098ECD8 /* pthread_mutex_legacy.c */; };
6E8C16621B14F08A00C8987C /* pthread_rwlock_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DA15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c */; };
- 6E8C16631B14F08A00C8987C /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
- 6E8C16641B14F08A00C8987C /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
6E8C16651B14F08A00C8987C /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
6E8C16661B14F08A00C8987C /* pthread_asm.s in Sources */ = {isa = PBXBuildFile; fileRef = C99AD87D15DF04D10009A6F8 /* pthread_asm.s */; };
6E8C16691B14F08A00C8987C /* qos.h in Headers */ = {isa = PBXBuildFile; fileRef = C9244C1A185FCFED00075748 /* qos.h */; };
74E594951613AAF4006C417B /* pthread_cond.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F215B7513200270056 /* pthread_cond.c */; };
74E594961613AAF4006C417B /* pthread_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F515B7513200270056 /* pthread_mutex.c */; };
74E594971613AAF4006C417B /* pthread_rwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F615B7513200270056 /* pthread_rwlock.c */; };
- 74E594981613AAF4006C417B /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
74E594991613AAF4006C417B /* pthread_tsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F815B7513200270056 /* pthread_tsd.c */; };
- 74E5949A1613AAF4006C417B /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
74E5949C1613AAF4006C417B /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
74E5949E1613AAF4006C417B /* pthread_asm.s in Sources */ = {isa = PBXBuildFile; fileRef = C99AD87D15DF04D10009A6F8 /* pthread_asm.s */; };
74E594A61613AB10006C417B /* pthread_cancelable_cancel.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A1BF5215C9A9F5006BB313 /* pthread_cancelable_cancel.c */; };
C04545A81C584F4A006A53B3 /* pthread_cond.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F215B7513200270056 /* pthread_cond.c */; };
C04545A91C584F4A006A53B3 /* pthread_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F515B7513200270056 /* pthread_mutex.c */; };
C04545AB1C584F4A006A53B3 /* pthread_rwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F615B7513200270056 /* pthread_rwlock.c */; };
- C04545AC1C584F4A006A53B3 /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
C04545AD1C584F4A006A53B3 /* pthread_tsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F815B7513200270056 /* pthread_tsd.c */; };
- C04545AE1C584F4A006A53B3 /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
C04545AF1C584F4A006A53B3 /* qos.c in Sources */ = {isa = PBXBuildFile; fileRef = C9244C1C1860D8EF00075748 /* qos.c */; };
C04545B01C584F4A006A53B3 /* pthread_cwd.c in Sources */ = {isa = PBXBuildFile; fileRef = 924D8EDE1C11832A002AC2BC /* pthread_cwd.c */; };
C04545B11C584F4A006A53B3 /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
C90E7AA615DC3C9D00A06D48 /* pthread_cond.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F215B7513200270056 /* pthread_cond.c */; };
C90E7AA715DC3C9D00A06D48 /* pthread_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F515B7513200270056 /* pthread_mutex.c */; };
C90E7AA815DC3C9D00A06D48 /* pthread_rwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F615B7513200270056 /* pthread_rwlock.c */; };
- C90E7AA915DC3C9D00A06D48 /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
C90E7AAA15DC3C9D00A06D48 /* pthread_tsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F815B7513200270056 /* pthread_tsd.c */; };
- C90E7AAB15DC3C9D00A06D48 /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
C90E7AB815DC40D900A06D48 /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
C90E7AB915DC40D900A06D48 /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
C9153096167ACC2B006BB094 /* private.h in Headers */ = {isa = PBXBuildFile; fileRef = C9153095167ACC22006BB094 /* private.h */; settings = {ATTRIBUTES = (Private, ); }; };
C9244C1D1860D8EF00075748 /* qos.c in Sources */ = {isa = PBXBuildFile; fileRef = C9244C1C1860D8EF00075748 /* qos.c */; };
C9244C1E1860D96D00075748 /* qos.c in Sources */ = {isa = PBXBuildFile; fileRef = C9244C1C1860D8EF00075748 /* qos.c */; };
C9244C1F1860D96E00075748 /* qos.c in Sources */ = {isa = PBXBuildFile; fileRef = C9244C1C1860D8EF00075748 /* qos.c */; };
- C948FCF715D1D1E100180BF5 /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
C975D5D715C9CECA0098ECD8 /* pthread_cond_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5D615C9CECA0098ECD8 /* pthread_cond_legacy.c */; };
C975D5D915C9CEEA0098ECD8 /* pthread_mutex_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5D815C9CEEA0098ECD8 /* pthread_mutex_legacy.c */; };
C975D5DB15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DA15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c */; };
- C975D5DD15C9D16B0098ECD8 /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
C98C95D918FF1F4E005654FB /* spawn.h in Headers */ = {isa = PBXBuildFile; fileRef = C98C95D818FF1F4E005654FB /* spawn.h */; settings = {ATTRIBUTES = (Public, ); }; };
C99AD87B15DEC4BC0009A6F8 /* posix_sched.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A325F015B7513200270056 /* posix_sched.h */; settings = {ATTRIBUTES = (Private, ); }; };
C99AD87C15DEC5290009A6F8 /* spinlock_private.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A325F715B7513200270056 /* spinlock_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
- C99AD87F15DF04D10009A6F8 /* pthread_asm.s in Sources */ = {isa = PBXBuildFile; fileRef = C99AD87D15DF04D10009A6F8 /* pthread_asm.s */; };
C99AD88015E2D8B50009A6F8 /* pthread_asm.s in Sources */ = {isa = PBXBuildFile; fileRef = C99AD87D15DF04D10009A6F8 /* pthread_asm.s */; };
C9A1BF4715C9A578006BB313 /* pthread.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FA15B7513200270056 /* pthread.c */; };
C9A1BF4815C9A578006BB313 /* pthread_cancelable.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F115B7513200270056 /* pthread_cancelable.c */; };
E41505D61E818BEB00F243FB /* pthread_cond.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F215B7513200270056 /* pthread_cond.c */; };
E41505D71E818BEB00F243FB /* pthread_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F515B7513200270056 /* pthread_mutex.c */; };
E41505D91E818BEB00F243FB /* pthread_rwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F615B7513200270056 /* pthread_rwlock.c */; };
- E41505DA1E818BEB00F243FB /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
E41505DB1E818BEB00F243FB /* pthread_tsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F815B7513200270056 /* pthread_tsd.c */; };
- E41505DC1E818BEB00F243FB /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
E41505DD1E818BEB00F243FB /* qos.c in Sources */ = {isa = PBXBuildFile; fileRef = C9244C1C1860D8EF00075748 /* qos.c */; };
E41505DE1E818BEB00F243FB /* pthread_cwd.c in Sources */ = {isa = PBXBuildFile; fileRef = 924D8EDE1C11832A002AC2BC /* pthread_cwd.c */; };
E41505DF1E818BEB00F243FB /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
E4F449921E82C1F000A7FB9A /* pthread_cond.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F215B7513200270056 /* pthread_cond.c */; };
E4F449931E82C1F000A7FB9A /* pthread_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F515B7513200270056 /* pthread_mutex.c */; };
E4F449941E82C1F000A7FB9A /* pthread_rwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F615B7513200270056 /* pthread_rwlock.c */; };
- E4F449951E82C1F000A7FB9A /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
E4F449961E82C1F000A7FB9A /* pthread_tsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F815B7513200270056 /* pthread_tsd.c */; };
- E4F449971E82C1F000A7FB9A /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
E4F449981E82C1F000A7FB9A /* qos.c in Sources */ = {isa = PBXBuildFile; fileRef = C9244C1C1860D8EF00075748 /* qos.c */; };
E4F449991E82C1F000A7FB9A /* pthread_cwd.c in Sources */ = {isa = PBXBuildFile; fileRef = 924D8EDE1C11832A002AC2BC /* pthread_cwd.c */; };
E4F4499A1E82C1F000A7FB9A /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
E4F449B51E82D03500A7FB9A /* pthread_cond_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5D615C9CECA0098ECD8 /* pthread_cond_legacy.c */; };
E4F449B61E82D03500A7FB9A /* pthread_mutex_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5D815C9CEEA0098ECD8 /* pthread_mutex_legacy.c */; };
E4F449B71E82D03500A7FB9A /* pthread_rwlock_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DA15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c */; };
- E4F449B81E82D03500A7FB9A /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
- E4F449B91E82D03500A7FB9A /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
E4F449BA1E82D03500A7FB9A /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
E4F449BB1E82D03500A7FB9A /* pthread_asm.s in Sources */ = {isa = PBXBuildFile; fileRef = C99AD87D15DF04D10009A6F8 /* pthread_asm.s */; };
E4F449BE1E82D03500A7FB9A /* qos.h in Headers */ = {isa = PBXBuildFile; fileRef = C9244C1A185FCFED00075748 /* qos.h */; settings = {ATTRIBUTES = (Public, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- 6E8C16811B14F11800C8987C /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = C9A325D915B7347000270056 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 6E8C16511B14F08A00C8987C;
- remoteInfo = "libsystem_pthread.dylib introspection";
- };
- 6E8C16831B14F11B00C8987C /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = C9A325D915B7347000270056 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 6E8C16511B14F08A00C8987C;
- remoteInfo = "libsystem_pthread.dylib introspection";
- };
74E594AA1613AD7F006C417B /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C9A325D915B7347000270056 /* Project object */;
remoteGlobalIDString = C04545A21C584F4A006A53B3;
remoteInfo = "libpthread.a generic";
};
+ C900AEAD215AF7290011B58C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9A325D915B7347000270056 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 6E8C16511B14F08A00C8987C;
+ remoteInfo = "libsystem_pthread introspection";
+ };
C90E7AAF15DC3D3D00A06D48 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C9A325D915B7347000270056 /* Project object */;
remoteGlobalIDString = C90E7A9E15DC3C3800A06D48;
remoteInfo = libpthread.a;
};
+ E4B7FCAA22000AF50010A840 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9A325D915B7347000270056 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C9A325E115B7347000270056;
+ remoteInfo = Libpthread;
+ };
E4F4498A1E825D2B00A7FB9A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C9A325D915B7347000270056 /* Project object */;
C975D5D615C9CECA0098ECD8 /* pthread_cond_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_cond_legacy.c; sourceTree = "<group>"; };
C975D5D815C9CEEA0098ECD8 /* pthread_mutex_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_mutex_legacy.c; sourceTree = "<group>"; };
C975D5DA15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_rwlock_legacy.c; sourceTree = "<group>"; };
- C975D5DC15C9D16B0098ECD8 /* pthread_support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_support.c; sourceTree = "<group>"; };
C979E9FB18A1BC2A000951E5 /* kern_trace.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = kern_trace.h; sourceTree = "<group>"; };
C979E9FC18A2BF2C000951E5 /* install-codes.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "install-codes.sh"; sourceTree = "<group>"; };
C98005141899BD2000368E4D /* workqueue_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = workqueue_internal.h; sourceTree = "<group>"; };
C9A325F815B7513200270056 /* pthread_tsd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_tsd.c; sourceTree = "<group>"; };
C9A325F915B7513200270056 /* workqueue_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = workqueue_private.h; sourceTree = "<group>"; };
C9A325FA15B7513200270056 /* pthread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread.c; sourceTree = "<group>"; };
- C9A325FC15B7513200270056 /* thread_setup.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = thread_setup.c; sourceTree = "<group>"; };
C9A325FE15B7513700270056 /* pthread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pthread.h; sourceTree = "<group>"; };
C9A325FF15B7513700270056 /* pthread_impl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pthread_impl.h; sourceTree = "<group>"; };
C9A3260015B7513700270056 /* pthread_spis.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pthread_spis.h; sourceTree = "<group>"; };
C9A325F515B7513200270056 /* pthread_mutex.c */,
6E5869CA20C9043200F1CB75 /* pthread_dependency.c */,
C9A325F615B7513200270056 /* pthread_rwlock.c */,
- C975D5DC15C9D16B0098ECD8 /* pthread_support.c */,
C9A325F815B7513200270056 /* pthread_tsd.c */,
C9244C1C1860D8EF00075748 /* qos.c */,
- C9A325FC15B7513200270056 /* thread_setup.c */,
E4943AAA1E80BE1F00D2A961 /* resolver */,
C9A1BF5115C9A8B7006BB313 /* variants */,
);
C90E7A9B15DC3C3800A06D48 /* Sources */,
C90E7A9C15DC3C3800A06D48 /* Frameworks */,
C90E7A9D15DC3C3800A06D48 /* Headers */,
- C04545891C5844F8006A53B3 /* Symlink libpthread_dyld.a to libpthread.a */,
);
buildRules = (
);
C9A325D915B7347000270056 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0900;
+ LastUpgradeCheck = 1100;
ORGANIZATIONNAME = "";
TargetAttributes = {
92799B441B96A5FD00861404 = {
C91D01B5162892FF0002E29A /* Kext */,
C98832C115DEB44000B3308E /* Embedded */,
92799B441B96A5FD00861404 /* Tests */,
+ C900AEA7215AF7170011B58C /* Introspection */,
+ E4B7FCA822000AF50010A840 /* libpthread_driverkit */,
C9A325E115B7347000270056 /* libsystem_pthread */,
E4F449A41E82D03500A7FB9A /* libsystem_pthread noresolver */,
6E8C16511B14F08A00C8987C /* libsystem_pthread introspection */,
shellScript = "dtrace -h -C -s \"${SCRIPT_INPUT_FILE_0}\" -o \"${SCRIPT_OUTPUT_FILE_0}\"";
showEnvVarsInLog = 0;
};
- C04545891C5844F8006A53B3 /* Symlink libpthread_dyld.a to libpthread.a */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 8;
- files = (
- );
- inputPaths = (
- "$(SRCROOT)/xcodescripts/run-on-install.sh",
- );
- name = "Symlink libpthread_dyld.a to libpthread.a";
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 1;
- shellPath = "/bin/bash -e -x";
- shellScript = ". \"${SCRIPT_INPUT_FILE_0}\" /bin/ln -sf libpthread_dyld.a \"${DSTROOT}${INSTALL_PATH}/libpthread.a\"";
- showEnvVarsInLog = 0;
- };
C04545BA1C585034006A53B3 /* Symlink libpthread.a to the loaderd path */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = "/bin/bash -e -x";
- shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-codes.sh";
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-codes.sh\n";
showEnvVarsInLog = 0;
};
C9A960B518452C1800AE10C8 /* Install lldbmacros */ = {
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/bin/bash -e -x";
- shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-lldbmacros.sh";
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-lldbmacros.sh\n";
showEnvVarsInLog = 0;
};
C9D70EBD167AC76700D52713 /* Symlink Old Header Location */ = {
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = "/bin/bash -e -x";
- shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-symlinks.sh";
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-symlinks.sh\n";
showEnvVarsInLog = 0;
};
C9DCA2A215DC4F3500D057E2 /* Install Manpages */ = {
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = "/bin/bash -e -x";
- shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-manpages.sh";
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-manpages.sh\n";
showEnvVarsInLog = 0;
};
E41505E31E818BEB00F243FB /* Symlink normal variant */ = {
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = "/bin/bash -e -x";
- shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-sys-headers.sh";
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-sys-headers.sh\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
6E8C16601B14F08A00C8987C /* pthread_cond_legacy.c in Sources */,
6E8C16611B14F08A00C8987C /* pthread_mutex_legacy.c in Sources */,
6E8C16621B14F08A00C8987C /* pthread_rwlock_legacy.c in Sources */,
- 6E8C16631B14F08A00C8987C /* pthread_support.c in Sources */,
- 6E8C16641B14F08A00C8987C /* thread_setup.c in Sources */,
6E8C16651B14F08A00C8987C /* pthread_atfork.c in Sources */,
6E5869CD20C9043B00F1CB75 /* pthread_dependency.c in Sources */,
6E8C16661B14F08A00C8987C /* pthread_asm.s in Sources */,
74E594951613AAF4006C417B /* pthread_cond.c in Sources */,
74E594961613AAF4006C417B /* pthread_mutex.c in Sources */,
74E594971613AAF4006C417B /* pthread_rwlock.c in Sources */,
- 74E594981613AAF4006C417B /* pthread_support.c in Sources */,
74E594991613AAF4006C417B /* pthread_tsd.c in Sources */,
- 74E5949A1613AAF4006C417B /* thread_setup.c in Sources */,
C9244C1F1860D96E00075748 /* qos.c in Sources */,
924D8EDF1C11833D002AC2BC /* pthread_cwd.c in Sources */,
74E5949C1613AAF4006C417B /* pthread_atfork.c in Sources */,
C04545A81C584F4A006A53B3 /* pthread_cond.c in Sources */,
C04545A91C584F4A006A53B3 /* pthread_mutex.c in Sources */,
C04545AB1C584F4A006A53B3 /* pthread_rwlock.c in Sources */,
- C04545AC1C584F4A006A53B3 /* pthread_support.c in Sources */,
C04545AD1C584F4A006A53B3 /* pthread_tsd.c in Sources */,
- C04545AE1C584F4A006A53B3 /* thread_setup.c in Sources */,
C04545AF1C584F4A006A53B3 /* qos.c in Sources */,
C04545B01C584F4A006A53B3 /* pthread_cwd.c in Sources */,
C04545B11C584F4A006A53B3 /* pthread_atfork.c in Sources */,
C90E7AA715DC3C9D00A06D48 /* pthread_mutex.c in Sources */,
6E5869D120C9043D00F1CB75 /* pthread_dependency.c in Sources */,
C90E7AA815DC3C9D00A06D48 /* pthread_rwlock.c in Sources */,
- C90E7AA915DC3C9D00A06D48 /* pthread_support.c in Sources */,
C90E7AAA15DC3C9D00A06D48 /* pthread_tsd.c in Sources */,
- C90E7AAB15DC3C9D00A06D48 /* thread_setup.c in Sources */,
924D8EE01C11833D002AC2BC /* pthread_cwd.c in Sources */,
C90E7AB915DC40D900A06D48 /* pthread_atfork.c in Sources */,
- C99AD87F15DF04D10009A6F8 /* pthread_asm.s in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C975D5D715C9CECA0098ECD8 /* pthread_cond_legacy.c in Sources */,
C975D5D915C9CEEA0098ECD8 /* pthread_mutex_legacy.c in Sources */,
C975D5DB15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c in Sources */,
- C975D5DD15C9D16B0098ECD8 /* pthread_support.c in Sources */,
- C948FCF715D1D1E100180BF5 /* thread_setup.c in Sources */,
C90E7AB815DC40D900A06D48 /* pthread_atfork.c in Sources */,
6E5869CB20C9043200F1CB75 /* pthread_dependency.c in Sources */,
C99AD88015E2D8B50009A6F8 /* pthread_asm.s in Sources */,
E41505D61E818BEB00F243FB /* pthread_cond.c in Sources */,
E41505D71E818BEB00F243FB /* pthread_mutex.c in Sources */,
E41505D91E818BEB00F243FB /* pthread_rwlock.c in Sources */,
- E41505DA1E818BEB00F243FB /* pthread_support.c in Sources */,
E41505DB1E818BEB00F243FB /* pthread_tsd.c in Sources */,
- E41505DC1E818BEB00F243FB /* thread_setup.c in Sources */,
E41505DD1E818BEB00F243FB /* qos.c in Sources */,
E41505DE1E818BEB00F243FB /* pthread_cwd.c in Sources */,
E41505DF1E818BEB00F243FB /* pthread_atfork.c in Sources */,
E4F449921E82C1F000A7FB9A /* pthread_cond.c in Sources */,
E4F449931E82C1F000A7FB9A /* pthread_mutex.c in Sources */,
E4F449941E82C1F000A7FB9A /* pthread_rwlock.c in Sources */,
- E4F449951E82C1F000A7FB9A /* pthread_support.c in Sources */,
E4F449961E82C1F000A7FB9A /* pthread_tsd.c in Sources */,
- E4F449971E82C1F000A7FB9A /* thread_setup.c in Sources */,
E4F449981E82C1F000A7FB9A /* qos.c in Sources */,
E4F449991E82C1F000A7FB9A /* pthread_cwd.c in Sources */,
E4F4499A1E82C1F000A7FB9A /* pthread_atfork.c in Sources */,
E4F449B51E82D03500A7FB9A /* pthread_cond_legacy.c in Sources */,
E4F449B61E82D03500A7FB9A /* pthread_mutex_legacy.c in Sources */,
E4F449B71E82D03500A7FB9A /* pthread_rwlock_legacy.c in Sources */,
- E4F449B81E82D03500A7FB9A /* pthread_support.c in Sources */,
- E4F449B91E82D03500A7FB9A /* thread_setup.c in Sources */,
E4F449BA1E82D03500A7FB9A /* pthread_atfork.c in Sources */,
6E5869CC20C9043B00F1CB75 /* pthread_dependency.c in Sources */,
E4F449BB1E82D03500A7FB9A /* pthread_asm.s in Sources */,
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
- 6E8C16821B14F11800C8987C /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 6E8C16511B14F08A00C8987C /* libsystem_pthread introspection */;
- targetProxy = 6E8C16811B14F11800C8987C /* PBXContainerItemProxy */;
- };
- 6E8C16841B14F11B00C8987C /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 6E8C16511B14F08A00C8987C /* libsystem_pthread introspection */;
- targetProxy = 6E8C16831B14F11B00C8987C /* PBXContainerItemProxy */;
- };
74E594AB1613AD7F006C417B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 74E594911613AAF4006C417B /* libpthread eOS */;
target = C04545A21C584F4A006A53B3 /* libpthread generic */;
targetProxy = C04545BD1C585487006A53B3 /* PBXContainerItemProxy */;
};
+ C900AEAE215AF7290011B58C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 6E8C16511B14F08A00C8987C /* libsystem_pthread introspection */;
+ targetProxy = C900AEAD215AF7290011B58C /* PBXContainerItemProxy */;
+ };
C90E7AB015DC3D3D00A06D48 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C9A325E115B7347000270056 /* libsystem_pthread */;
target = C90E7A9E15DC3C3800A06D48 /* libpthread dyld */;
targetProxy = C98832C715DEB44B00B3308E /* PBXContainerItemProxy */;
};
+ E4B7FCA922000AF50010A840 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C9A325E115B7347000270056 /* libsystem_pthread */;
+ targetProxy = E4B7FCAA22000AF50010A840 /* PBXContainerItemProxy */;
+ };
E4F4498B1E825D2B00A7FB9A /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = E41505D01E818BEB00F243FB /* libpthread mp resolved */;
};
name = Release;
};
+ C900AEAB215AF7170011B58C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ C900AEAC215AF7170011B58C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Debug;
+ };
C90E7AA015DC3C3800A06D48 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = C04545B91C584F8B006A53B3 /* static.xcconfig */;
};
name = Debug;
};
+ E4B7FCB022000AF50010A840 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ E4B7FCB122000AF50010A840 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
E4F4499E1E82C1F000A7FB9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E41505E81E818D4D00F243FB /* resolved.xcconfig */;
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ C900AEAA215AF7170011B58C /* Build configuration list for PBXAggregateTarget "Introspection" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C900AEAB215AF7170011B58C /* Release */,
+ C900AEAC215AF7170011B58C /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
C90E7AA115DC3C3800A06D48 /* Build configuration list for PBXNativeTarget "libpthread dyld" */ = {
isa = XCConfigurationList;
buildConfigurations = (
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ E4B7FCAF22000AF50010A840 /* Build configuration list for PBXAggregateTarget "libpthread_driverkit" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ E4B7FCB022000AF50010A840 /* Release */,
+ E4B7FCB122000AF50010A840 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
E4F4499D1E82C1F000A7FB9A /* Build configuration list for PBXNativeTarget "libpthread armv81 resolved" */ = {
isa = XCConfigurationList;
buildConfigurations = (
.Fn pthread_setname_np "const char *name"
.Sh DESCRIPTION
The
-.Fn pthread_set_name_np
+.Fn pthread_setname_np
function sets the internal name for the calling thread to string value specified by
.Fa name
argument.
* If this is used on a workqueue (dispatch) thread, it MUST be unset with
* pthread_fchdir_np(-1) before returning.
*
+ * posix_spawn_file_actions_addchdir_np is a better approach if this call would
+ * only be used to spawn a new process with a given working directory.
+ *
* @param path
* The path of the new working directory.
*
* 0 upon success, -1 upon error and errno is set.
*/
__API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0))
-int pthread_chdir_np(char *path);
+int pthread_chdir_np(const char *path);
/*!
* @function pthread_fchdir_np
* directory fd. If this is used on a workqueue (dispatch) thread, it MUST be
* unset with pthread_fchdir_np(-1) before returning.
*
+ * posix_spawn_file_actions_addfchdir_np is a better approach if this call would
+ * only be used to spawn a new process with a given working directory.
+ *
* @param fd
* A file descriptor to the new working directory. Pass -1 to unset the
* per-thread working directory.
__API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0))
int pthread_attr_setcpupercent_np(pthread_attr_t * __restrict, int, unsigned long);
+__API_AVAILABLE(macos(10.15), ios(13.0), tvos(13.0), watchos(6.0))
+int pthread_current_stack_contains_np(const void *, size_t);
+
#ifdef _os_tsd_get_base
#ifdef __LP64__
#define __PTK_FRAMEWORK_SWIFT_KEY8 108
#define __PTK_FRAMEWORK_SWIFT_KEY9 109
+/* Keys 190 - 194 are for the use of PerfUtils */
+#define __PTK_PERF_UTILS_KEY0 190
+#define __PTK_PERF_UTILS_KEY1 191
+#define __PTK_PERF_UTILS_KEY2 192
+#define __PTK_PERF_UTILS_KEY3 193
+#define __PTK_PERF_UTILS_KEY4 194
+
/* Keys 210 - 229 are for libSystem usage within the iOS Simulator */
/* They are offset from their corresponding libSystem keys by 200 */
#define __PTK_LIBC_SIM_LOCALE_KEY 210
typedef void (*pthread_workqueue_function_workloop_t)(uint64_t *workloop_id, void **events, int *nevents);
+#define PTHREAD_WORKQUEUE_CONFIG_VERSION 2
+#define PTHREAD_WORKQUEUE_CONFIG_MIN_SUPPORTED_VERSION 1
+#define PTHREAD_WORKQUEUE_CONFIG_SUPPORTED_FLAGS 0
+struct pthread_workqueue_config {
+ uint32_t flags;
+ uint32_t version;
+ pthread_workqueue_function_kevent_t kevent_cb;
+ pthread_workqueue_function_workloop_t workloop_cb;
+ pthread_workqueue_function2_t workq_cb;
+ uint64_t queue_serialno_offs;
+ uint64_t queue_label_offs;
+};
+
+__API_AVAILABLE(macos(10.15), ios(13.0))
+int
+pthread_workqueue_setup(struct pthread_workqueue_config *cfg, size_t cfg_size);
+
// Initialises the pthread workqueue subsystem, passing the new-style callback prototype,
// the dispatchoffset and an unused flags field.
__API_AVAILABLE(macos(10.10), ios(8.0))
#define PTHREAD_MUTEX_INITIALIZER {_PTHREAD_MUTEX_SIG_init, {0}}
/* <rdar://problem/10854763> */
-#if ((__MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) || (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000))
+#if ((__MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) || (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)) || defined(__DRIVERKIT_VERSION_MIN_REQUIRED)
# if (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || defined(_DARWIN_C_SOURCE)
# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER {_PTHREAD_ERRORCHECK_MUTEX_SIG_init, {0}}
# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER {_PTHREAD_RECURSIVE_MUTEX_SIG_init, {0}}
#error Unsupported target
#endif
+
#define PTHREAD_INTERNAL_CRASH(c, x) do { \
_os_set_crash_log_cause_and_message((c), \
"BUG IN LIBPTHREAD: " x); \
#define _INTERNAL_POSIX_THREAD_KEYS_END 768
#endif
+#if defined(__arm64__)
+/* Pull the pthread_t into the same page as the top of the stack so we dirty one less page.
+ * <rdar://problem/19941744> The _pthread struct at the top of the stack shouldn't be page-aligned
+ */
+#define PTHREAD_T_OFFSET (12*1024)
+#else
#define PTHREAD_T_OFFSET 0
+#endif
#define MAXTHREADNAMESIZE 64
#define _PTHREAD_T
// MACH_PORT_DEAD if the thread exited
uint32_t tl_exit_gate;
struct sched_param tl_param;
+ void *__unused_padding;
//
// Fields protected by pthread_t::lock
schedset:1,
wqthread:1,
wqkillset:1,
- wqoutsideqos:1,
- __flags_pad:3;
+ __flags_pad:4;
char pthread_name[MAXTHREADNAMESIZE]; // includes NUL [aligned]
void *(*fun)(void *); // thread start routine
- void *wq_kqid_ptr; // wqthreads (workloop)
void *arg; // thread start routine argument
int wq_nevents; // wqthreads (workloop / kevent)
- uint16_t wq_retop; // wqthreads
- uint8_t cancel_state; // whether the thread can be canceled [atomic]
+ bool wq_outsideqos;
uint8_t canceled; // 4597450 set if conformant cancelation happened
+ uint16_t cancel_state; // whether the thread can be canceled [atomic]
errno_t cancel_error;
errno_t err_no; // thread-local errno
#define _PTHREAD_CANCEL_STATE_MASK 0x01
#define _PTHREAD_CANCEL_TYPE_MASK 0x02
#define _PTHREAD_CANCEL_PENDING 0x10 /* pthread_cancel() has been called for this thread */
-#define _PTHREAD_CANCEL_INITIALIZED 0x20 /* the thread in the list is properly initialized */
extern boolean_t swtch_pri(int);
void
_pthread_deallocate(pthread_t t, bool from_mach_thread);
-PTHREAD_NORETURN PTHREAD_NOEXPORT
-void
-__pthread_abort(void);
-
-PTHREAD_NORETURN PTHREAD_NOEXPORT
-void
-__pthread_abort_reason(const char *fmt, ...) __printflike(1,2);
-
PTHREAD_NOEXPORT
thread_qos_t
_pthread_qos_class_to_thread_qos(qos_class_t qos);
void
_pthread_start(pthread_t self, mach_port_t kport, void *(*fun)(void *), void * funarg, size_t stacksize, unsigned int flags);
-PTHREAD_NORETURN PTHREAD_EXPORT
+PTHREAD_EXPORT
void
_pthread_wqthread(pthread_t self, mach_port_t kport, void *stackaddr, void *keventlist, int flags, int nkevents);
t->tsd[_PTHREAD_TSD_SLOT_MACH_THREAD_SELF] = p;
}
-#define PTHREAD_ABORT(f,...) __pthread_abort_reason( \
- "%s:%s:%u: " f, __FILE__, __func__, __LINE__, ## __VA_ARGS__)
-
-#define PTHREAD_ASSERT(b) \
- do { if (!(b)) PTHREAD_ABORT("failed assertion `%s'", #b); } while (0)
+#ifdef DEBUG
+#define PTHREAD_DEBUG_ASSERT(b) \
+ do { \
+ if (os_unlikely(!(b))) { \
+ PTHREAD_INTERNAL_CRASH(0, "Assertion failed: " #b); \
+ } \
+ } while (0)
+#else
+#define PTHREAD_DEBUG_ASSERT(b) ((void)0)
+#endif
#include <os/semaphore_private.h>
#include <os/alloc_once_private.h>
{
pthread_t p;
if (thread == NULL) return false;
-loop:
_PTHREAD_LOCK(_pthread_list_lock);
TAILQ_FOREACH(p, &__pthread_head, tl_plist) {
if (p != thread) continue;
- int state = os_atomic_load(&p->cancel_state, relaxed);
- if (os_likely(state & _PTHREAD_CANCEL_INITIALIZED)) {
- if (os_unlikely(p->sig != _PTHREAD_SIG)) {
- PTHREAD_CLIENT_CRASH(0, "pthread_t was corrupted");
- }
- return true;
+ if (os_unlikely(p->sig != _PTHREAD_SIG)) {
+ PTHREAD_CLIENT_CRASH(0, "pthread_t was corrupted");
}
- _PTHREAD_UNLOCK(_pthread_list_lock);
- thread_switch(_pthread_kernel_thread(p),
- SWITCH_OPTION_OSLOCK_DEPRESS, 1);
- goto loop;
+ return true;
}
_PTHREAD_UNLOCK(_pthread_list_lock);
#include <machine/vmparam.h>
#define __APPLE_API_PRIVATE
#include <machine/cpu_capabilities.h>
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif // __has_include(<ptrauth.h>)
#include <_simple.h>
#include <platform/string.h>
#include <platform/compat.h>
+#include <stack_logging.h>
+
+// Defined in libsyscall; initialized in libmalloc
+extern malloc_logger_t *__syscall_logger;
+
extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen);
extern void __exit(int) __attribute__((noreturn));
static pthread_workqueue_function2_t __libdispatch_workerfunction;
static pthread_workqueue_function_kevent_t __libdispatch_keventfunction = &__pthread_invalid_keventfunction;
static pthread_workqueue_function_workloop_t __libdispatch_workloopfunction = &__pthread_invalid_workloopfunction;
-static int __libdispatch_offset;
static int __pthread_supported_features; // supported feature set
#if defined(__i386__) || defined(__x86_64__)
static mach_vm_address_t __pthread_stack_hint = 0xB0000000;
+#elif defined(__arm__) || defined(__arm64__)
+static mach_vm_address_t __pthread_stack_hint = 0x30000000;
#else
#error no __pthread_stack_hint for this architecture
#endif
#if VARIANT_DYLD
static void _pthread_set_self_dyld(void);
#endif // VARIANT_DYLD
-static inline void _pthread_set_self_internal(pthread_t, bool needs_tsd_base_set);
+static inline void _pthread_set_self_internal(pthread_t);
static void _pthread_dealloc_reply_port(pthread_t t);
static void _pthread_dealloc_special_reply_port(pthread_t t);
#define PTHREAD_START_POLICY_MASK 0xff
#define PTHREAD_START_IMPORTANCE_MASK 0xffff
-#if (!defined(__OPEN_SOURCE__) && TARGET_OS_OSX) || OS_VARIANT_RESOLVED // 40703288
-static int pthread_setschedparam_internal(pthread_t, mach_port_t, int,
- const struct sched_param *);
-#endif
-
extern pthread_t __bsdthread_create(void *(*func)(void *), void * func_arg, void * stack, pthread_t thread, unsigned int flags);
extern int __bsdthread_register(void (*)(pthread_t, mach_port_t, void *(*)(void *), void *, size_t, unsigned int), void (*)(pthread_t, mach_port_t, void *, void *, int), int,void (*)(pthread_t, mach_port_t, void *(*)(void *), void *, size_t, unsigned int), int32_t *,__uint64_t);
extern int __bsdthread_terminate(void * freeaddr, size_t freesize, mach_port_t kport, mach_port_t joinsem);
// it should be freed.
static pthread_t
-_pthread_allocate(const pthread_attr_t *attrs, void **stack)
+_pthread_allocate(const pthread_attr_t *attrs, void **stack,
+ bool from_mach_thread)
{
mach_vm_address_t allocaddr = __pthread_stack_hint;
size_t allocsize, guardsize, stacksize, pthreadoff;
kern_return_t kr;
pthread_t t;
- PTHREAD_ASSERT(attrs->stacksize == 0 ||
- attrs->stacksize >= PTHREAD_STACK_MIN);
+ if (os_unlikely(attrs->stacksize != 0 &&
+ attrs->stacksize < PTHREAD_STACK_MIN)) {
+ PTHREAD_CLIENT_CRASH(attrs->stacksize, "Stack size in attrs is too small");
+ }
+
+ if (os_unlikely(((uintptr_t)attrs->stackaddr % vm_page_size) != 0)) {
+ PTHREAD_CLIENT_CRASH(attrs->stacksize, "Unaligned stack addr in attrs");
+ }
// Allocate a pthread structure if necessary
if (attrs->stackaddr != NULL) {
- PTHREAD_ASSERT(((uintptr_t)attrs->stackaddr % vm_page_size) == 0);
allocsize = PTHREAD_SIZE;
guardsize = 0;
pthreadoff = 0;
if (kr != KERN_SUCCESS) {
kr = mach_vm_allocate(mach_task_self(), &allocaddr, allocsize,
VM_MAKE_TAG(VM_MEMORY_STACK)| VM_FLAGS_ANYWHERE);
+ } else if (__syscall_logger && !from_mach_thread) {
+ // libsyscall will not output malloc stack logging events when
+ // VM_MEMORY_STACK is passed in to facilitate mach thread promotion.
+ // To avoid losing the stack traces for normal p-thread create
+ // operations, libpthread must pretend to be the vm syscall and log
+ // the allocations. <rdar://36418708>
+ int eventTypeFlags = stack_logging_type_vm_allocate |
+ stack_logging_type_mapped_file_or_shared_mem;
+ __syscall_logger(eventTypeFlags | VM_MAKE_TAG(VM_MEMORY_STACK),
+ (uintptr_t)mach_task_self(), (uintptr_t)allocsize, 0,
+ (uintptr_t)allocaddr, 0);
}
+
if (kr != KERN_SUCCESS) {
*stack = NULL;
return NULL;
+ } else if (__syscall_logger && !from_mach_thread) {
+ // libsyscall will not output malloc stack logging events when
+ // VM_MEMORY_STACK is passed in to facilitate mach thread promotion.
+ // To avoid losing the stack traces for normal p-thread create
+ // operations, libpthread must pretend to be the vm syscall and log
+ // the allocations. <rdar://36418708>
+ int eventTypeFlags = stack_logging_type_vm_allocate;
+ __syscall_logger(eventTypeFlags | VM_MAKE_TAG(VM_MEMORY_STACK),
+ (uintptr_t)mach_task_self(), (uintptr_t)allocsize, 0,
+ (uintptr_t)allocaddr, 0);
}
// The stack grows down.
_pthread_introspection_thread_destroy(t);
}
ret = mach_vm_deallocate(mach_task_self(), t->freeaddr, t->freesize);
- PTHREAD_ASSERT(ret == KERN_SUCCESS);
+ if (ret != KERN_SUCCESS) {
+ PTHREAD_INTERNAL_CRASH(ret, "Unable to deallocate stack");
+ }
}
}
static void
_pthread_terminate(pthread_t t, void *exit_value)
{
- PTHREAD_ASSERT(t == pthread_self());
-
_pthread_introspection_thread_terminate(t);
uintptr_t freeaddr = (uintptr_t)t->freeaddr;
#pragma mark pthread start / body
-/*
- * Create and start execution of a new thread.
- */
-PTHREAD_NOINLINE PTHREAD_NORETURN
-static void
-_pthread_body(pthread_t self, bool needs_tsd_base_set)
-{
- _pthread_set_self_internal(self, needs_tsd_base_set);
- __pthread_started_thread(self);
- _pthread_exit(self, (self->fun)(self->arg));
-}
-
PTHREAD_NORETURN
void
_pthread_start(pthread_t self, mach_port_t kport,
__unused void *(*fun)(void *), __unused void *arg,
__unused size_t stacksize, unsigned int pflags)
{
- bool thread_tsd_bsd_set = (bool)(pflags & PTHREAD_START_TSD_BASE_SET);
-
if (os_unlikely(pflags & PTHREAD_START_SUSPENDED)) {
- PTHREAD_INTERNAL_CRASH(0,
+ PTHREAD_INTERNAL_CRASH(pflags,
"kernel without PTHREAD_START_SUSPENDED support");
}
-#if DEBUG
- PTHREAD_ASSERT(MACH_PORT_VALID(kport));
- PTHREAD_ASSERT(_pthread_kernel_thread(self) == kport);
-#endif
- // will mark the thread initialized
+ if (os_unlikely((pflags & PTHREAD_START_TSD_BASE_SET) == 0)) {
+ PTHREAD_INTERNAL_CRASH(pflags,
+ "thread_set_tsd_base() wasn't called by the kernel");
+ }
+ PTHREAD_DEBUG_ASSERT(MACH_PORT_VALID(kport));
+ PTHREAD_DEBUG_ASSERT(_pthread_kernel_thread(self) == kport);
_pthread_markcancel_if_canceled(self, kport);
- _pthread_body(self, !thread_tsd_bsd_set);
+ _pthread_set_self_internal(self);
+ __pthread_started_thread(self);
+ _pthread_exit(self, (self->fun)(self->arg));
}
PTHREAD_ALWAYS_INLINE
_pthread_struct_init(pthread_t t, const pthread_attr_t *attrs,
void *stackaddr, size_t stacksize, void *freeaddr, size_t freesize)
{
-#if DEBUG
- PTHREAD_ASSERT(t->sig != _PTHREAD_SIG);
-#endif
+ PTHREAD_DEBUG_ASSERT(t->sig != _PTHREAD_SIG);
t->sig = _PTHREAD_SIG;
t->tsd[_PTHREAD_TSD_SLOT_PTHREAD_SELF] = t;
pthread_get_stacksize_np(pthread_t t)
{
size_t size = 0;
- size_t stacksize = t->stackaddr - t->stackbottom;
if (t == NULL) {
return ESRCH; // XXX bug?
}
-#if !defined(__arm__) && !defined(__arm64__)
+#if TARGET_OS_OSX
// The default rlimit based allocations will be provided with a stacksize
// of the current limit and a freesize of the max. However, custom
// allocations will just have the guard page to free. If we aren't in the
//
// Of course, on arm rlim_cur == rlim_max and there's only the one guard
// page. So, we can skip all this there.
- if (t == main_thread() && stacksize + vm_page_size != t->freesize) {
- // We want to call getrlimit() just once, as it's relatively expensive
- static size_t rlimit_stack;
+ if (t == main_thread()) {
+ size_t stacksize = t->stackaddr - t->stackbottom;
+
+ if (stacksize + vm_page_size != t->freesize) {
+ // We want to call getrlimit() just once, as it's relatively
+ // expensive
+ static size_t rlimit_stack;
- if (rlimit_stack == 0) {
- struct rlimit limit;
- int ret = getrlimit(RLIMIT_STACK, &limit);
+ if (rlimit_stack == 0) {
+ struct rlimit limit;
+ int ret = getrlimit(RLIMIT_STACK, &limit);
- if (ret == 0) {
- rlimit_stack = (size_t) limit.rlim_cur;
+ if (ret == 0) {
+ rlimit_stack = (size_t) limit.rlim_cur;
+ }
}
- }
- if (rlimit_stack == 0 || rlimit_stack > t->freesize) {
- return stacksize;
- } else {
- return rlimit_stack;
+ if (rlimit_stack == 0 || rlimit_stack > t->freesize) {
+ return stacksize;
+ } else {
+ return round_page(rlimit_stack);
+ }
}
}
-#endif /* !defined(__arm__) && !defined(__arm64__) */
+#endif /* TARGET_OS_OSX */
if (t == pthread_self() || t == main_thread()) {
- size = stacksize;
+ size = t->stackaddr - t->stackbottom;;
goto out;
}
if (_pthread_validate_thread_and_list_lock(t)) {
- size = stacksize;
+ size = t->stackaddr - t->stackbottom;;
_PTHREAD_UNLOCK(_pthread_list_lock);
- } else {
- size = ESRCH; // XXX bug?
}
out:
}
+static int
+_pthread_threadid_slow(pthread_t thread, uint64_t *thread_id)
+{
+ unsigned int info_count = THREAD_IDENTIFIER_INFO_COUNT;
+ mach_port_t thport = _pthread_kernel_thread(thread);
+ struct thread_identifier_info info;
+ kern_return_t kr;
+
+ kr = thread_info(thport, THREAD_IDENTIFIER_INFO,
+ (thread_info_t)&info, &info_count);
+ if (kr == KERN_SUCCESS && info.thread_id) {
+ *thread_id = info.thread_id;
+ os_atomic_store(&thread->thread_id, info.thread_id, relaxed);
+ return 0;
+ }
+ return EINVAL;
+}
+
/*
* if we are passed in a pthread_t that is NULL, then we return the current
* thread's thread_id. So folks don't have to call pthread_self, in addition to
} else if (!_pthread_validate_thread_and_list_lock(thread)) {
res = ESRCH;
} else {
- if (thread->thread_id == 0) {
- res = EINVAL;
- } else {
- *thread_id = thread->thread_id;
+ *thread_id = os_atomic_load(&thread->thread_id, relaxed);
+ if (os_unlikely(*thread_id == 0)) {
+ // there is a race at init because the thread sets its own TID.
+ // correct this by asking mach
+ res = _pthread_threadid_slow(thread, thread_id);
}
_PTHREAD_UNLOCK(_pthread_list_lock);
}
__pthread_started_thread(pthread_t t)
{
mach_port_t kport = _pthread_kernel_thread(t);
- if (os_slowpath(!MACH_PORT_VALID(kport))) {
+ if (os_unlikely(!MACH_PORT_VALID(kport))) {
PTHREAD_CLIENT_CRASH(kport,
"Unable to allocate thread port, possible port leak");
}
__is_threaded = 1;
- t =_pthread_allocate(attrs, &stack);
+ t =_pthread_allocate(attrs, &stack, from_mach_thread);
if (t == NULL) {
return EAGAIN;
}
return EAGAIN;
}
- if (create_flags & _PTHREAD_CREATE_SUSPENDED) {
- _pthread_markcancel_if_canceled(t, _pthread_kernel_thread(t));
- }
-
// n.b. if a thread is created detached and exits, t will be invalid
*thread = t;
return 0;
return _pthread_create(thread, attr, start_routine, arg, flags);
}
-#if !defined(__OPEN_SOURCE__) && TARGET_OS_OSX // 40703288
-/* Functions defined in machine-dependent files. */
-PTHREAD_NOEXPORT void _pthread_setup_suspended(pthread_t th, void (*f)(pthread_t), void *sp);
-
-PTHREAD_NORETURN
-static void
-_pthread_suspended_body(pthread_t self)
-{
- _pthread_set_self(self);
- __pthread_started_thread(self);
- _pthread_exit(self, (self->fun)(self->arg));
-}
-
-static int
-_pthread_create_suspended_np(pthread_t *thread, const pthread_attr_t *attrs,
- void *(*start_routine)(void *), void *arg)
-{
- pthread_t t;
- void *stack;
- mach_port_t kernel_thread = MACH_PORT_NULL;
-
- if (attrs == NULL) {
- attrs = &_pthread_attr_default;
- } else if (attrs->sig != _PTHREAD_ATTR_SIG) {
- return EINVAL;
- }
-
- t = _pthread_allocate(attrs, &stack);
- if (t == NULL) {
- return EAGAIN;
- }
-
- if (thread_create(mach_task_self(), &kernel_thread) != KERN_SUCCESS) {
- _pthread_deallocate(t, false);
- return EAGAIN;
- }
-
- _pthread_set_kernel_thread(t, kernel_thread);
- (void)pthread_setschedparam_internal(t, kernel_thread,
- t->tl_policy, &t->tl_param);
-
- __is_threaded = 1;
-
- t->arg = arg;
- t->fun = start_routine;
- t->cancel_state |= _PTHREAD_CANCEL_INITIALIZED;
- __pthread_add_thread(t, false);
-
- // Set up a suspended thread.
- _pthread_setup_suspended(t, _pthread_suspended_body, stack);
- *thread = t;
- return 0;
-}
-#endif // !defined(__OPEN_SOURCE__) && TARGET_OS_OSX
-
int
pthread_create_suspended_np(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg)
{
-#if !defined(__OPEN_SOURCE__) && TARGET_OS_OSX // 40703288
- if (_os_xbs_chrooted) {
- return _pthread_create_suspended_np(thread, attr, start_routine, arg);
- }
-#endif
unsigned int flags = _PTHREAD_CREATE_SUSPENDED;
return _pthread_create(thread, attr, start_routine, arg, flags);
}
}
mach_port_t kport = MACH_PORT_NULL;
- if (!_pthread_is_valid(th, &kport)) {
- return ESRCH; // Not a valid thread.
- }
-
- // Don't signal workqueue threads.
- if (th->wqthread != 0 && th->wqkillset == 0) {
- return ENOTSUP;
+ {
+ if (!_pthread_is_valid(th, &kport)) {
+ return ESRCH;
+ }
}
int ret = __pthread_kill(kport, sig);
int
__pthread_workqueue_setkill(int enable)
{
- pthread_t self = pthread_self();
-
- _PTHREAD_LOCK(self->lock);
- self->wqkillset = enable ? 1 : 0;
- _PTHREAD_UNLOCK(self->lock);
-
- return 0;
+ {
+ return __bsdthread_ctl(BSDTHREAD_CTL_WORKQ_ALLOW_KILL, enable, 0, 0);
+ }
}
return _pthread_set_self_dyld();
}
#endif // VARIANT_DYLD
- _pthread_set_self_internal(p, true);
+ _pthread_set_self_internal(p);
+ _thread_set_tsd_base(&p->tsd[0]);
}
#if VARIANT_DYLD
PTHREAD_ALWAYS_INLINE
static inline void
-_pthread_set_self_internal(pthread_t p, bool needs_tsd_base_set)
+_pthread_set_self_internal(pthread_t p)
{
- p->thread_id = __thread_selfid();
+ os_atomic_store(&p->thread_id, __thread_selfid(), relaxed);
if (os_unlikely(p->thread_id == -1ull)) {
PTHREAD_INTERNAL_CRASH(0, "failed to set thread_id");
}
-
- if (needs_tsd_base_set) {
- _thread_set_tsd_base(&p->tsd[0]);
- }
}
// and make it our main thread point.
pthread_t thread = (pthread_t)_pthread_getspecific_direct(
_PTHREAD_TSD_SLOT_PTHREAD_SELF);
- PTHREAD_ASSERT(thread);
+ if (os_unlikely(thread == NULL)) {
+ PTHREAD_INTERNAL_CRASH(0, "PTHREAD_SELF TSD not initialized");
+ }
_main_thread_ptr = thread;
- PTHREAD_ASSERT(_pthread_attr_default.qosclass ==
+ PTHREAD_DEBUG_ASSERT(_pthread_attr_default.qosclass ==
_pthread_default_priority(0));
_pthread_struct_init(thread, &_pthread_attr_default,
stackaddr, stacksize, allocaddr, allocsize);
p->tl_exit_gate = MACH_PORT_NULL;
p->tsd[__TSD_SEMAPHORE_CACHE] = (void*)(uintptr_t)SEMAPHORE_NULL;
p->tsd[__TSD_MACH_SPECIAL_REPLY] = 0;
- p->cancel_state |= _PTHREAD_CANCEL_INITIALIZED;
// Initialize the list of threads with the new main thread.
TAILQ_INSERT_HEAD(&__pthread_head, p, tl_plist);
_pthread_main_thread_postfork_init(pthread_t p)
{
_pthread_main_thread_init(p);
- _pthread_set_self_internal(p, false);
+ _pthread_set_self_internal(p);
}
int
sched_yield();
}
+// Libsystem knows about this symbol and exports it to libsyscall
+int
+pthread_current_stack_contains_np(const void *addr, size_t length)
+{
+ uintptr_t begin = (uintptr_t) addr, end;
+ uintptr_t stack_base = (uintptr_t) _pthread_self_direct()->stackbottom;
+ uintptr_t stack_top = (uintptr_t) _pthread_self_direct()->stackaddr;
+
+ if (stack_base == stack_top) {
+ return -ENOTSUP;
+ }
+
+ if (__builtin_add_overflow(begin, length, &end)) {
+ return -EINVAL;
+ }
+
+ return stack_base <= begin && end <= stack_top;
+}
+
// Libsystem knows about this symbol and exports it to libsyscall
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__)
+#if __ARM64_ARCH_8_32__
+/*
+ * arm64_32 uses 64-bit sizes for the frame pointer and
+ * return address of a stack frame.
+ */
+typedef uint64_t frame_data_addr_t;
+#else
typedef uintptr_t frame_data_addr_t;
+#endif
struct frame_data {
frame_data_addr_t frame_addr_next;
struct frame_data *frame = (struct frame_data *)frame_addr;
if (return_addr) {
+#if __has_feature(ptrauth_calls)
+ *return_addr = (uintptr_t)ptrauth_strip((void *)frame->ret_addr,
+ ptrauth_key_return_address);
+#else
*return_addr = (uintptr_t)frame->ret_addr;
+#endif /* __has_feature(ptrauth_calls) */
}
+#if __has_feature(ptrauth_calls)
+ return (uintptr_t)ptrauth_strip((void *)frame->frame_addr_next,
+ ptrauth_key_frame_pointer);
+#endif /* __has_feature(ptrauth_calls) */
return (uintptr_t)frame->frame_addr_next;
}
self->wqthread = 1;
self->wqkillset = 0;
self->tl_joinable = false;
- self->cancel_state |= _PTHREAD_CANCEL_INITIALIZED;
// Update the running thread count and set childrun bit.
- bool thread_tsd_base_set = (bool)(flags & WQ_FLAG_THREAD_TSD_BASE_SET);
- _pthread_set_self_internal(self, !thread_tsd_base_set);
+ if (os_unlikely((flags & WQ_FLAG_THREAD_TSD_BASE_SET) == 0)) {
+ PTHREAD_INTERNAL_CRASH(flags,
+ "thread_set_tsd_base() wasn't called by the kernel");
+ }
+ _pthread_set_self_internal(self);
__pthread_add_thread(self, false);
__pthread_started_thread(self);
}
}
pthread_priority_t pp;
+
if (flags & WQ_FLAG_THREAD_OUTSIDEQOS) {
- self->wqoutsideqos = 1;
+ self->wq_outsideqos = 1;
pp = _pthread_priority_make_from_thread_qos(THREAD_QOS_LEGACY, 0,
_PTHREAD_PRIORITY_FALLBACK_FLAG);
} else {
- self->wqoutsideqos = 0;
+ self->wq_outsideqos = 0;
pp = _pthread_wqthread_priority(flags);
}
self->tsd[_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS] = (void *)pp;
// avoid spills on the stack hard to keep used stack space minimal
- if (nkevents == WORKQ_EXIT_THREAD_NKEVENT) {
- goto exit;
+ if (os_unlikely(nkevents == WORKQ_EXIT_THREAD_NKEVENT)) {
+ _pthread_wqthread_exit(self);
} else if (flags & WQ_FLAG_THREAD_WORKLOOP) {
+ kqueue_id_t *kqidptr = (kqueue_id_t *)keventlist - 1;
self->fun = (void *(*)(void*))__libdispatch_workloopfunction;
- self->wq_retop = WQOPS_THREAD_WORKLOOP_RETURN;
- self->wq_kqid_ptr = ((kqueue_id_t *)keventlist - 1);
self->arg = keventlist;
self->wq_nevents = nkevents;
+ (*__libdispatch_workloopfunction)(kqidptr, &self->arg, &self->wq_nevents);
+ __workq_kernreturn(WQOPS_THREAD_WORKLOOP_RETURN, self->arg, self->wq_nevents, 0);
} else if (flags & WQ_FLAG_THREAD_KEVENT) {
self->fun = (void *(*)(void*))__libdispatch_keventfunction;
- self->wq_retop = WQOPS_THREAD_KEVENT_RETURN;
- self->wq_kqid_ptr = NULL;
self->arg = keventlist;
self->wq_nevents = nkevents;
+ (*__libdispatch_keventfunction)(&self->arg, &self->wq_nevents);
+ __workq_kernreturn(WQOPS_THREAD_KEVENT_RETURN, self->arg, self->wq_nevents, 0);
} else {
self->fun = (void *(*)(void*))__libdispatch_workerfunction;
- self->wq_retop = WQOPS_THREAD_RETURN;
- self->wq_kqid_ptr = NULL;
self->arg = (void *)(uintptr_t)pp;
self->wq_nevents = 0;
if (os_likely(__workq_newapi)) {
} else {
_pthread_wqthread_legacy_worker_wrap(pp);
}
- goto just_return;
- }
-
- if (nkevents > 0) {
-kevent_errors_retry:
- if (self->wq_retop == WQOPS_THREAD_WORKLOOP_RETURN) {
- ((pthread_workqueue_function_workloop_t)self->fun)
- (self->wq_kqid_ptr, &self->arg, &self->wq_nevents);
- } else {
- ((pthread_workqueue_function_kevent_t)self->fun)
- (&self->arg, &self->wq_nevents);
- }
- int rc = __workq_kernreturn(self->wq_retop, self->arg, self->wq_nevents, 0);
- if (os_unlikely(rc > 0)) {
- self->wq_nevents = rc;
- goto kevent_errors_retry;
- }
- if (os_unlikely(rc < 0)) {
- PTHREAD_INTERNAL_CRASH(self->err_no, "kevent (workloop) failed");
- }
- } else {
-just_return:
- __workq_kernreturn(self->wq_retop, NULL, 0, 0);
+ __workq_kernreturn(WQOPS_THREAD_RETURN, NULL, 0, 0);
}
-exit:
- _pthread_wqthread_exit(self);
+ _os_set_crash_log_cause_and_message(self->err_no,
+ "BUG IN LIBPTHREAD: __workq_kernreturn returned");
+ /*
+ * 52858993: we should never return but the compiler insists on outlining,
+ * so the __builtin_trap() is in _start_wqthread in pthread_asm.s
+ */
}
void
pthread_workqueue_setdispatchoffset_np(int offset)
{
- __libdispatch_offset = offset;
+ __workq_kernreturn(WQOPS_QUEUE_NEWSPISUPP, NULL, offset, 0x00);
}
-static int
-pthread_workqueue_setdispatch_with_workloop_np(pthread_workqueue_function2_t queue_func,
- pthread_workqueue_function_kevent_t kevent_func,
- pthread_workqueue_function_workloop_t workloop_func)
+int
+pthread_workqueue_setup(struct pthread_workqueue_config *cfg, size_t cfg_size)
{
- int res = EBUSY;
+ int rv = EBUSY;
+ struct workq_dispatch_config wdc_cfg;
+ size_t min_size = 0;
+
+ if (cfg_size < sizeof(uint32_t)) {
+ return EINVAL;
+ }
+
+ switch (cfg->version) {
+ case 1:
+ min_size = offsetof(struct pthread_workqueue_config, queue_label_offs);
+ break;
+ case 2:
+ min_size = sizeof(struct pthread_workqueue_config);
+ break;
+ default:
+ return EINVAL;
+ }
+
+ if (!cfg || cfg_size < min_size) {
+ return EINVAL;
+ }
+
+ if (cfg->flags & ~PTHREAD_WORKQUEUE_CONFIG_SUPPORTED_FLAGS ||
+ cfg->version < PTHREAD_WORKQUEUE_CONFIG_MIN_SUPPORTED_VERSION) {
+ return ENOTSUP;
+ }
+
if (__libdispatch_workerfunction == NULL) {
- // Check whether the kernel supports new SPIs
- res = __workq_kernreturn(WQOPS_QUEUE_NEWSPISUPP, NULL, __libdispatch_offset, kevent_func != NULL ? 0x01 : 0x00);
- if (res == -1){
- res = ENOTSUP;
+ __workq_newapi = true;
+
+ wdc_cfg.wdc_version = WORKQ_DISPATCH_CONFIG_VERSION;
+ wdc_cfg.wdc_flags = 0;
+ wdc_cfg.wdc_queue_serialno_offs = cfg->queue_serialno_offs;
+#if WORKQ_DISPATCH_CONFIG_VERSION >= 2
+ wdc_cfg.wdc_queue_label_offs = cfg->queue_label_offs;
+#endif
+
+ // Tell the kernel about dispatch internals
+ rv = (int) __workq_kernreturn(WQOPS_SETUP_DISPATCH, &wdc_cfg, sizeof(wdc_cfg), 0);
+ if (rv == -1) {
+ return errno;
} else {
- __libdispatch_workerfunction = queue_func;
- __libdispatch_keventfunction = kevent_func;
- __libdispatch_workloopfunction = workloop_func;
+ __libdispatch_keventfunction = cfg->kevent_cb;
+ __libdispatch_workloopfunction = cfg->workloop_cb;
+ __libdispatch_workerfunction = cfg->workq_cb;
// Prepare the kernel for workq action
(void)__workq_open();
if (__is_threaded == 0) {
__is_threaded = 1;
}
+
+ return 0;
}
}
- return res;
+
+ return rv;
}
int
pthread_workqueue_function_workloop_t workloop_func,
int offset, int flags)
{
- if (flags != 0) {
- return ENOTSUP;
- }
-
- __workq_newapi = true;
- __libdispatch_offset = offset;
+ struct pthread_workqueue_config cfg = {
+ .version = PTHREAD_WORKQUEUE_CONFIG_VERSION,
+ .flags = 0,
+ .workq_cb = queue_func,
+ .kevent_cb = kevent_func,
+ .workloop_cb = workloop_func,
+ .queue_serialno_offs = offset,
+ .queue_label_offs = 0,
+ };
- int rv = pthread_workqueue_setdispatch_with_workloop_np(queue_func, kevent_func, workloop_func);
- return rv;
+ return pthread_workqueue_setup(&cfg, sizeof(cfg));
}
int
int
pthread_workqueue_setdispatch_np(pthread_workqueue_function_t worker_func)
{
- return pthread_workqueue_setdispatch_with_workloop_np((pthread_workqueue_function2_t)worker_func, NULL, NULL);
+ struct pthread_workqueue_config cfg = {
+ .version = PTHREAD_WORKQUEUE_CONFIG_VERSION,
+ .flags = 0,
+ .workq_cb = (uint64_t)(pthread_workqueue_function2_t)worker_func,
+ .kevent_cb = 0,
+ .workloop_cb = 0,
+ .queue_serialno_offs = 0,
+ .queue_label_offs = 0,
+ };
+
+ return pthread_workqueue_setup(&cfg, sizeof(cfg));
}
int
_pthread_introspection_hook_callout_thread_destroy(t);
}
+
+#if !VARIANT_DYLD
#pragma mark libplatform shims
#include <platform/string.h>
return _platform_memmove(a, b, s);
}
+#endif // !VARIANT_DYLD
.globl _start_wqthread
_start_wqthread:
// This routine is never called directly by user code, jumped from kernel
+ // Push a sentinel frame, so backtracers know when to stop.
+ push $0
push %rbp
mov %rsp,%rbp
- sub $24,%rsp // align the stack
+ sub $16,%rsp // align the stack
call __pthread_wqthread
- leave
- ret
+ ud2 // never returns
.align 2, 0x90
.globl _thread_start
_thread_start:
// This routine is never called directly by user code, jumped from kernel
+ // Push a sentinel frame, so backtracers know when to stop.
+ push $0
push %rbp
mov %rsp,%rbp
- sub $24,%rsp // align the stack
+ sub $16,%rsp // align the stack
call __pthread_start
leave
ret
popq %rcx
retq
+Lcrash:
+ // POSIX mandates that stack overflow crashes with SIGSEGV
+ // so load an address in the guard page and dereference it
+ movq %gs:_PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET, %rcx
+ testq %rcx, -8(%rcx)
+ // if main_thread caused stack growth with setrlimit()
+ // fall into Lprobe and eventually cause SIGSEGV.
+
Lprobe:
// probe the stack when it's not ours (altstack or some shenanigan)
cmpq $0x1000, %rax
popq %rcx
retq
-Lcrash:
- ud2
-
#endif
#elif defined(__i386__)
.globl _start_wqthread
_start_wqthread:
// This routine is never called directly by user code, jumped from kernel
+ // Push a sentinel frame, so backtracers know when to stop.
+ push $0
push %ebp
mov %esp,%ebp
- sub $28,%esp // align the stack
+ sub $24,%esp // align the stack
mov %esi,20(%esp) //arg5
mov %edi,16(%esp) //arg5
mov %edx,12(%esp) //arg4
mov %ebx,4(%esp) //arg2
mov %eax,(%esp) //arg1
call __pthread_wqthread
- leave
- ret
+ ud2 // never returns
.align 2, 0x90
.globl _thread_start
_thread_start:
// This routine is never called directly by user code, jumped from kernel
+ // Push a sentinel frame, so backtracers know when to stop.
+ push $0
push %ebp
mov %esp,%ebp
- sub $28,%esp // align the stack
+ sub $24,%esp // align the stack
mov %esi,20(%esp) //arg6
mov %edi,16(%esp) //arg5
mov %edx,12(%esp) //arg4
popl %ecx
retl
+Lcrash:
+ // POSIX mandates that stack overflow crashes with SIGSEGV
+ // so load an address in the guard page and dereference it
+ movl %gs:0x0, %ecx // pthread_self()
+ movl _PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET(%ecx), %ecx
+ testl %ecx, -4(%ecx)
+ // if main_thread caused stack growth with setrlimit()
+ // fall into Lprobe and eventually cause SIGSEGV.
+
Lprobe:
// probe the stack when it's not ours (altstack or some shenanigan)
cmpl $0x1000, %eax
popl %ecx
retl
-Lcrash:
- ud2
-
#endif
#elif defined(__arm__)
.align 2
.globl _start_wqthread
_start_wqthread:
-#if __ARM_ARCH_7K__
- /* align stack to 16 bytes before calling C */
- sub sp, sp, #8
-#endif
+// Push a sentinel frame, so backtracers know when to stop.
+ mov ip, #0
+ str ip, [sp, #-4]!
+ str ip, [sp, #-4]!
stmfd sp!, {r4, r5}
bl __pthread_wqthread
+ trap // never returns
+
+ .text
+ .align 2
+ .globl _thread_start
+_thread_start:
+// Push a sentinel frame, so backtracers know when to stop.
+ mov ip, #0
+ str ip, [sp, #-4]!
+ str ip, [sp, #-4]!
+ stmfd sp!, {r4, r5}
+ bl __pthread_start
// Stackshots will show the routine that happens to link immediately following
// _start_wqthread. So we add an extra instruction (nop) to make stackshots
// more readable.
nop
+#endif
+
+#elif defined(__arm64__)
+
+#include <mach/arm/syscall_sw.h>
+
+#ifndef VARIANT_DYLD
+
+// This routine is never called directly by user code, jumped from kernel
+// args 0 to 5 in registers.
+ .text
+ .align 2
+ .globl _start_wqthread
+_start_wqthread:
+// Push a sentinel frame, so backtracers know when to stop.
+ stp xzr, xzr, [sp, #-16]!
+ bl __pthread_wqthread
+ brk #1 // never returns
+
.text
.align 2
.globl _thread_start
_thread_start:
-#if __ARM_ARCH_7K__
- /* align stack to 16 bytes before calling C */
- sub sp, sp, #8
-#endif
- stmfd sp!, {r4, r5}
+// Push a sentinel frame, so backtracers know when to stop.
+ stp xzr, xzr, [sp, #-16]!
bl __pthread_start
-// See above
nop
+ .text
+ .align 2
+ .globl _thread_chkstk_darwin
+_thread_chkstk_darwin:
+ .globl ____chkstk_darwin
+____chkstk_darwin: // %w9 == alloca size
+ stp x10, x11, [sp, #-16]
+
+ // validate that the frame pointer is on our stack (no alt stack)
+ mrs x10, TPIDRRO_EL0
+ and x10, x10, #0xfffffffffffffff8
+
+ // (%sp - pthread_self()->stackaddr) > 0 ?
+#if defined(__ARM64_ARCH_8_32__)
+ ldur w11, [x10, _PTHREAD_STRUCT_DIRECT_STACKADDR_OFFSET]
+#else
+ ldur x11, [x10, _PTHREAD_STRUCT_DIRECT_STACKADDR_OFFSET]
+#endif
+ subs x11, sp, x11
+ b.hs Lprobe
+
+ // %sp <= pthread_self()->stackbottom ?
+#if defined(__ARM64_ARCH_8_32__)
+ ldur w11, [x10, _PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET]
+#else
+ ldur x11, [x10, _PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET]
+#endif
+ mov x10, sp
+ cmp x10, x11
+ b.ls Lprobe
+
+ // %sp - (uintptr_t)%w9 < pthread_self()->stackbottom ?
+ subs x10, x10, w9, uxtw
+ b.lo Lcrash
+ cmp x10, x11
+ b.lo Lcrash
+
+Lexit:
+ ldp x10, x11, [sp, #-16]
+ ret
+
+Lcrash:
+ // POSIX mandates that stack overflow crashes with SIGSEGV
+ // so load an address in the guard page and dereference it
+ //
+ // x11 contains pthread_self()->stackbottom already
+ ldr x11, [x11, #-8]
+ // if main_thread caused stack growth with setrlimit()
+ // fall into Lprobe and eventually cause SIGSEGV.
+
+Lprobe:
+ mov x10, sp
+ cmp w9, #0x1000
+ b.lo Lend
+Lloop:
+ sub x10, x10, #0x1000
+ ldr x11, [x10]
+ sub w9, w9, #0x1000
+ cmp w9, #0x1000
+ b.hi Lloop
+Lend:
+ sub x10, x10, x9
+ ldr x11, [x10]
+ b Lexit
+
#endif
#else
_pthread_markcancel_if_canceled(pthread_t thread, mach_port_t kport)
{
const int flags = (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING);
- int state = os_atomic_or2o(thread, cancel_state,
- _PTHREAD_CANCEL_INITIALIZED, relaxed);
+ int state = os_atomic_load2o(thread, cancel_state, relaxed);
if ((state & flags) == flags && __unix_conforming) {
__pthread_markcancel(kport);
}
* _pthread_joiner_prepost_wake() didn't happen
* allow another thread to join
*/
-#if DEBUG
- PTHREAD_ASSERT(thread->tl_join_ctx == ctx);
-#endif
+ PTHREAD_DEBUG_ASSERT(thread->tl_join_ctx == ctx);
thread->tl_join_ctx = NULL;
thread->tl_exit_gate = MACH_PORT_NULL;
aborted = true;
// If pthread_detach() was called, we can't safely dereference the thread,
// else, decide who gets to deallocate the thread (see _pthread_terminate).
if (!ctx->detached) {
-#if DEBUG
- PTHREAD_ASSERT(thread->tl_join_ctx == ctx);
-#endif
+ PTHREAD_DEBUG_ASSERT(thread->tl_join_ctx == ctx);
thread->tl_join_ctx = NULL;
cleanup = thread->tl_joiner_cleans_up;
}
res = EDEADLK;
} else if (thread->tl_exit_gate == MACH_PORT_DEAD) {
TAILQ_REMOVE(&__pthread_head, thread, tl_plist);
-#if DEBUG
- PTHREAD_ASSERT(thread->tl_joiner_cleans_up);
-#endif
+ PTHREAD_DEBUG_ASSERT(thread->tl_joiner_cleans_up);
thread->tl_joinable = false;
if (value_ptr) *value_ptr = _pthread_get_exit_value(thread);
} else {
volatile uint32_t *c_lseqcnt, *c_useqcnt, *c_sseqcnt;
uint64_t oldval64, newval64, mugen, cvlsgen;
uint32_t *npmtx = NULL;
+ int timeout_elapsed = 0;
res = _pthread_cond_check_init(cond, NULL);
if (res != 0) {
/* send relative time to kernel */
if (abstime) {
+ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= NSEC_PER_SEC) {
+ return EINVAL;
+ }
+
if (isRelative == 0) {
struct timespec now;
struct timeval tv;
__gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &now);
- /* Compute relative time to sleep */
- then.tv_nsec = abstime->tv_nsec - now.tv_nsec;
- then.tv_sec = abstime->tv_sec - now.tv_sec;
- if (then.tv_nsec < 0) {
- then.tv_nsec += NSEC_PER_SEC;
- then.tv_sec--;
- }
- if (then.tv_sec < 0 || (then.tv_sec == 0 && then.tv_nsec == 0)) {
- return ETIMEDOUT;
- }
- if (conforming &&
- (abstime->tv_sec < 0 ||
- abstime->tv_nsec < 0 ||
- abstime->tv_nsec >= NSEC_PER_SEC)) {
- return EINVAL;
+ if ((abstime->tv_sec == now.tv_sec) ?
+ (abstime->tv_nsec <= now.tv_nsec) :
+ (abstime->tv_sec < now.tv_sec)) {
+ timeout_elapsed = 1;
+ } else {
+ /* Compute relative time to sleep */
+ then.tv_nsec = abstime->tv_nsec - now.tv_nsec;
+ then.tv_sec = abstime->tv_sec - now.tv_sec;
+ if (then.tv_nsec < 0) {
+ then.tv_nsec += NSEC_PER_SEC;
+ then.tv_sec--;
+ }
}
} else {
then.tv_sec = abstime->tv_sec;
then.tv_nsec = abstime->tv_nsec;
if ((then.tv_sec == 0) && (then.tv_nsec == 0)) {
- return ETIMEDOUT;
+ timeout_elapsed = 1;
}
}
- if (conforming && (then.tv_sec < 0 || then.tv_nsec < 0)) {
- return EINVAL;
- }
- if (then.tv_nsec >= NSEC_PER_SEC) {
- return EINVAL;
- }
}
if (cond->busy != NULL && cond->busy != mutex) {
return EINVAL;
}
+ /*
+ * If timeout is known to have elapsed, we still need to unlock and
+ * relock the mutex to allow other waiters to get in line and
+ * modify the condition state.
+ */
+ if (timeout_elapsed) {
+ res = pthread_mutex_unlock(omutex);
+ if (res != 0) {
+ return res;
+ }
+ res = pthread_mutex_lock(omutex);
+ if (res != 0) {
+ return res;
+ }
+ return ETIMEDOUT;
+ }
+
COND_GETSEQ_ADDR(cond, &c_lsseqaddr, &c_lseqcnt, &c_useqcnt, &c_sseqcnt);
do {
#include <fcntl.h>
#include <unistd.h>
-extern int __pthread_chdir(char *path);
+extern int __pthread_chdir(const char *path);
int
-pthread_chdir_np(char *path)
+pthread_chdir_np(const char *path)
{
return __pthread_chdir(path);
}
pr->__pdep_owner, 0);
switch (-ret) {
case EFAULT:
- if (pr->__pdep_opaque1 == pr->__pdep_owner) goto again;
+ case EINTR:
case 0:
+ if (pr->__pdep_opaque1 == pr->__pdep_owner) goto again;
break;
case EOWNERDEAD:
PTHREAD_CLIENT_CRASH(pr->__pdep_owner, "Waiting on orphaned dependency");
_pthread_mutex_global_init(const char *envp[],
struct _pthread_registration_data *registration_data)
{
-
int opt = _PTHREAD_MTX_OPT_POLICY_DEFAULT;
if (registration_data->mutex_default_policy) {
int policy = registration_data->mutex_default_policy;
int
_pthread_mutex_corruption_abort(_pthread_mutex *mutex)
{
- PTHREAD_ABORT("pthread_mutex corruption: mutex owner changed in the "
- "middle of lock/unlock");
+ PTHREAD_CLIENT_CRASH(0, "pthread_mutex corruption: mutex owner changed "
+ "in the middle of lock/unlock");
}
res = 0;
}
if (res != 0) {
- PTHREAD_ABORT("__psynch_mutexdrop failed with error %d", res);
+ PTHREAD_INTERNAL_CRASH(res, "__psynch_mutexdrop failed");
}
return res;
}
res = 0;
}
if (res != 0) {
- PTHREAD_ABORT("__psynch_mutexdrop failed with error %d", res);
+ PTHREAD_INTERNAL_CRASH(res, "__psynch_mutexdrop failed");
}
return res;
}
switch (seqfields) {
case RWLOCK_SEQ_LSU:
#if RWLOCK_USE_INT128
+#if defined(__arm64__) && defined(__ARM_ARCH_8_2__)
+ // Workaround clang armv81 codegen bug for 128bit os_atomic_load
+ // rdar://problem/31213932
+ oldseqval->seq_LSU = seqaddr->seq_LSU;
+ while (!os_atomic_cmpxchgvw(&seqaddr->atomic_seq_LSU,
+ oldseqval->seq_LSU, oldseqval->seq_LSU, &oldseqval->seq_LSU,
+ relaxed));
+#else
oldseqval->seq_LSU = os_atomic_load(&seqaddr->atomic_seq_LSU, relaxed);
+#endif
#else
oldseqval->seq_LS = os_atomic_load(&seqaddr->atomic_seq_LS, relaxed);
oldseqval->seq_U = os_atomic_load(&seqaddr->atomic_seq_U, relaxed);
PLOCKSTAT_RW_BLOCKED(orwlock, plockstat, BLOCK_SUCCESS_PLOCKSTAT);
} else {
PLOCKSTAT_RW_BLOCKED(orwlock, plockstat, BLOCK_FAIL_PLOCKSTAT);
- PTHREAD_ABORT("kernel rwlock returned unknown error %x: "
- "tid %llx\n", res, _pthread_selfid_direct());
+ PTHREAD_INTERNAL_CRASH(res, "kernel rwlock returned unknown error");
}
return res;
} while (res == EINTR);
if (res != 0) {
- PTHREAD_ABORT("kernel rwunlock returned unknown error %x: "
- "tid %llx\n", res, _pthread_selfid_direct());
+ PTHREAD_INTERNAL_CRASH(res, "kernel rwunlock returned unknown error");
}
return res;
+++ /dev/null
-/*
- * Copyright (c) 2012 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@
- */
-
-#include "internal.h"
-#include <dlfcn.h>
-#include <_simple.h>
-
-
-#define __SIGABRT 6
-
-/* We should move abort() into Libsyscall, if possible. */
-int __getpid(void);
-
-int
-__kill(int pid, int signum, int posix);
-
-void
-__pthread_abort(void)
-{
- PTHREAD_NORETURN void (*_libc_abort)(void);
- _libc_abort = dlsym(RTLD_DEFAULT, "abort");
-
- if (_libc_abort) {
- _libc_abort();
- } else {
- __kill(__getpid(), __SIGABRT, 0);
- }
- __builtin_trap();
-}
-
-void
-__pthread_abort_reason(const char *fmt, ...)
-{
- __pthread_abort();
-}
#include "internal.h"
#include <TargetConditionals.h>
+#ifndef PTHREAD_KEY_LEGACY_SUPPORT
+#if TARGET_OS_DRIVERKIT
+#define PTHREAD_KEY_LEGACY_SUPPORT 0
+#else
+#define PTHREAD_KEY_LEGACY_SUPPORT 1
+#endif // TARGET_OS_DRIVERKIT
+#endif // PTHREAD_KEY_LEGACY_SUPPORT
+
#if !VARIANT_DYLD
// __pthread_tsd_first is first static key managed by libpthread.
// __pthread_tsd_max is the (observed) end of static key destructors.
static int __pthread_tsd_max = __pthread_tsd_first;
static _pthread_lock __pthread_tsd_lock = _PTHREAD_LOCK_INITIALIZER;
+#if PTHREAD_KEY_LEGACY_SUPPORT
static bool __pthread_key_legacy_behaviour = 0;
static bool __pthread_key_legacy_behaviour_log = 0;
+#else
+#define __pthread_key_legacy_behaviour 0
+#define _pthread_tsd_cleanup_legacy(...)
+#endif // PTHREAD_KEY_LEGACY_SUPPORT
// Omit support for pthread key destructors in the static archive for dyld.
// dyld does not create and destroy threads so these are not necessary.
void
_pthread_key_global_init(const char *envp[])
{
+#if PTHREAD_KEY_LEGACY_SUPPORT
if (_simple_getenv(envp, "PTHREAD_KEY_LEGACY_DESTRUCTOR_ORDER")) {
__pthread_key_legacy_behaviour = true;
}
if (_simple_getenv(envp, "PTHREAD_KEY_LEGACY_DESTRUCTOR_ORDER_LOG")) {
__pthread_key_legacy_behaviour_log = true;
}
+#endif // PTHREAD_KEY_LEGACY_SUPPORT
}
// Returns true if successful, false if destructor was already set.
}
#endif // !VARIANT_DYLD
-#import <_simple.h>
-#import <dlfcn.h>
-
#if !VARIANT_DYLD
static void
_pthread_tsd_cleanup_new(pthread_t self)
self->max_tsd_key = 0;
}
+#if PTHREAD_KEY_LEGACY_SUPPORT
+#import <_simple.h>
+#import <dlfcn.h>
static void
_pthread_tsd_behaviour_check(pthread_t self)
{
}
}
}
+#endif // PTHREAD_KEY_LEGACY_SUPPORT
#endif // !VARIANT_DYLD
void
case WORKQ_LOW_PRIOQUEUE: qos = THREAD_QOS_UTILITY; break;
case WORKQ_BG_PRIOQUEUE: qos = THREAD_QOS_BACKGROUND; break;
default:
- __pthread_abort();
+ PTHREAD_CLIENT_CRASH(queue_priority, "Invalid priority");
}
return _pthread_priority_make_from_thread_qos(qos, 0, flags);
}
_pthread_set_flags_t kflags = flags;
int rv = 0;
- if (self->wqoutsideqos && (flags & _PTHREAD_SET_SELF_OUTSIDE_QOS_SKIP)) {
+ if (self->wq_outsideqos && (flags & _PTHREAD_SET_SELF_OUTSIDE_QOS_SKIP)) {
// A number of properties cannot be altered if we are a workloop
// thread that has outside of QoS properties applied to it.
kflags &= ~_PTHREAD_SET_SELF_OUTSIDE_QOS_SKIP;
+++ /dev/null
-/*
- * Copyright (c) 2000-2003, 2008, 2012 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@
- */
-/*
- * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
- * All Rights Reserved
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appears in all copies and
- * that both the copyright notice and this permission notice appear in
- * supporting documentation.
- *
- * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE.
- *
- * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
- * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-/*
- * MkLinux
- */
-
-#include "internal.h"
-
-#if !defined(__OPEN_SOURCE__) && TARGET_OS_OSX // 40703288
-/*
- * Machine specific support for thread initialization
- */
-
-// NOTE: no resolvers, so this file must not contain any atomic operations
-
-PTHREAD_NOEXPORT void _pthread_setup_suspended(pthread_t th, void (*f)(pthread_t), void *sp);
-
-/*
- * Set up the initial state of a MACH thread
- */
-void
-_pthread_setup_suspended(pthread_t thread,
- void (*routine)(pthread_t),
- void *vsp)
-{
-#if defined(__i386__)
- i386_thread_state_t state = { };
- thread_state_flavor_t flavor = x86_THREAD_STATE32;
- mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
-#elif defined(__x86_64__)
- x86_thread_state64_t state = { };
- thread_state_flavor_t flavor = x86_THREAD_STATE64;
- mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
-#else
-#error _pthread_setup not defined for this architecture
-#endif
-
- (void)thread_get_state(_pthread_kernel_thread(thread),
- flavor, (thread_state_t)&state, &count);
-
-#if defined(__i386__)
- uintptr_t *sp = vsp;
-
- state.__eip = (uintptr_t)routine;
-
- // We need to simulate a 16-byte aligned stack frame as if we had
- // executed a call instruction. Since we're "pushing" one argument,
- // we need to adjust the pointer by 12 bytes (3 * sizeof (int *))
- sp -= 3; // make sure stack is aligned
- *--sp = (uintptr_t)thread; // argument to function
- *--sp = 0; // fake return address
- state.__esp = (uintptr_t)sp; // set stack pointer
-#elif defined(__x86_64__)
- uintptr_t *sp = vsp;
-
- state.__rip = (uintptr_t)routine;
-
- // We need to simulate a 16-byte aligned stack frame as if we had
- // executed a call instruction. The stack should already be aligned
- // before it comes to us and we don't need to push any arguments,
- // so we shouldn't need to change it.
- state.__rdi = (uintptr_t)thread; // argument to function
- *--sp = 0; // fake return address
- state.__rsp = (uintptr_t)sp; // set stack pointer
-#else
-#error _pthread_setup_suspended not defined for this architecture
-#endif
-
- (void)thread_set_state(_pthread_kernel_thread(thread), flavor, (thread_state_t)&state, count);
-}
-#endif // !defined(__OPEN_SOURCE__) && TARGET_OS_OSX
#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
* system responsiveness for the user.
* This is SPI for use by Spotlight and Time Machine only.
*/
-#define QOS_CLASS_MAINTENANCE 0x05
+#define QOS_CLASS_MAINTENANCE ((qos_class_t)0x05)
#endif //_QOS_SYS_PRIVATE_H
TARGETS += pthread_attr_setstacksize
TARGETS += pthread_bulk_create
TARGETS += pthread_cancel
+TARGETS += pthread_create_from_mach_thread
TARGETS += pthread_cwd
TARGETS += pthread_exit
TARGETS += pthread_introspection
#TARGETS += rwlock-signal
#TARGETS += rwlock
TARGETS += tsd
+TARGETS += setrlimit_sigsegv
#TARGETS += wq_block_handoff
#TARGETS += wq_event_manager
#TARGETS += wq_kevent
TARGETS += add_timer_termination
TARGETS += perf_contended_mutex_rwlock
+# this should be CUSTOM_TARGETS, see "Compatibility defines" in Makefile.targets
+OTHER_TARGETS := stackoverflow_crash
+
OTHER_LTE_INCLUDE_FILES += \
/usr/local/lib/libdarwintest_utils.dylib
bsdthread_set_self: OTHER_CFLAGS += -D_DARWIN_FEATURE_CLOCK_GETTIME
include $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.targets
+
+stackoverflow_crash: helpers/stackoverflow_crash.c
+ mkdir -p $(SYMROOT)/assets/
+ $(CC) -o $(SYMROOT)/assets/$@ $(CFLAGS) -D_POSIX_C_SOURCE=1 $(OTHER_CFLAGS) $(LDFLAGS) $(OTHER_LDFLAGS) $<
+ env CODESIGN_ALLOCATE=$(CODESIGN_ALLOCATE) $(CODESIGN) --force --sign - --timestamp=none $(SYMROOT)/assets/$@
+
+install-stackoverflow_crash: stackoverflow_crash
+ mkdir -p $(INSTALLDIR)/assets
+ @cp $(SYMROOT)/assets/stackoverflow_crash $(INSTALLDIR)/assets
#include "darwintest_defaults.h"
#define NUM_THREADS 8
+#define RDAR_38144536 1
struct context {
pthread_cond_t cond;
T_DECL(cond_timedwait_zerotimeout, "pthread_cond_timedwait() with zero timeout, ensure mutex is unlocked")
{
+#if RDAR_38144536
+ T_SKIP("skipped <rdar://38144536>");
+#else // RDAR_38144536
cond_timedwait_timeouts_internal(eZeroTimeout, false);
+#endif // RDAR_38144536
}
T_DECL(cond_timedwait_beforeepochtimeout, "pthread_cond_timedwait() with timeout before the epoch, ensure mutex is unlocked")
{
+#if RDAR_38144536
+ T_SKIP("skipped <rdar://38144536>");
+#else // RDAR_38144536
cond_timedwait_timeouts_internal(eBeforeEpochTimeout, false);
+#endif // RDAR_38144536
}
T_DECL(cond_timedwait_pasttimeout, "pthread_cond_timedwait() with timeout in the past, ensure mutex is unlocked")
{
+#if RDAR_38144536
+ T_SKIP("skipped <rdar://38144536>");
+#else // RDAR_38144536
cond_timedwait_timeouts_internal(eRecentPastTimeout, false);
+#endif // RDAR_38144536
}
T_DECL(cond_timedwait_relative_nulltimeout, "pthread_cond_timedwait_relative_np() with relative NULL timeout, ensure mutex is unlocked")
--- /dev/null
+#include<stdio.h>
+#include<sys/resource.h>
+
+static volatile int * array1_ref = NULL;
+static long last_stack_addr = 0;
+
+static void
+recursive_fn(void)
+{
+ volatile int array1[1024]; /* leave this as it is */
+ int addr;
+ last_stack_addr = (long)&addr;
+ array1_ref = array1; /* make sure compiler cannot discard storage */
+ array1[0] = 0;
+ if (array1_ref == 0) {
+ /* fool clang -Winfinite-recursion */
+ return;
+ }
+ recursive_fn();
+ return;
+}
+
+int
+main(__unused int argc, __unused const char *argv[])
+{
+ struct rlimit save;
+
+ if (getrlimit(RLIMIT_STACK, &save) == -1) {
+ printf("child: ERROR - getrlimit");
+ return 2;
+ }
+ printf("child: LOG - current stack limits cur=0x%llx, max=0x%llx, inf=0x%llx\n", save.rlim_cur, save.rlim_max, RLIM_INFINITY);
+
+ if(save.rlim_cur >= save.rlim_max) {
+ printf("child: ERROR - invalid limits");
+ return 2;
+ }
+
+ if(save.rlim_max == RLIM_INFINITY) {
+ printf("child: ERROR - rlim_max = RLIM_INFINITY");
+ return 2;
+ }
+
+ save.rlim_cur += 4;
+
+ printf("child: LOG - Raising setrlimit rlim_cur=0x%llx, rlim_max=0x%llx\n", save.rlim_cur, save.rlim_max);
+
+ if (setrlimit(RLIMIT_STACK, &save) == -1) {
+ printf("child: ERROR - Raising the limits failed.");
+ return 2;
+ }
+
+ printf("child: LOG - Make the stack grow such that a SIGSEGV is generated.\n");
+ recursive_fn();
+ return 0;
+}
--- /dev/null
+
+#include <pthread.h>
+#include <mach/mach.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread_spis.h>
+
+#include "darwintest_defaults.h"
+
+#define CHILD_STACK_COUNT 1024
+static uint64_t child_stack[CHILD_STACK_COUNT];
+
+static void*
+pthread_runner(void* __unused arg)
+{
+ T_PASS("mach -> pthread conversion successful");
+ T_END;
+}
+
+static void *
+mach_bootstrap(void * __unused arg)
+{
+ pthread_t thread;
+ pthread_create_from_mach_thread(&thread, NULL, pthread_runner, NULL);
+ while (1) {
+ swtch_pri(0); // mach_yield
+ }
+}
+
+T_DECL(pthread_create_from_mach_thread, "pthread_create_from_mach_thread",
+ T_META_ALL_VALID_ARCHS(YES),
+ // Having leaks running will suppress the behavior we are testing
+ T_META_CHECK_LEAKS(false),
+ T_META_ENVVAR("MallocStackLogging=1")
+ )
+{
+ T_PASS("MallocStackLogging: %s", getenv("MallocStackLogging"));
+
+ // Create a mach_thread to start with
+ mach_port_t task = mach_task_self();
+
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t count;
+
+ uintptr_t start_addr = (uintptr_t)&mach_bootstrap;
+ // Force alignment to 16-bytes
+ uintptr_t stack_top = ((uintptr_t)&child_stack[CHILD_STACK_COUNT]) & ~0xf;
+
+#if defined(__x86_64__)
+ T_PASS("x86_64");
+ flavor = x86_THREAD_STATE64;
+ count = x86_THREAD_STATE64_COUNT;
+ x86_thread_state64_t state = {
+ .__rip = start_addr,
+ // Must be 16-byte-off-by-8 aligned <rdar://problem/15886599>
+ .__rsp = stack_top - 8,
+ };
+#elif defined(__arm64__)
+ T_PASS("arm64");
+ flavor = ARM_THREAD_STATE64;
+ count = ARM_THREAD_STATE64_COUNT;
+ arm_thread_state64_t state = { };
+ arm_thread_state64_set_pc_fptr(state, &mach_bootstrap);
+ arm_thread_state64_set_sp(state, stack_top);
+ (void)start_addr;
+#elif defined(__arm__)
+ T_PASS("arm (32)");
+ flavor = ARM_THREAD_STATE;
+ count = ARM_THREAD_STATE_COUNT;
+ arm_thread_state_t state = {
+ .__pc = start_addr,
+ .__sp = stack_top,
+ .__cpsr = 0x20,
+ };
+#else
+#error Unknown architecture
+#endif
+
+ thread_state_t state_ptr = (thread_state_t)&state;
+ thread_t task_thread;
+ T_PASS("Launching Thread");
+
+ kern_return_t ret = thread_create_running(task, flavor, state_ptr, count, &task_thread);
+ T_ASSERT_MACH_SUCCESS(ret, "mach thread created");
+ // Wait forever
+ sigset_t empty;
+ T_QUIET; T_ASSERT_POSIX_ZERO(sigemptyset(&empty), NULL);
+ while (sigsuspend(&empty)) {
+ continue;
+ }
+ T_FAIL("Didn't wait forever?");
+}
extern __uint64_t __thread_selfid( void );
-static void *do_test(void * __unused arg)
+static void *do_test(void * arg)
{
uint64_t threadid = __thread_selfid();
T_ASSERT_NE(threadid, (uint64_t)0, "__thread_selfid()");
pth_threadid = _pthread_threadid_self_np_direct();
T_EXPECT_EQ(threadid, pth_threadid, "pthread_threadid_np_direct()");
+ if (arg) {
+ *(uint64_t *)arg = pth_threadid;
+ }
return NULL;
}
do_test(NULL);
T_LOG("Pthread");
- pthread_t pth;
- T_ASSERT_POSIX_ZERO(pthread_create(&pth, NULL, do_test, NULL), NULL);
- T_ASSERT_POSIX_ZERO(pthread_join(pth, NULL), NULL);
+ for (int i = 0; i < 100; i++) {
+ uint64_t tid1 = 0, tid2 = 0;
+ pthread_t pth;
+ T_ASSERT_POSIX_ZERO(pthread_create(&pth, NULL, do_test, &tid1), NULL);
+ T_EXPECT_POSIX_ZERO(pthread_threadid_np(pth, &tid2), NULL);
+ T_ASSERT_POSIX_ZERO(pthread_join(pth, NULL), NULL);
+ T_EXPECT_EQ(tid1, tid2, "parent and child agree");
+ }
T_LOG("Workqueue Thread");
dispatch_queue_t dq = dispatch_queue_create("myqueue", NULL);
--- /dev/null
+#include "darwintest_defaults.h"
+#include <spawn.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+
+
+extern char **environ;
+
+T_DECL(setrlimit_overflow_segfault,
+ "sigsegv is sent when stack(limit set with setrlimit) is fully used.",
+ T_META_IGNORECRASHES(".*stackoverflow_crash.*"),
+ T_META_CHECK_LEAKS(NO),
+ T_META_ALL_VALID_ARCHS(YES),
+ T_META_ASROOT(YES))
+{
+ pid_t child_pid = 0;
+ int rv = 0;
+
+ struct rlimit lim, save;
+ T_ASSERT_POSIX_SUCCESS(getrlimit(RLIMIT_STACK, &save), NULL);
+ T_ASSERT_POSIX_SUCCESS(getrlimit(RLIMIT_STACK, &lim), NULL);
+ T_LOG("parent: stack limits cur=%llx max=%llx", lim.rlim_cur, lim.rlim_max);
+ lim.rlim_cur = lim.rlim_cur/8;
+ T_ASSERT_POSIX_SUCCESS(setrlimit(RLIMIT_STACK, &lim), NULL);
+ int status = 0;
+ int exit_signal = 0;
+
+ char *crash_cmd[] = { "./assets/stackoverflow_crash", NULL };
+ posix_spawn_file_actions_t fact;
+ posix_spawn_file_actions_init(&fact);
+ T_ASSERT_POSIX_SUCCESS(posix_spawn_file_actions_addinherit_np(&fact, STDIN_FILENO), NULL);
+ T_ASSERT_POSIX_SUCCESS(posix_spawn_file_actions_addinherit_np(&fact, STDOUT_FILENO), NULL);
+ T_ASSERT_POSIX_SUCCESS(posix_spawn_file_actions_addinherit_np(&fact, STDERR_FILENO), NULL);
+ T_LOG("spawning %s", crash_cmd[0]);
+ rv = posix_spawn(&child_pid, crash_cmd[0], &fact, NULL, crash_cmd, environ);
+ T_ASSERT_POSIX_SUCCESS(rv, "spawning the stackoverflow program");
+
+ T_LOG("parent: waiting for child process with pid %d", child_pid);
+ wait(&status);
+ T_LOG("parent: child process exited. status=%d", WEXITSTATUS(status));
+
+
+ T_ASSERT_POSIX_SUCCESS(setrlimit(RLIMIT_STACK, &save), "Restore original limtis");
+ posix_spawn_file_actions_destroy(&fact);
+
+ T_ASSERT_TRUE(WIFSIGNALED(status), "child exit with a signal");
+ exit_signal = WTERMSIG(status);
+ T_ASSERT_EQ(exit_signal, SIGSEGV, "child should receive SIGSEGV");
+
+ return;
+}
#define call_chkstk(value) \
__asm__ volatile("orr x9, xzr, %0\t\n" \
"bl _thread_chkstk_darwin" : : "i"(value) : "x9")
-#define TRAPSIG SIGTRAP
#elif defined(__x86_64__)
#define call_chkstk(value) \
__asm__ volatile("movq %0, %%rax\t\n" \
"callq _thread_chkstk_darwin" : : "i"(value) : "rax")
-#define TRAPSIG SIGILL
#elif defined(__i386__)
#define call_chkstk(value) \
__asm__ volatile("movl %0, %%eax\t\n" \
"calll _thread_chkstk_darwin" : : "i"(value) : "eax")
-#define TRAPSIG SIGILL
#endif
static void
call_chkstk(1 << 16);
T_PASS("calling with 1 << 16");
- signal(TRAPSIG, got_signal);
+ stack_t ss = {
+ .ss_sp = malloc(MINSIGSTKSZ),
+ .ss_size = MINSIGSTKSZ,
+ };
+ T_ASSERT_POSIX_SUCCESS(sigaltstack(&ss, NULL), "sigaltstack");
+
+ struct sigaction sa = {
+ .sa_handler = got_signal,
+ .sa_flags = SA_ONSTACK,
+ };
+ T_ASSERT_POSIX_SUCCESS(sigaction(SIGSEGV, &sa, NULL), "sigaction");
call_chkstk(1 << 24);
T_FAIL("should have crashed");
#include <stdlib.h>
#include "darwintest_defaults.h"
+#if defined(__arm64__)
+#define PTHREAD_T_OFFSET (12*1024)
+#else
#define PTHREAD_T_OFFSET (0)
+#endif
static void *
function(void *arg)
#!/bin/bash -e
+
+if [ "${DRIVERKIT}" = 1 ]; then exit 0; fi
+
# install kdebug trace files based on the input file
INPUT=${SCRIPT_INPUT_FILE_0}
OUTPUT=${SCRIPT_OUTPUT_FILE_0}
ln -sf init.py $DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME/Contents/Resources/Python/$EXECUTABLE_NAME$SUFFIX.py
done
+
+if test "$PLATFORM_NAME" != macosx; then
+ mkdir -p $DSTROOT/AppleInternal/KextObjects/Python/$MODULE_NAME || true
+ rsync -aq $SRCROOT/lldbmacros/* $DSTROOT/AppleInternal/KextObjects/Python/$MODULE_NAME
+ ln -sf init.py $DSTROOT/AppleInternal/KextObjects/Python/$MODULE_NAME/$EXECUTABLE_NAME.py
+fi
if [ "$ACTION" = installhdrs ]; then exit 0; fi
if [ "${RC_ProjectName%_Sim}" != "${RC_ProjectName}" ]; then exit 0; fi
+if [ "${DRIVERKIT}" = 1 ]; then exit 0; fi
set -x
set -e
# Symlink old header locations.
#
+DSTROOT="${DSTROOT}/${SDK_INSTALL_HEADERS_ROOT}"
+
ln -sf "pthread/pthread.h" "$DSTROOT/usr/include/pthread.h"
ln -sf "pthread/pthread_impl.h" "$DSTROOT/usr/include/pthread_impl.h"
ln -sf "pthread/pthread_spis.h" "$DSTROOT/usr/include/pthread_spis.h"
if [ "$ACTION" = build ]; then exit 0; fi
+DSTROOT="${DSTROOT}/${SDK_INSTALL_HEADERS_ROOT}"
+
DESTDIR="$DSTROOT/usr/include/sys"
mkdir -p "$DESTDIR"
for X in \
ALWAYS_SEARCH_USER_PATHS = NO
SRCROOT_SEARCH_PATHS = $(SRCROOT) $(SRCROOT)/pthread $(SRCROOT)/private
HEADER_SEARCH_PATHS = $(SDKROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders $(SDKROOT)/System/Library/Frameworks/Kernel.framework/Headers $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders $(SDKROOT)/System/Library/Frameworks/System.framework/Headers $(SRCROOT_SEARCH_PATHS)
-GCC_C_LANGUAGE_STANDARD = gnu99
+GCC_C_LANGUAGE_STANDARD = gnu11
CLANG_CXX_LANGUAGE_STANDARD = gnu++0x
CLANG_CXX_LIBRARY = libc++
GCC_PRECOMPILE_PREFIX_HEADER = YES
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
GCC_OPTIMIZATION_LEVEL_normal = s
-GCC_OPTIMIZATION_LEVEL_development = 0
+GCC_OPTIMIZATION_LEVEL_development = s
GCC_OPTIMIZATION_LEVEL = $(GCC_OPTIMIZATION_LEVEL_$(PTHREAD_VARIANT))
DEAD_CODE_STRIPPING = NO
# int-sized
___is_threaded
-___libdispatch_offset
___pthread_supported_features
___pthread_tsd_lock
___pthread_tsd_max
SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator
BUILD_VARIANTS = normal debug
-INSTALL_PATH = /usr/lib/system
+SDK_INSTALL_VARIANT = $(SDK_INSTALL_VARIANT_$(DRIVERKIT))
+SDK_INSTALL_VARIANT_1 = driverkit
+SDK_INSTALL_VARIANT_ = default
+SDK_INSTALL_ROOT = $(SDK_INSTALL_ROOT_$(SDK_INSTALL_VARIANT))
+SDK_INSTALL_ROOT_driverkit = $(DRIVERKITROOT)
+SDK_INSTALL_HEADERS_ROOT = $(SDK_INSTALL_HEADERS_ROOT_$(SDK_INSTALL_VARIANT))
+SDK_INSTALL_HEADERS_ROOT_driverkit = $(SDK_INSTALL_ROOT)/$(SDK_RUNTIME_HEADERS_PREFIX)
+SDK_RUNTIME_HEADERS_PREFIX = Runtime
+
+INSTALL_PATH = $(SDK_INSTALL_ROOT)/usr/lib/system
EXECUTABLE_PREFIX = lib
PRODUCT_NAME = system_pthread
-PUBLIC_HEADERS_FOLDER_PATH = /usr/include/pthread
-PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/pthread
+PUBLIC_HEADERS_FOLDER_PATH = $(SDK_INSTALL_HEADERS_ROOT)/usr/include/pthread
+PRIVATE_HEADERS_FOLDER_PATH = $(SDK_INSTALL_HEADERS_ROOT)/usr/local/include/pthread
SRCROOT_SEARCH_PATHS = $(SRCROOT) $(SRCROOT)/private $(SRCROOT)/os $(SRCROOT)/src/resolver
-SYSTEM_FRAMEWORK_HEADERS = $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders
-HEADER_SEARCH_PATHS = $($(PRODUCT_NAME)_SEARCH_PATHS) $(SRCROOT_SEARCH_PATHS) $(SYSTEM_FRAMEWORK_HEADERS) $(SDKROOT)/usr/local/include $(inherited)
+SYSTEM_FRAMEWORK_HEADERS = $(SDKROOT)/$(SDK_INSTALL_HEADERS_ROOT)/System/Library/Frameworks/System.framework/PrivateHeaders
+HEADER_SEARCH_PATHS = $($(PRODUCT_NAME)_SEARCH_PATHS) $(SRCROOT_SEARCH_PATHS) $(inherited)
+SYSTEM_HEADER_SEARCH_PATHS = $(SYSTEM_FRAMEWORK_HEADERS) $(SDKROOT)/$(SDK_INSTALL_HEADERS_ROOT)/usr/local/include $(SDKROOT)/$(SDK_INSTALL_HEADERS_ROOT)/usr/include
+SYSTEM_FRAMEWORK_SEARCH_PATHS = $(SDKROOT)/$(SDK_INSTALL_HEADERS_ROOT)/System/Library/Frameworks
INSTALLHDRS_SCRIPT_PHASE = YES
ALWAYS_SEARCH_USER_PATHS = YES
USE_HEADERMAP = NO
GCC_PREPROCESSOR_DEFINITIONS = $(BASE_PREPROCESSOR_MACROS) $(PLATFORM_PREPROCESSOR_DEFINITIONS)
// TODO: Remove -fstack-protector on _debug when it is moved to libplatform
-OTHER_CFLAGS = -fno-stack-protector -fno-builtin $(PLATFORM_CFLAGS) $($(PRODUCT_NAME)_CFLAGS)
+OTHER_CFLAGS = -fno-stack-protector -fno-stack-check -fno-builtin $(PLATFORM_CFLAGS) $($(PRODUCT_NAME)_CFLAGS)
OTHER_CFLAGS_normal = -momit-leaf-frame-pointer
OTHER_CFLAGS_debug = -fno-inline -O0 -DDEBUG=1
DYLIB_COMPATIBILITY_VERSION = 1
DIRTY_LDFLAGS = -Wl,-dirty_data_list,$(SRCROOT)/xcodescripts/pthread.dirty
DIRTY_LDFLAGS[sdk=macos*] =
-DYLIB_LDFLAGS = -Wl,-alias_list,$(SRCROOT)/xcodescripts/pthread.aliases -Wl,-umbrella,System -L/usr/lib/system -lsystem_kernel -lsystem_platform -ldyld -lcompiler_rt
-OTHER_LDFLAGS = $(DYLIB_LDFLAGS) $(DIRTY_LDFLAGS) $(CR_LDFLAGS) $(PLATFORM_LDFLAGS)
+DYLIB_LDFLAGS = -Wl,-alias_list,$(SRCROOT)/xcodescripts/pthread.aliases -Wl,-umbrella,System -L$(SDK_INSTALL_ROOT)/usr/lib/system -lsystem_kernel -lsystem_platform -ldyld -lcompiler_rt
+OTHER_LDFLAGS = $(DYLIB_LDFLAGS) $(DIRTY_LDFLAGS) $(CR_LDFLAGS) $(PLATFORM_LDFLAGS) $(SIMULATOR_LDFLAGS)
+
+SIMULATOR_LDFLAGS =
+SIMULATOR_LDFLAGS[sdk=macosx*] = -Wl,-simulator_support
+IS_ZIPPERED = YES
+
// Simulator build rules
EXCLUDED_SOURCE_FILE_NAMES[sdk=iphonesimulator*] = *.c *.s
SKIP_INSTALL[sdk=iphonesimulator*] = YES
OTHER_LDFLAGS[sdk=iphonesimulator*] =
-