X-Git-Url: https://git.saurik.com/apple/libdispatch.git/blobdiff_plain/e85f44377864e428703fb21503e29f422c11288f..refs/heads/master:/src/trace.h?ds=inline diff --git a/src/trace.h b/src/trace.h index 0d9bc3d..c670f60 100644 --- a/src/trace.h +++ b/src/trace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2011 Apple Inc. All rights reserved. + * Copyright (c) 2010-2013 Apple Inc. All rights reserved. * * @APPLE_APACHE_LICENSE_HEADER_START@ * @@ -27,81 +27,85 @@ #ifndef __DISPATCH_TRACE__ #define __DISPATCH_TRACE__ -#if DISPATCH_USE_DTRACE - -#include "provider.h" +#if DISPATCH_PURE_C +#if DISPATCH_USE_DTRACE_INTROSPECTION #define _dispatch_trace_callout(_c, _f, _dcc) do { \ if (slowpath(DISPATCH_CALLOUT_ENTRY_ENABLED()) || \ slowpath(DISPATCH_CALLOUT_RETURN_ENABLED())) { \ dispatch_queue_t _dq = _dispatch_queue_get_current(); \ - char *_label = _dq ? _dq->dq_label : ""; \ + const char *_label = _dq && _dq->dq_label ? _dq->dq_label : ""; \ dispatch_function_t _func = (dispatch_function_t)(_f); \ void *_ctxt = (_c); \ DISPATCH_CALLOUT_ENTRY(_dq, _label, _func, _ctxt); \ _dcc; \ DISPATCH_CALLOUT_RETURN(_dq, _label, _func, _ctxt); \ - return; \ + } else { \ + _dcc; \ } \ - return _dcc; \ } while (0) +#elif DISPATCH_INTROSPECTION +#define _dispatch_trace_callout(_c, _f, _dcc) \ + do { (void)(_c); (void)(_f); _dcc; } while (0) +#endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION +#if DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION DISPATCH_ALWAYS_INLINE static inline void _dispatch_trace_client_callout(void *ctxt, dispatch_function_t f) { - _dispatch_trace_callout(ctxt, f == _dispatch_call_block_and_release && - ctxt ? ((struct Block_basic *)ctxt)->Block_invoke : f, - _dispatch_client_callout(ctxt, f)); + dispatch_function_t func = (f == _dispatch_call_block_and_release && + ctxt ? _dispatch_Block_invoke(ctxt) : f); + _dispatch_introspection_callout_entry(ctxt, func); + _dispatch_trace_callout(ctxt, func, _dispatch_client_callout(ctxt, f)); + _dispatch_introspection_callout_return(ctxt, func); } DISPATCH_ALWAYS_INLINE static inline void _dispatch_trace_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t)) { - _dispatch_trace_callout(ctxt, f, _dispatch_client_callout2(ctxt, i, f)); + dispatch_function_t func = (dispatch_function_t)f; + _dispatch_introspection_callout_entry(ctxt, func); + _dispatch_trace_callout(ctxt, func, _dispatch_client_callout2(ctxt, i, f)); + _dispatch_introspection_callout_return(ctxt, func); } -#ifdef __BLOCKS__ -DISPATCH_ALWAYS_INLINE -static inline void -_dispatch_trace_client_callout_block(dispatch_block_t b) -{ - struct Block_basic *bb = (void*)b; - _dispatch_trace_callout(b, bb->Block_invoke, - _dispatch_client_callout(b, (dispatch_function_t)bb->Block_invoke)); -} -#endif - #define _dispatch_client_callout _dispatch_trace_client_callout #define _dispatch_client_callout2 _dispatch_trace_client_callout2 -#define _dispatch_client_callout_block _dispatch_trace_client_callout_block +#endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION +#if DISPATCH_USE_DTRACE_INTROSPECTION #define _dispatch_trace_continuation(_q, _o, _t) do { \ dispatch_queue_t _dq = (_q); \ - char *_label = _dq ? _dq->dq_label : ""; \ + const char *_label = _dq && _dq->dq_label ? _dq->dq_label : ""; \ struct dispatch_object_s *_do = (_o); \ + dispatch_continuation_t _dc; \ char *_kind; \ dispatch_function_t _func; \ void *_ctxt; \ - if (DISPATCH_OBJ_IS_VTABLE(_do)) { \ - _ctxt = _do->do_ctxt; \ + if (_dispatch_object_has_vtable(_do)) { \ _kind = (char*)dx_kind(_do); \ - if (dx_type(_do) == DISPATCH_SOURCE_KEVENT_TYPE && \ - (_dq) != &_dispatch_mgr_q) { \ - _func = ((dispatch_source_t)_do)->ds_refs->ds_handler_func; \ + if ((dx_type(_do) & _DISPATCH_META_TYPE_MASK) == \ + _DISPATCH_SOURCE_TYPE && (_dq) != &_dispatch_mgr_q) { \ + dispatch_source_t _ds = (dispatch_source_t)_do; \ + _dc = os_atomic_load(&_ds->ds_refs->ds_handler[ \ + DS_EVENT_HANDLER], relaxed); \ + _func = _dc ? _dc->dc_func : NULL; \ + _ctxt = _dc ? _dc->dc_ctxt : NULL; \ } else { \ _func = (dispatch_function_t)_dispatch_queue_invoke; \ + _ctxt = _do->do_ctxt; \ } \ } else { \ - struct dispatch_continuation_s *_dc = (void*)(_do); \ + _dc = (void*)_do; \ _ctxt = _dc->dc_ctxt; \ - if ((long)_dc->do_vtable & DISPATCH_OBJ_SYNC_SLOW_BIT) { \ + if (_dc->dc_flags & DISPATCH_OBJ_SYNC_WAITER_BIT) { \ _kind = "semaphore"; \ _func = (dispatch_function_t)dispatch_semaphore_signal; \ - } else if (_dc->dc_func == _dispatch_call_block_and_release) { \ + } else if (_dc->dc_flags & DISPATCH_OBJ_BLOCK_BIT) { \ _kind = "block"; \ - _func = ((struct Block_basic *)_dc->dc_ctxt)->Block_invoke;\ + _func = _dispatch_Block_invoke(_dc->dc_ctxt); \ } else { \ _kind = "function"; \ _func = _dc->dc_func; \ @@ -109,11 +113,18 @@ _dispatch_trace_client_callout_block(dispatch_block_t b) } \ _t(_dq, _label, _do, _kind, _func, _ctxt); \ } while (0) +#elif DISPATCH_INTROSPECTION +#define _dispatch_trace_continuation(_q, _o, _t) \ + do { (void)(_q); (void)(_o); } while(0) +#define DISPATCH_QUEUE_PUSH_ENABLED() 0 +#define DISPATCH_QUEUE_POP_ENABLED() 0 +#endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION +#if DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION DISPATCH_ALWAYS_INLINE static inline void -_dispatch_trace_queue_push_list(dispatch_queue_t dq, dispatch_object_t _head, - dispatch_object_t _tail) +_dispatch_trace_root_queue_push_list(dispatch_queue_t dq, + dispatch_object_t _head, dispatch_object_t _tail, int n) { if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) { struct dispatch_object_s *dou = _head._do; @@ -121,32 +132,161 @@ _dispatch_trace_queue_push_list(dispatch_queue_t dq, dispatch_object_t _head, _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH); } while (dou != _tail._do && (dou = dou->do_next)); } - _dispatch_queue_push_list(dq, _head, _tail); + _dispatch_introspection_queue_push_list(dq, _head, _tail); + _dispatch_root_queue_push_inline(dq, _head, _tail, n); } DISPATCH_ALWAYS_INLINE static inline void -_dispatch_queue_push_notrace(dispatch_queue_t dq, dispatch_object_t dou) +_dispatch_trace_queue_push_inline(dispatch_queue_t dq, dispatch_object_t _tail, + dispatch_qos_t qos) { - _dispatch_queue_push_list(dq, dou, dou); + if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) { + struct dispatch_object_s *dou = _tail._do; + _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH); + } + _dispatch_introspection_queue_push(dq, _tail); + _dispatch_queue_push_inline(dq, _tail, qos); } -#define _dispatch_queue_push_list _dispatch_trace_queue_push_list +DISPATCH_ALWAYS_INLINE +static inline void +_dispatch_trace_continuation_push(dispatch_queue_t dq, dispatch_object_t _tail) +{ + if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) { + struct dispatch_object_s *dou = _tail._do; + _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH); + } + _dispatch_introspection_queue_push(dq, _tail); +} + +#define _dispatch_root_queue_push_inline _dispatch_trace_root_queue_push_list +#define _dispatch_queue_push_inline _dispatch_trace_queue_push_inline DISPATCH_ALWAYS_INLINE static inline void -_dispatch_trace_continuation_pop(dispatch_queue_t dq, - dispatch_object_t dou) +_dispatch_trace_continuation_pop(dispatch_queue_t dq, dispatch_object_t dou) { if (slowpath(DISPATCH_QUEUE_POP_ENABLED())) { _dispatch_trace_continuation(dq, dou._do, DISPATCH_QUEUE_POP); } + _dispatch_introspection_queue_pop(dq, dou); } #else +#define _dispatch_trace_continuation_push(dq, dou) \ + do { (void)(dq); (void)(dou); } while(0) +#define _dispatch_trace_continuation_pop(dq, dou) \ + do { (void)(dq); (void)(dou); } while(0) +#endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION + +#if DISPATCH_USE_DTRACE +static inline dispatch_function_t +_dispatch_trace_timer_function(dispatch_timer_source_refs_t dr) +{ + dispatch_continuation_t dc; + dc = os_atomic_load(&dr->ds_handler[DS_EVENT_HANDLER], relaxed); + return dc ? dc->dc_func : NULL; +} -#define _dispatch_queue_push_notrace _dispatch_queue_push -#define _dispatch_trace_continuation_pop(dq, dou) +DISPATCH_ALWAYS_INLINE +static inline dispatch_trace_timer_params_t +_dispatch_trace_timer_params(dispatch_clock_t clock, + struct dispatch_timer_source_s *values, uint64_t deadline, + dispatch_trace_timer_params_t params) +{ + #define _dispatch_trace_time2nano3(t) \ + (clock == DISPATCH_CLOCK_MACH ? _dispatch_time_mach2nano(t) : (t)) + #define _dispatch_trace_time2nano2(v, t) ({ uint64_t _t = (t); \ + (v) >= INT64_MAX ? -1ll : (int64_t)_dispatch_trace_time2nano3(_t);}) + #define _dispatch_trace_time2nano(v) ({ uint64_t _t; \ + _t = _dispatch_trace_time2nano3(v); _t >= INT64_MAX ? -1ll : \ + (int64_t)_t; }) + if (deadline) { + params->deadline = (int64_t)deadline; + } else { + uint64_t now = _dispatch_time_now(clock); + params->deadline = _dispatch_trace_time2nano2(values->target, + values->target < now ? 0 : values->target - now); + } + uint64_t leeway = values->deadline - values->target; + params->interval = _dispatch_trace_time2nano(values->interval); + params->leeway = _dispatch_trace_time2nano(leeway); + return params; +} + +DISPATCH_ALWAYS_INLINE +static inline bool +_dispatch_trace_timer_configure_enabled(void) +{ + return slowpath(DISPATCH_TIMER_CONFIGURE_ENABLED()); +} + +DISPATCH_ALWAYS_INLINE +static inline void +_dispatch_trace_timer_configure(dispatch_source_t ds, dispatch_clock_t clock, + struct dispatch_timer_source_s *values) +{ + dispatch_timer_source_refs_t dr = ds->ds_timer_refs; + struct dispatch_trace_timer_params_s params; + DISPATCH_TIMER_CONFIGURE(ds, _dispatch_trace_timer_function(dr), + _dispatch_trace_timer_params(clock, values, 0, ¶ms)); +} + +DISPATCH_ALWAYS_INLINE +static inline void +_dispatch_trace_timer_program(dispatch_timer_source_refs_t dr, uint64_t deadline) +{ + if (slowpath(DISPATCH_TIMER_PROGRAM_ENABLED())) { + if (deadline && dr) { + dispatch_source_t ds = _dispatch_source_from_refs(dr); + dispatch_clock_t clock = DISPATCH_TIMER_CLOCK(dr->du_ident); + struct dispatch_trace_timer_params_s params; + DISPATCH_TIMER_PROGRAM(ds, _dispatch_trace_timer_function(dr), + _dispatch_trace_timer_params(clock, &dr->dt_timer, + deadline, ¶ms)); + } + } +} + +DISPATCH_ALWAYS_INLINE +static inline void +_dispatch_trace_timer_wake(dispatch_timer_source_refs_t dr) +{ + if (slowpath(DISPATCH_TIMER_WAKE_ENABLED())) { + if (dr) { + dispatch_source_t ds = _dispatch_source_from_refs(dr); + DISPATCH_TIMER_WAKE(ds, _dispatch_trace_timer_function(dr)); + } + } +} + +DISPATCH_ALWAYS_INLINE +static inline void +_dispatch_trace_timer_fire(dispatch_timer_source_refs_t dr, uint64_t data, + uint64_t missed) +{ + if (slowpath(DISPATCH_TIMER_FIRE_ENABLED())) { + if (!(data - missed) && dr) { + dispatch_source_t ds = _dispatch_source_from_refs(dr); + DISPATCH_TIMER_FIRE(ds, _dispatch_trace_timer_function(dr)); + } + } +} + +#else + +#define _dispatch_trace_timer_configure_enabled() false +#define _dispatch_trace_timer_configure(ds, clock, values) \ + do { (void)(ds); (void)(clock); (void)(values); } while(0) +#define _dispatch_trace_timer_program(dr, deadline) \ + do { (void)(dr); (void)(deadline); } while(0) +#define _dispatch_trace_timer_wake(dr) \ + do { (void)(dr); } while(0) +#define _dispatch_trace_timer_fire(dr, data, missed) \ + do { (void)(dr); (void)(data); (void)(missed); } while(0) #endif // DISPATCH_USE_DTRACE +#endif // DISPATCH_PURE_C + #endif // __DISPATCH_TRACE__