2 * Copyright (c) 2010-2013 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
22 * IMPORTANT: This header file describes INTERNAL interfaces to libdispatch
23 * which are subject to change in future releases of Mac OS X. Any applications
24 * relying on these interfaces WILL break.
27 #ifndef __DISPATCH_TRACE__
28 #define __DISPATCH_TRACE__
30 #if !__OBJC2__ && !defined(__cplusplus)
32 #if DISPATCH_USE_DTRACE || DISPATCH_USE_DTRACE_INTROSPECTION
33 typedef struct dispatch_trace_timer_params_s
{
34 int64_t deadline
, interval
, leeway
;
35 } *dispatch_trace_timer_params_t
;
38 #endif // DISPATCH_USE_DTRACE || DISPATCH_USE_DTRACE_INTROSPECTION
40 #if DISPATCH_USE_DTRACE_INTROSPECTION
41 #define _dispatch_trace_callout(_c, _f, _dcc) do { \
42 if (slowpath(DISPATCH_CALLOUT_ENTRY_ENABLED()) || \
43 slowpath(DISPATCH_CALLOUT_RETURN_ENABLED())) { \
44 dispatch_queue_t _dq = _dispatch_queue_get_current(); \
45 const char *_label = _dq && _dq->dq_label ? _dq->dq_label : ""; \
46 dispatch_function_t _func = (dispatch_function_t)(_f); \
48 DISPATCH_CALLOUT_ENTRY(_dq, _label, _func, _ctxt); \
50 DISPATCH_CALLOUT_RETURN(_dq, _label, _func, _ctxt); \
55 #elif DISPATCH_INTROSPECTION
56 #define _dispatch_trace_callout(_c, _f, _dcc) \
57 do { (void)(_c); (void)(_f); _dcc; } while (0)
58 #endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
60 #if DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
61 DISPATCH_ALWAYS_INLINE
63 _dispatch_trace_client_callout(void *ctxt
, dispatch_function_t f
)
65 dispatch_function_t func
= (f
== _dispatch_call_block_and_release
&&
66 ctxt
? _dispatch_Block_invoke(ctxt
) : f
);
67 _dispatch_introspection_callout_entry(ctxt
, func
);
68 _dispatch_trace_callout(ctxt
, func
, _dispatch_client_callout(ctxt
, f
));
69 _dispatch_introspection_callout_return(ctxt
, func
);
72 DISPATCH_ALWAYS_INLINE
74 _dispatch_trace_client_callout2(void *ctxt
, size_t i
, void (*f
)(void *, size_t))
76 dispatch_function_t func
= (dispatch_function_t
)f
;
77 _dispatch_introspection_callout_entry(ctxt
, func
);
78 _dispatch_trace_callout(ctxt
, func
, _dispatch_client_callout2(ctxt
, i
, f
));
79 _dispatch_introspection_callout_return(ctxt
, func
);
82 #define _dispatch_client_callout _dispatch_trace_client_callout
83 #define _dispatch_client_callout2 _dispatch_trace_client_callout2
84 #endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
86 #if DISPATCH_USE_DTRACE_INTROSPECTION
87 #define _dispatch_trace_continuation(_q, _o, _t) do { \
88 dispatch_queue_t _dq = (_q); \
89 const char *_label = _dq && _dq->dq_label ? _dq->dq_label : ""; \
90 struct dispatch_object_s *_do = (_o); \
91 dispatch_continuation_t _dc; \
93 dispatch_function_t _func; \
95 if (DISPATCH_OBJ_IS_VTABLE(_do)) { \
96 _kind = (char*)dx_kind(_do); \
97 if ((dx_type(_do) & _DISPATCH_META_TYPE_MASK) == \
98 _DISPATCH_SOURCE_TYPE && (_dq) != &_dispatch_mgr_q) { \
99 dispatch_source_t _ds = (dispatch_source_t)_do; \
100 _dc = _ds->ds_refs->ds_handler[DS_EVENT_HANDLER]; \
101 _func = _dc ? _dc->dc_func : NULL; \
102 _ctxt = _dc ? _dc->dc_ctxt : NULL; \
104 _func = (dispatch_function_t)_dispatch_queue_invoke; \
105 _ctxt = _do->do_ctxt; \
109 _ctxt = _dc->dc_ctxt; \
110 if ((long)_dc->do_vtable & DISPATCH_OBJ_SYNC_SLOW_BIT) { \
111 _kind = "semaphore"; \
112 _func = (dispatch_function_t)dispatch_semaphore_signal; \
113 } else if (_dc->dc_func == _dispatch_call_block_and_release) { \
115 _func = _dispatch_Block_invoke(_dc->dc_ctxt); \
117 _kind = "function"; \
118 _func = _dc->dc_func; \
121 _t(_dq, _label, _do, _kind, _func, _ctxt); \
123 #elif DISPATCH_INTROSPECTION
124 #define _dispatch_trace_continuation(_q, _o, _t) \
125 do { (void)(_q); (void)(_o); } while(0)
126 #define DISPATCH_QUEUE_PUSH_ENABLED() 0
127 #define DISPATCH_QUEUE_POP_ENABLED() 0
128 #endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
130 #if DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
131 DISPATCH_ALWAYS_INLINE
133 _dispatch_trace_queue_push_list(dispatch_queue_t dq
, dispatch_object_t _head
,
134 dispatch_object_t _tail
, pthread_priority_t pp
, unsigned int n
)
136 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
137 struct dispatch_object_s
*dou
= _head
._do
;
139 _dispatch_trace_continuation(dq
, dou
, DISPATCH_QUEUE_PUSH
);
140 } while (dou
!= _tail
._do
&& (dou
= dou
->do_next
));
142 _dispatch_introspection_queue_push_list(dq
, _head
, _tail
);
143 _dispatch_queue_push_list(dq
, _head
, _tail
, pp
, n
);
146 DISPATCH_ALWAYS_INLINE
148 _dispatch_trace_queue_push(dispatch_queue_t dq
, dispatch_object_t _tail
, pthread_priority_t pp
)
150 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
151 struct dispatch_object_s
*dou
= _tail
._do
;
152 _dispatch_trace_continuation(dq
, dou
, DISPATCH_QUEUE_PUSH
);
154 _dispatch_introspection_queue_push(dq
, _tail
);
155 _dispatch_queue_push(dq
, _tail
, pp
);
158 DISPATCH_ALWAYS_INLINE
160 _dispatch_trace_queue_push_wakeup(dispatch_queue_t dq
, dispatch_object_t _tail
,
161 pthread_priority_t pp
, bool wakeup
)
163 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
164 struct dispatch_object_s
*dou
= _tail
._do
;
165 _dispatch_trace_continuation(dq
, dou
, DISPATCH_QUEUE_PUSH
);
167 _dispatch_introspection_queue_push(dq
, _tail
);
168 _dispatch_queue_push_wakeup(dq
, _tail
, pp
, wakeup
);
171 DISPATCH_ALWAYS_INLINE
173 _dispatch_trace_continuation_push(dispatch_queue_t dq
, dispatch_object_t _tail
)
175 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
176 struct dispatch_object_s
*dou
= _tail
._do
;
177 _dispatch_trace_continuation(dq
, dou
, DISPATCH_QUEUE_PUSH
);
179 _dispatch_introspection_queue_push(dq
, _tail
);
182 DISPATCH_ALWAYS_INLINE
184 _dispatch_queue_push_notrace(dispatch_queue_t dq
, dispatch_object_t dou
, pthread_priority_t pp
)
186 _dispatch_queue_push(dq
, dou
, pp
);
189 #define _dispatch_queue_push_list _dispatch_trace_queue_push_list
190 #define _dispatch_queue_push _dispatch_trace_queue_push
191 #define _dispatch_queue_push_wakeup _dispatch_trace_queue_push_wakeup
193 DISPATCH_ALWAYS_INLINE
195 _dispatch_trace_continuation_pop(dispatch_queue_t dq
, dispatch_object_t dou
)
197 if (slowpath(DISPATCH_QUEUE_POP_ENABLED())) {
198 _dispatch_trace_continuation(dq
, dou
._do
, DISPATCH_QUEUE_POP
);
200 _dispatch_introspection_queue_pop(dq
, dou
);
203 #define _dispatch_queue_push_notrace _dispatch_queue_push
204 #define _dispatch_trace_continuation_push(dq, dou) \
205 do { (void)(dq); (void)(dou); } while(0)
206 #define _dispatch_trace_continuation_pop(dq, dou) \
207 do { (void)(dq); (void)(dou); } while(0)
208 #endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
210 #if DISPATCH_USE_DTRACE
211 static inline dispatch_function_t
212 _dispatch_trace_timer_function(dispatch_source_t ds
, dispatch_source_refs_t dr
)
214 dispatch_continuation_t dc
= dr
->ds_handler
[DS_EVENT_HANDLER
];
215 dispatch_function_t func
= dc
? dc
->dc_func
: NULL
;
216 if (func
== _dispatch_after_timer_callback
&&
217 !(ds
->ds_atomic_flags
& DSF_CANCELED
)) {
219 func
= dc
->dc_func
!= _dispatch_call_block_and_release
? dc
->dc_func
:
220 dc
->dc_ctxt
? _dispatch_Block_invoke(dc
->dc_ctxt
) : NULL
;
225 DISPATCH_ALWAYS_INLINE
226 static inline dispatch_trace_timer_params_t
227 _dispatch_trace_timer_params(uintptr_t ident
,
228 struct dispatch_timer_source_s
*values
, uint64_t deadline
,
229 dispatch_trace_timer_params_t params
)
231 #define _dispatch_trace_time2nano3(t) (DISPATCH_TIMER_KIND(ident) \
232 == DISPATCH_TIMER_KIND_MACH ? _dispatch_time_mach2nano(t) : (t))
233 #define _dispatch_trace_time2nano2(v, t) ({ uint64_t _t = (t); \
234 (v) >= INT64_MAX ? -1ll : (int64_t)_dispatch_trace_time2nano3(_t);})
235 #define _dispatch_trace_time2nano(v) ({ uint64_t _t; \
236 _t = _dispatch_trace_time2nano3(v); _t >= INT64_MAX ? -1ll : \
239 params
->deadline
= (int64_t)deadline
;
241 uint64_t now
= (DISPATCH_TIMER_KIND(ident
) ==
242 DISPATCH_TIMER_KIND_MACH
? _dispatch_absolute_time() :
243 _dispatch_get_nanoseconds());
244 params
->deadline
= _dispatch_trace_time2nano2(values
->target
,
245 values
->target
< now
? 0 : values
->target
- now
);
247 params
->interval
= _dispatch_trace_time2nano(values
->interval
);
248 params
->leeway
= _dispatch_trace_time2nano(values
->leeway
);
252 DISPATCH_ALWAYS_INLINE
254 _dispatch_trace_timer_configure_enabled(void)
256 return slowpath(DISPATCH_TIMER_CONFIGURE_ENABLED());
259 DISPATCH_ALWAYS_INLINE
261 _dispatch_trace_timer_configure(dispatch_source_t ds
, uintptr_t ident
,
262 struct dispatch_timer_source_s
*values
)
264 struct dispatch_trace_timer_params_s params
;
265 DISPATCH_TIMER_CONFIGURE(ds
, _dispatch_trace_timer_function(ds
,
266 ds
->ds_refs
), _dispatch_trace_timer_params(ident
, values
, 0,
270 DISPATCH_ALWAYS_INLINE
272 _dispatch_trace_timer_program(dispatch_source_refs_t dr
, uint64_t deadline
)
274 if (slowpath(DISPATCH_TIMER_PROGRAM_ENABLED())) {
275 if (deadline
&& dr
) {
276 dispatch_source_t ds
= _dispatch_source_from_refs(dr
);
277 struct dispatch_trace_timer_params_s params
;
278 DISPATCH_TIMER_PROGRAM(ds
, _dispatch_trace_timer_function(ds
, dr
),
279 _dispatch_trace_timer_params(ds
->ds_ident_hack
,
280 &ds_timer(dr
), deadline
, ¶ms
));
285 DISPATCH_ALWAYS_INLINE
287 _dispatch_trace_timer_wake(dispatch_source_refs_t dr
)
289 if (slowpath(DISPATCH_TIMER_WAKE_ENABLED())) {
291 dispatch_source_t ds
= _dispatch_source_from_refs(dr
);
292 DISPATCH_TIMER_WAKE(ds
, _dispatch_trace_timer_function(ds
, dr
));
297 DISPATCH_ALWAYS_INLINE
299 _dispatch_trace_timer_fire(dispatch_source_refs_t dr
, unsigned long data
,
300 unsigned long missed
)
302 if (slowpath(DISPATCH_TIMER_FIRE_ENABLED())) {
303 if (!(data
- missed
) && dr
) {
304 dispatch_source_t ds
= _dispatch_source_from_refs(dr
);
305 DISPATCH_TIMER_FIRE(ds
, _dispatch_trace_timer_function(ds
, dr
));
312 #define _dispatch_trace_timer_configure_enabled() false
313 #define _dispatch_trace_timer_configure(ds, ident, values) \
314 do { (void)(ds); (void)(ident); (void)(values); } while(0)
315 #define _dispatch_trace_timer_program(dr, deadline) \
316 do { (void)(dr); (void)(deadline); } while(0)
317 #define _dispatch_trace_timer_wake(dr) \
318 do { (void)(dr); } while(0)
319 #define _dispatch_trace_timer_fire(dr, data, missed) \
320 do { (void)(dr); (void)(data); (void)(missed); } while(0)
322 #endif // DISPATCH_USE_DTRACE
324 #endif // !__OBJC2__ && !defined(__cplusplus)
326 #endif // __DISPATCH_TRACE__