]> git.saurik.com Git - apple/libdispatch.git/blob - src/trace.h
libdispatch-339.92.1.tar.gz
[apple/libdispatch.git] / src / trace.h
1 /*
2 * Copyright (c) 2010-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
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
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
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.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21 /*
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.
25 */
26
27 #ifndef __DISPATCH_TRACE__
28 #define __DISPATCH_TRACE__
29
30 #if DISPATCH_USE_DTRACE && !__OBJC2__
31
32 typedef struct dispatch_trace_timer_params_s {
33 int64_t deadline, interval, leeway;
34 } *dispatch_trace_timer_params_t;
35
36 #include "provider.h"
37
38 #if DISPATCH_USE_DTRACE_INTROSPECTION
39
40 #define _dispatch_trace_callout(_c, _f, _dcc) do { \
41 if (slowpath(DISPATCH_CALLOUT_ENTRY_ENABLED()) || \
42 slowpath(DISPATCH_CALLOUT_RETURN_ENABLED())) { \
43 dispatch_queue_t _dq = _dispatch_queue_get_current(); \
44 const char *_label = _dq && _dq->dq_label ? _dq->dq_label : ""; \
45 dispatch_function_t _func = (dispatch_function_t)(_f); \
46 void *_ctxt = (_c); \
47 DISPATCH_CALLOUT_ENTRY(_dq, _label, _func, _ctxt); \
48 _dcc; \
49 DISPATCH_CALLOUT_RETURN(_dq, _label, _func, _ctxt); \
50 } else { \
51 _dcc; \
52 } \
53 } while (0)
54
55 DISPATCH_ALWAYS_INLINE
56 static inline void
57 _dispatch_trace_client_callout(void *ctxt, dispatch_function_t f)
58 {
59 dispatch_function_t func = (f == _dispatch_call_block_and_release &&
60 ctxt ? _dispatch_Block_invoke(ctxt) : f);
61 _dispatch_introspection_callout_entry(ctxt, func);
62 _dispatch_trace_callout(ctxt, func, _dispatch_client_callout(ctxt, f));
63 _dispatch_introspection_callout_return(ctxt, func);
64 }
65
66 DISPATCH_ALWAYS_INLINE
67 static inline void
68 _dispatch_trace_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
69 {
70 dispatch_function_t func = (dispatch_function_t)f;
71 _dispatch_introspection_callout_entry(ctxt, func);
72 _dispatch_trace_callout(ctxt, func, _dispatch_client_callout2(ctxt, i, f));
73 _dispatch_introspection_callout_return(ctxt, func);
74 }
75
76 #ifdef __BLOCKS__
77 DISPATCH_ALWAYS_INLINE
78 static inline void
79 _dispatch_trace_client_callout_block(dispatch_block_t b)
80 {
81 dispatch_function_t func = _dispatch_Block_invoke(b);
82 _dispatch_introspection_callout_entry(b, func);
83 _dispatch_trace_callout(b, func, _dispatch_client_callout(b, func));
84 _dispatch_introspection_callout_return(b, func);
85 }
86 #endif
87
88 #define _dispatch_client_callout _dispatch_trace_client_callout
89 #define _dispatch_client_callout2 _dispatch_trace_client_callout2
90 #define _dispatch_client_callout_block _dispatch_trace_client_callout_block
91
92 #define _dispatch_trace_continuation(_q, _o, _t) do { \
93 dispatch_queue_t _dq = (_q); \
94 const char *_label = _dq && _dq->dq_label ? _dq->dq_label : ""; \
95 struct dispatch_object_s *_do = (_o); \
96 char *_kind; \
97 dispatch_function_t _func; \
98 void *_ctxt; \
99 if (DISPATCH_OBJ_IS_VTABLE(_do)) { \
100 _ctxt = _do->do_ctxt; \
101 _kind = (char*)dx_kind(_do); \
102 if ((dx_type(_do) & _DISPATCH_META_TYPE_MASK) == \
103 _DISPATCH_SOURCE_TYPE && (_dq) != &_dispatch_mgr_q) { \
104 _func = ((dispatch_source_t)_do)->ds_refs->ds_handler_func; \
105 } else { \
106 _func = (dispatch_function_t)_dispatch_queue_invoke; \
107 } \
108 } else { \
109 struct dispatch_continuation_s *_dc = (void*)(_do); \
110 _ctxt = _dc->dc_ctxt; \
111 if ((long)_dc->do_vtable & DISPATCH_OBJ_SYNC_SLOW_BIT) { \
112 _kind = "semaphore"; \
113 _func = (dispatch_function_t)dispatch_semaphore_signal; \
114 } else if (_dc->dc_func == _dispatch_call_block_and_release) { \
115 _kind = "block"; \
116 _func = _dispatch_Block_invoke(_dc->dc_ctxt); \
117 } else { \
118 _kind = "function"; \
119 _func = _dc->dc_func; \
120 } \
121 } \
122 _t(_dq, _label, _do, _kind, _func, _ctxt); \
123 } while (0)
124
125 DISPATCH_ALWAYS_INLINE
126 static inline void
127 _dispatch_trace_queue_push_list(dispatch_queue_t dq, dispatch_object_t _head,
128 dispatch_object_t _tail, unsigned int n)
129 {
130 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
131 struct dispatch_object_s *dou = _head._do;
132 do {
133 _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH);
134 } while (dou != _tail._do && (dou = dou->do_next));
135 }
136 _dispatch_introspection_queue_push_list(dq, _head, _tail);
137 _dispatch_queue_push_list(dq, _head, _tail, n);
138 }
139
140 DISPATCH_ALWAYS_INLINE
141 static inline void
142 _dispatch_trace_queue_push(dispatch_queue_t dq, dispatch_object_t _tail)
143 {
144 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
145 struct dispatch_object_s *dou = _tail._do;
146 _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH);
147 }
148 _dispatch_introspection_queue_push(dq, _tail);
149 _dispatch_queue_push(dq, _tail);
150 }
151
152 DISPATCH_ALWAYS_INLINE
153 static inline void
154 _dispatch_trace_queue_push_wakeup(dispatch_queue_t dq, dispatch_object_t _tail,
155 bool wakeup)
156 {
157 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
158 struct dispatch_object_s *dou = _tail._do;
159 _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH);
160 }
161 _dispatch_introspection_queue_push(dq, _tail);
162 _dispatch_queue_push_wakeup(dq, _tail, wakeup);
163 }
164
165 DISPATCH_ALWAYS_INLINE
166 static inline void
167 _dispatch_queue_push_notrace(dispatch_queue_t dq, dispatch_object_t dou)
168 {
169 _dispatch_queue_push(dq, dou);
170 }
171
172 #define _dispatch_queue_push_list _dispatch_trace_queue_push_list
173 #define _dispatch_queue_push _dispatch_trace_queue_push
174 #define _dispatch_queue_push_wakeup _dispatch_trace_queue_push_wakeup
175
176 DISPATCH_ALWAYS_INLINE
177 static inline void
178 _dispatch_trace_continuation_pop(dispatch_queue_t dq,
179 dispatch_object_t dou)
180 {
181 if (slowpath(DISPATCH_QUEUE_POP_ENABLED())) {
182 _dispatch_trace_continuation(dq, dou._do, DISPATCH_QUEUE_POP);
183 }
184 _dispatch_introspection_queue_pop(dq, dou);
185 }
186
187 #endif // DISPATCH_USE_DTRACE_INTROSPECTION
188
189 static inline dispatch_function_t
190 _dispatch_trace_timer_function(dispatch_source_t ds, dispatch_source_refs_t dr)
191 {
192 dispatch_function_t func = dr->ds_handler_func;
193 if (func == _dispatch_after_timer_callback &&
194 !(ds->ds_atomic_flags & DSF_CANCELED)) {
195 dispatch_continuation_t dc = ds->do_ctxt;
196 func = dc->dc_func != _dispatch_call_block_and_release ? dc->dc_func :
197 dc->dc_ctxt ? _dispatch_Block_invoke(dc->dc_ctxt) : NULL;
198 }
199 return func;
200 }
201
202 DISPATCH_ALWAYS_INLINE
203 static inline dispatch_trace_timer_params_t
204 _dispatch_trace_timer_params(uintptr_t ident,
205 struct dispatch_timer_source_s *values, uint64_t deadline,
206 dispatch_trace_timer_params_t params)
207 {
208 #define _dispatch_trace_time2nano3(t) (DISPATCH_TIMER_KIND(ident) \
209 == DISPATCH_TIMER_KIND_MACH ? _dispatch_time_mach2nano(t) : (t))
210 #define _dispatch_trace_time2nano2(v, t) ({ uint64_t _t = (t); \
211 (v) >= INT64_MAX ? -1ll : (int64_t)_dispatch_trace_time2nano3(_t);})
212 #define _dispatch_trace_time2nano(v) ({ uint64_t _t; \
213 _t = _dispatch_trace_time2nano3(v); _t >= INT64_MAX ? -1ll : \
214 (int64_t)_t; })
215 if (deadline) {
216 params->deadline = (int64_t)deadline;
217 } else {
218 uint64_t now = (DISPATCH_TIMER_KIND(ident) ==
219 DISPATCH_TIMER_KIND_MACH ? _dispatch_absolute_time() :
220 _dispatch_get_nanoseconds());
221 params->deadline = _dispatch_trace_time2nano2(values->target,
222 values->target < now ? 0 : values->target - now);
223 }
224 params->interval = _dispatch_trace_time2nano(values->interval);
225 params->leeway = _dispatch_trace_time2nano(values->leeway);
226 return params;
227 }
228
229 DISPATCH_ALWAYS_INLINE
230 static inline bool
231 _dispatch_trace_timer_configure_enabled(void)
232 {
233 return slowpath(DISPATCH_TIMER_CONFIGURE_ENABLED());
234 }
235
236 DISPATCH_ALWAYS_INLINE
237 static inline void
238 _dispatch_trace_timer_configure(dispatch_source_t ds, uintptr_t ident,
239 struct dispatch_timer_source_s *values)
240 {
241 struct dispatch_trace_timer_params_s params;
242 DISPATCH_TIMER_CONFIGURE(ds, _dispatch_trace_timer_function(ds,
243 ds->ds_refs), _dispatch_trace_timer_params(ident, values, 0,
244 &params));
245 }
246
247 DISPATCH_ALWAYS_INLINE
248 static inline void
249 _dispatch_trace_timer_program(dispatch_source_refs_t dr, uint64_t deadline)
250 {
251 if (slowpath(DISPATCH_TIMER_PROGRAM_ENABLED())) {
252 if (deadline && dr) {
253 dispatch_source_t ds = _dispatch_source_from_refs(dr);
254 struct dispatch_trace_timer_params_s params;
255 DISPATCH_TIMER_PROGRAM(ds, _dispatch_trace_timer_function(ds, dr),
256 _dispatch_trace_timer_params(ds->ds_ident_hack,
257 &ds_timer(dr), deadline, &params));
258 }
259 }
260 }
261
262 DISPATCH_ALWAYS_INLINE
263 static inline void
264 _dispatch_trace_timer_wake(dispatch_source_refs_t dr)
265 {
266 if (slowpath(DISPATCH_TIMER_WAKE_ENABLED())) {
267 if (dr) {
268 dispatch_source_t ds = _dispatch_source_from_refs(dr);
269 DISPATCH_TIMER_WAKE(ds, _dispatch_trace_timer_function(ds, dr));
270 }
271 }
272 }
273
274 DISPATCH_ALWAYS_INLINE
275 static inline void
276 _dispatch_trace_timer_fire(dispatch_source_refs_t dr, unsigned long data,
277 unsigned long missed)
278 {
279 if (slowpath(DISPATCH_TIMER_FIRE_ENABLED())) {
280 if (!(data - missed) && dr) {
281 dispatch_source_t ds = _dispatch_source_from_refs(dr);
282 DISPATCH_TIMER_FIRE(ds, _dispatch_trace_timer_function(ds, dr));
283 }
284 }
285 }
286
287 #else
288
289 #define _dispatch_trace_timer_configure_enabled() false
290 #define _dispatch_trace_timer_configure(ds, ident, values) \
291 do { (void)(ds); (void)(ident); (void)(values); } while(0)
292 #define _dispatch_trace_timer_program(dr, deadline) \
293 do { (void)(dr); (void)(deadline); } while(0)
294 #define _dispatch_trace_timer_wake(dr) \
295 do { (void)(dr); } while(0)
296 #define _dispatch_trace_timer_fire(dr, data, missed) \
297 do { (void)(dr); (void)(data); (void)(missed); } while(0)
298
299 #endif // DISPATCH_USE_DTRACE && !__OBJC2__
300
301 #if !DISPATCH_USE_DTRACE_INTROSPECTION
302
303 #define _dispatch_queue_push_notrace _dispatch_queue_push
304 #define _dispatch_trace_continuation_pop(dq, dou) \
305 do { (void)(dq); (void)(dou); } while(0)
306
307 #endif // !DISPATCH_USE_DTRACE_INTROSPECTION
308
309 #endif // __DISPATCH_TRACE__