// Thread keys reserved by libc for our use.
-// Keys [0..4] are used by autozone.
-#if defined(__PTK_FRAMEWORK_OBJC_KEY5)
+#if defined(__PTK_FRAMEWORK_OBJC_KEY0)
# define SUPPORT_DIRECT_THREAD_KEYS 1
-# define TLS_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY5)
-# define SYNC_DATA_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY6)
-# define SYNC_COUNT_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY7)
-# define AUTORELEASE_POOL_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY8)
+# define TLS_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY0)
+# define SYNC_DATA_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY1)
+# define SYNC_COUNT_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY2)
+# define AUTORELEASE_POOL_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY3)
# if SUPPORT_RETURN_AUTORELEASE
-# define AUTORELEASE_POOL_RECLAIM_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY9)
+# define AUTORELEASE_POOL_RECLAIM_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY4)
+# endif
+# if SUPPORT_QOS_HACK
+# define QOS_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY5)
# endif
#else
# define SUPPORT_DIRECT_THREAD_KEYS 0
|| k == AUTORELEASE_POOL_KEY
# if SUPPORT_RETURN_AUTORELEASE
|| k == AUTORELEASE_POOL_RECLAIM_KEY
+# endif
+# if SUPPORT_QOS_HACK
+ || k == QOS_KEY
# endif
);
}
#endif
+static inline pthread_t pthread_self_direct()
+{
+ return (pthread_t)
+ _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);
+}
+
+static inline mach_port_t mach_thread_self_direct()
+{
+ return (mach_port_t)(uintptr_t)
+ _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF);
+}
+
+#if SUPPORT_QOS_HACK
+static inline pthread_priority_t pthread_self_priority_direct()
+{
+ pthread_priority_t pri = (pthread_priority_t)
+ _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS);
+ return pri & ~_PTHREAD_PRIORITY_FLAGS_MASK;
+}
+#endif
+
+
typedef pthread_mutex_t mutex_t;
#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER;
}
+#if SUPPORT_QOS_HACK
+// Override QOS class to avoid priority inversion in rwlocks
+// <rdar://17697862> do a qos override before taking rw lock in objc
+
+#include <pthread/workqueue_private.h>
+extern pthread_priority_t BackgroundPriority;
+extern pthread_priority_t MainPriority;
+
+static inline void qosStartOverride()
+{
+ uintptr_t overrideRefCount = (uintptr_t)tls_get_direct(QOS_KEY);
+ if (overrideRefCount > 0) {
+ // If there is a qos override, increment the refcount and continue
+ tls_set_direct(QOS_KEY, (void *)(overrideRefCount + 1));
+ }
+ else {
+ pthread_priority_t currentPriority = pthread_self_priority_direct();
+ // Check if override is needed. Only override if we are background qos
+ if (currentPriority <= BackgroundPriority) {
+ int res __unused = _pthread_override_qos_class_start_direct(mach_thread_self_direct(), MainPriority);
+ assert(res == 0);
+ // Once we override, we set the reference count in the tsd
+ // to know when to end the override
+ tls_set_direct(QOS_KEY, (void *)1);
+ }
+ }
+}
+
+static inline void qosEndOverride()
+{
+ uintptr_t overrideRefCount = (uintptr_t)tls_get_direct(QOS_KEY);
+ if (overrideRefCount == 0) return;
+
+ if (overrideRefCount == 1) {
+ // end the override
+ int res __unused = _pthread_override_qos_class_end_direct(mach_thread_self_direct());
+ assert(res == 0);
+ }
+
+ // decrement refcount
+ tls_set_direct(QOS_KEY, (void *)(overrideRefCount - 1));
+}
+
+// SUPPORT_QOS_HACK
+#else
+// not SUPPORT_QOS_HACK
+
+static inline void qosStartOverride() { }
+static inline void qosEndOverride() { }
+
+// not SUPPORT_QOS_HACK
+#endif
+
/* Custom read-write lock
- reader is atomic add/subtract
- writer is pthread mutex plus atomic add/subtract
static inline void _rwlock_read_nodebug(rwlock_t *l)
{
+ qosStartOverride();
int err __unused = pthread_rwlock_rdlock(&l->rwl);
assert(err == 0);
}
{
int err __unused = pthread_rwlock_unlock(&l->rwl);
assert(err == 0);
+ qosEndOverride();
}
static inline bool _rwlock_try_read_nodebug(rwlock_t *l)
{
+ qosStartOverride();
int err = pthread_rwlock_tryrdlock(&l->rwl);
- assert(err == 0 || err == EBUSY);
- return (err == 0);
+ assert(err == 0 || err == EBUSY || err == EAGAIN);
+ if (err == 0) {
+ return true;
+ } else {
+ qosEndOverride();
+ return false;
+ }
}
static inline void _rwlock_write_nodebug(rwlock_t *l)
{
+ qosStartOverride();
int err __unused = pthread_rwlock_wrlock(&l->rwl);
assert(err == 0);
}
{
int err __unused = pthread_rwlock_unlock(&l->rwl);
assert(err == 0);
+ qosEndOverride();
}
static inline bool _rwlock_try_write_nodebug(rwlock_t *l)
{
+ qosStartOverride();
int err = pthread_rwlock_trywrlock(&l->rwl);
assert(err == 0 || err == EBUSY);
- return (err == 0);
+ if (err == 0) {
+ return true;
+ } else {
+ qosEndOverride();
+ return false;
+ }
}
.long 0 /* table.clsopt_offset */
.space PAGE_MAX_SIZE-16
-/* space for selopt, smax/capacity=262144, blen/mask=65535+1 */
-.space 65536
+/* space for selopt, smax/capacity=262144, blen/mask=131071+1 */
+.space 131072 /* mask tab */
.space 262144 /* checkbytes */
.space 262144*4 /* offsets */
-
-/* space for clsopt, smax/capacity=32768, blen/mask=4095+1 */
-.space PAGE_MAX_SIZE
+/* space for clsopt, smax/capacity=32768, blen/mask=16383+1 */
+.space 16384 /* mask tab */
.space 32768 /* checkbytes */
.space 32768*12 /* offsets to name and class and header_info */
.space PAGE_MAX_SIZE /* some duplicate classes */