From 3e7be3d344c094f6fee3cc994e5d23f8bccff4fd Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 11 Mar 2014 19:54:31 +0000 Subject: [PATCH] libdispatch-339.90.1.tar.gz --- private/introspection_private.h | 110 +++++++++++++++++++++++++-- src/introspection.c | 30 +++++++- src/introspection_internal.h | 6 ++ src/queue.c | 11 ++- src/queue_internal.h | 2 + src/shims/tsd.h | 20 +++++ src/source.c | 1 + xcodeconfig/libdispatch.interposable | 1 + 8 files changed, 170 insertions(+), 11 deletions(-) diff --git a/private/introspection_private.h b/private/introspection_private.h index 727d971..dd18bee 100644 --- a/private/introspection_private.h +++ b/private/introspection_private.h @@ -38,9 +38,9 @@ * loaded by running a process with the environment variable * DYLD_LIBRARY_PATH=/usr/lib/system/introspection * - * NOTE: these functions are _not_ exported from the shared library, they are - * only intended to be called from a debugger context while the rest of the - * process is suspended. + * NOTE: most of these functions are _not_ exported from the shared library, + * the unexported functions are intended to only be called from a debugger + * context while the rest of the process is suspended. */ #ifndef __BEGIN_DECLS @@ -68,7 +68,13 @@ typedef struct dispatch_queue_s *dispatch_queue_t; typedef struct dispatch_source_s *dispatch_source_t; typedef struct dispatch_group_s *dispatch_group_t; typedef struct dispatch_object_s *dispatch_object_t; +#ifndef __OSX_AVAILABLE_STARTING +#define __OSX_AVAILABLE_STARTING(x,y) #endif +#ifndef DISPATCH_EXPORT +#define DISPATCH_EXPORT extern +#endif +#endif // __DISPATCH_INDIRECT__ /*! * @typedef dispatch_introspection_versions_s @@ -79,6 +85,43 @@ typedef struct dispatch_object_s *dispatch_object_t; * @field introspection_version * Version of overall dispatch_introspection SPI. * + * @field hooks_version + * Version of dispatch_introspection_hooks_s structure. + * Version 2 adds the queue_item_complete member. + * + * @field hooks_size + * Size of dispatch_introspection_hooks_s structure. + * + * @field queue_item_version + * Version of dispatch_introspection_queue_item_s structure. + * + * @field queue_item_size + * Size of dispatch_introspection_queue_item_s structure. + * + * @field queue_block_version + * Version of dispatch_introspection_queue_block_s structure. + * + * @field queue_block_size + * Size of dispatch_introspection_queue_block_s structure. + * + * @field queue_function_version + * Version of dispatch_introspection_queue_function_s structure. + * + * @field queue_function_size + * Size of dispatch_introspection_queue_function_s structure. + * + * @field queue_thread_version + * Version of dispatch_introspection_queue_thread_s structure. + * + * @field queue_thread_size + * Size of dispatch_introspection_queue_thread_s structure. + * + * @field object_version + * Version of dispatch_introspection_object_s structure. + * + * @field object_size + * Size of dispatch_introspection_object_s structure. + * * @field queue_version * Version of dispatch_introspection_queue_s structure. * @@ -467,6 +510,27 @@ typedef void (*dispatch_introspection_hook_queue_item_enqueue_t)( typedef void (*dispatch_introspection_hook_queue_item_dequeue_t)( dispatch_queue_t queue, dispatch_introspection_queue_item_t item); +/*! + * @typedef dispatch_introspection_hook_queue_item_complete_t + * + * @abstract + * A function pointer called when an item previously dequeued from a dispatch + * queue has completed processing. + * + * @discussion + * The object pointer value passed to this function pointer must be treated as a + * value only. It is intended solely for matching up with an earlier call to a + * dequeue hook function pointer by comparing to the first member of the + * dispatch_introspection_queue_item_t structure. It must NOT be dereferenced + * or e.g. passed to dispatch_introspection_queue_item_get_info(), the memory + * that was backing it may have been reused at the time this hook is called. + * + * @param object + * Opaque dentifier for completed item. Must NOT be dereferenced. + */ +typedef void (*dispatch_introspection_hook_queue_item_complete_t)( + dispatch_continuation_t object); + /*! * @typedef dispatch_introspection_hooks_s * @@ -479,7 +543,8 @@ typedef struct dispatch_introspection_hooks_s { dispatch_introspection_hook_queue_dispose_t queue_dispose; dispatch_introspection_hook_queue_item_enqueue_t queue_item_enqueue; dispatch_introspection_hook_queue_item_dequeue_t queue_item_dequeue; - void *_reserved[6]; + dispatch_introspection_hook_queue_item_complete_t queue_item_complete; + void *_reserved[5]; } dispatch_introspection_hooks_s; typedef dispatch_introspection_hooks_s *dispatch_introspection_hooks_t; @@ -638,7 +703,8 @@ dispatch_introspection_queue_item_get_info(dispatch_queue_t queue, * * @discussion * Installing hook functions must take place from a debugger context (while the - * rest of the process is suspended). + * rest of the process is suspended) or early enough in the process lifecycle + * that the process is still single-threaded. * * The caller is responsible for implementing chaining to the hooks that were * previously installed (if any). @@ -650,7 +716,8 @@ dispatch_introspection_queue_item_get_info(dispatch_queue_t queue, * hooks on output. */ -extern void +__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0) +DISPATCH_EXPORT void dispatch_introspection_hooks_install(dispatch_introspection_hooks_t hooks); /*! @@ -722,6 +789,37 @@ extern void dispatch_introspection_hook_callout_queue_item_dequeue( dispatch_queue_t queue, dispatch_introspection_queue_item_t item); +/*! + * @function dispatch_introspection_hook_callout_queue_item_complete + * + * @abstract + * Callout to queue item complete hook that a debugger can break on. + */ + +extern void +dispatch_introspection_hook_callout_queue_item_complete( + dispatch_continuation_t object); + +/*! + * @function dispatch_introspection_hook_queue_item_complete + * + * @abstract + * Interposable hook function called when an item previously dequeued from a + * dispatch queue has completed processing. + * + * @discussion + * The object pointer value passed to this function must be treated as a value + * only. It is intended solely for matching up with an earlier call to a + * dequeue hook function and must NOT be dereferenced. + * + * @param item + * Opaque dentifier for completed item. Must NOT be dereferenced. + */ + +DISPATCH_EXPORT +void +dispatch_introspection_hook_queue_item_complete(dispatch_object_t item); + __END_DECLS #endif diff --git a/src/introspection.c b/src/introspection.c index 5338f25..d1dd04d 100644 --- a/src/introspection.c +++ b/src/introspection.c @@ -85,7 +85,7 @@ _dispatch_introspection_init(void) const struct dispatch_introspection_versions_s dispatch_introspection_versions = { .introspection_version = 1, - .hooks_version = 1, + .hooks_version = 2, .hooks_size = sizeof(dispatch_introspection_hooks_s), .queue_item_version = 1, .queue_item_size = sizeof(dispatch_introspection_queue_item_s), @@ -390,6 +390,7 @@ dispatch_introspection_hooks_s _dispatch_introspection_hook_callouts_enabled = { .queue_dispose = DISPATCH_INTROSPECTION_NO_HOOK, .queue_item_enqueue = DISPATCH_INTROSPECTION_NO_HOOK, .queue_item_dequeue = DISPATCH_INTROSPECTION_NO_HOOK, + .queue_item_complete = DISPATCH_INTROSPECTION_NO_HOOK, }; #define DISPATCH_INTROSPECTION_HOOKS_COUNT (( \ @@ -419,6 +420,7 @@ DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_create); DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_destroy); DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_enqueue); DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_dequeue); +DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_complete); DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_callout_begin); DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_callout_end); @@ -564,7 +566,7 @@ _dispatch_introspection_queue_item_dequeue_hook(dispatch_queue_t dq, { dispatch_introspection_queue_item_s diqi; diqi = dispatch_introspection_queue_item_get_info(dq, dou._dc); - dispatch_introspection_hook_callout_queue_item_enqueue(dq, &diqi); + dispatch_introspection_hook_callout_queue_item_dequeue(dq, &diqi); } void @@ -578,6 +580,30 @@ _dispatch_introspection_queue_item_dequeue(dispatch_queue_t dq, } } +DISPATCH_NOINLINE +void +dispatch_introspection_hook_callout_queue_item_complete( + dispatch_continuation_t object) +{ + DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_item_complete, object); +} + +DISPATCH_NOINLINE +static void +_dispatch_introspection_queue_item_complete_hook(dispatch_object_t dou) +{ + dispatch_introspection_hook_callout_queue_item_complete(dou._dc); +} + +void +_dispatch_introspection_queue_item_complete(dispatch_object_t dou) +{ + DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_item_complete, dou); + if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_item_complete)) { + _dispatch_introspection_queue_item_complete_hook(dou); + } +} + void _dispatch_introspection_callout_entry(void *ctxt, dispatch_function_t f) { dispatch_queue_t dq = _dispatch_queue_get_current(); diff --git a/src/introspection_internal.h b/src/introspection_internal.h index 89a9360..7b015aa 100644 --- a/src/introspection_internal.h +++ b/src/introspection_internal.h @@ -42,6 +42,7 @@ void _dispatch_introspection_queue_item_enqueue(dispatch_queue_t dq, dispatch_object_t dou); void _dispatch_introspection_queue_item_dequeue(dispatch_queue_t dq, dispatch_object_t dou); +void _dispatch_introspection_queue_item_complete(dispatch_object_t dou); void _dispatch_introspection_callout_entry(void *ctxt, dispatch_function_t f); void _dispatch_introspection_callout_return(void *ctxt, dispatch_function_t f); @@ -104,6 +105,11 @@ static inline void _dispatch_introspection_queue_pop(dispatch_queue_t dq DISPATCH_UNUSED, dispatch_object_t dou DISPATCH_UNUSED) {} +DISPATCH_ALWAYS_INLINE +static inline void +_dispatch_introspection_queue_item_complete( + dispatch_object_t dou DISPATCH_UNUSED) {} + DISPATCH_ALWAYS_INLINE static inline void _dispatch_introspection_callout_entry(void *ctxt DISPATCH_UNUSED, diff --git a/src/queue.c b/src/queue.c index 0568762..0c05b0b 100644 --- a/src/queue.c +++ b/src/queue.c @@ -1345,15 +1345,17 @@ _dispatch_continuation_redirect(dispatch_queue_t dq, dispatch_object_t dou) { dispatch_continuation_t dc = dou._dc; - _dispatch_trace_continuation_pop(dq, dou); (void)dispatch_atomic_add2o(dq, dq_running, 2, acquire); if (!DISPATCH_OBJ_IS_VTABLE(dc) && (long)dc->do_vtable & DISPATCH_OBJ_SYNC_SLOW_BIT) { + _dispatch_trace_continuation_pop(dq, dou); _dispatch_thread_semaphore_signal( (_dispatch_thread_semaphore_t)dc->dc_other); + _dispatch_introspection_queue_item_complete(dou); } else { _dispatch_async_f_redirect(dq, dc); } + _dispatch_perfmon_workitem_inc(); } DISPATCH_ALWAYS_INLINE_NDEBUG @@ -1389,6 +1391,7 @@ _dispatch_continuation_pop(dispatch_object_t dou) dispatch_group_leave(dg); _dispatch_release(dg); } + _dispatch_introspection_queue_item_complete(dou); if (slowpath(dc1)) { _dispatch_continuation_free_to_cache_limit(dc1); } @@ -1700,6 +1703,7 @@ _dispatch_barrier_sync_f_pop(dispatch_queue_t dq, dispatch_object_t dou, // returns (void)dispatch_atomic_add2o(dq, dq_running, 2, relaxed); } + _dispatch_introspection_queue_item_complete(dou); return sema ? sema : MACH_PORT_DEAD; } @@ -1715,7 +1719,7 @@ _dispatch_barrier_sync_f_slow_invoke(void *ctxt) #if DISPATCH_COCOA_COMPAT if (slowpath(dq->dq_is_thread_bound)) { // The queue is bound to a non-dispatch thread (e.g. main thread) - dc->dc_func(dc->dc_ctxt); + _dispatch_client_callout(dc->dc_ctxt, dc->dc_func); dispatch_atomic_store2o(dc, dc_func, NULL, release); _dispatch_thread_semaphore_signal(sema); // release return; @@ -1985,7 +1989,8 @@ _dispatch_sync_f2(dispatch_queue_t dq, void *ctxt, dispatch_function_t func) return _dispatch_sync_f_slow(dq, ctxt, func, false); } uint32_t running = dispatch_atomic_add2o(dq, dq_running, 2, relaxed); - if (slowpath(running & 1)) { + // re-check suspension after barrier check + if (slowpath(running & 1) || slowpath(DISPATCH_OBJECT_SUSPENDED(dq))) { running = dispatch_atomic_sub2o(dq, dq_running, 2, relaxed); return _dispatch_sync_f_slow(dq, ctxt, func, running == 0); } diff --git a/src/queue_internal.h b/src/queue_internal.h index 4f42d24..5f6476a 100644 --- a/src/queue_internal.h +++ b/src/queue_internal.h @@ -270,6 +270,7 @@ _dispatch_queue_class_invoke(dispatch_object_t dou, if (sema) { _dispatch_thread_semaphore_signal(sema); } else if (tq) { + _dispatch_introspection_queue_item_complete(dq); return _dispatch_queue_push(tq, dq); } } @@ -281,6 +282,7 @@ _dispatch_queue_class_invoke(dispatch_object_t dou, _dispatch_wakeup(dq); // verify that the queue is idle } } + _dispatch_introspection_queue_item_complete(dq); _dispatch_release(dq); // added when the queue is put on the list } diff --git a/src/shims/tsd.h b/src/shims/tsd.h index 2a0ab22..c7e387c 100644 --- a/src/shims/tsd.h +++ b/src/shims/tsd.h @@ -36,6 +36,9 @@ #if USE_APPLE_TSD_OPTIMIZATIONS && HAVE_PTHREAD_KEY_INIT_NP && \ !defined(DISPATCH_USE_DIRECT_TSD) #define DISPATCH_USE_DIRECT_TSD 1 +#if __has_include() +#include +#endif #endif #if DISPATCH_USE_DIRECT_TSD @@ -128,3 +131,20 @@ DISPATCH_TSD_INLINE DISPATCH_CONST static inline unsigned int _dispatch_cpu_number(void) { +#if TARGET_IPHONE_SIMULATOR && IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED < 1090 + return 0; +#elif __has_include() + return _os_cpu_number(); +#elif defined(__x86_64__) || defined(__i386__) + struct { uintptr_t p1, p2; } p; + __asm__("sidt %[p]" : [p] "=&m" (p)); + return (unsigned int)(p.p1 & 0xfff); +#else + // Not yet implemented. + return 0; +#endif +} + +#undef DISPATCH_TSD_INLINE + +#endif diff --git a/src/source.c b/src/source.c index 067c5ba..c6aaae3 100644 --- a/src/source.c +++ b/src/source.c @@ -3678,6 +3678,7 @@ _dispatch_mach_msg_invoke(dispatch_mach_msg_t dmsg) _dispatch_client_callout4(dr->dm_handler_ctxt, reason, dmsg, err, dr->dm_handler_func); _dispatch_thread_setspecific(dispatch_queue_key, (dispatch_queue_t)dm); + _dispatch_introspection_queue_item_complete(dmsg); dispatch_release(dmsg); } diff --git a/xcodeconfig/libdispatch.interposable b/xcodeconfig/libdispatch.interposable index f337761..52a1264 100644 --- a/xcodeconfig/libdispatch.interposable +++ b/xcodeconfig/libdispatch.interposable @@ -24,5 +24,6 @@ _dispatch_introspection_hook_queue_create _dispatch_introspection_hook_queue_destroy _dispatch_introspection_hook_queue_item_enqueue _dispatch_introspection_hook_queue_item_dequeue +_dispatch_introspection_hook_queue_item_complete _dispatch_introspection_hook_queue_callout_begin _dispatch_introspection_hook_queue_callout_end -- 2.45.2