]> git.saurik.com Git - apple/libdispatch.git/blob - src/trace.h
libdispatch-703.1.4.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_PURE_C
31
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;
36
37 #include "provider.h"
38 #endif // DISPATCH_USE_DTRACE || DISPATCH_USE_DTRACE_INTROSPECTION
39
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); \
47 void *_ctxt = (_c); \
48 DISPATCH_CALLOUT_ENTRY(_dq, _label, _func, _ctxt); \
49 _dcc; \
50 DISPATCH_CALLOUT_RETURN(_dq, _label, _func, _ctxt); \
51 } else { \
52 _dcc; \
53 } \
54 } while (0)
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
59
60 #if DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
61 DISPATCH_ALWAYS_INLINE
62 static inline void
63 _dispatch_trace_client_callout(void *ctxt, dispatch_function_t f)
64 {
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);
70 }
71
72 DISPATCH_ALWAYS_INLINE
73 static inline void
74 _dispatch_trace_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
75 {
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);
80 }
81
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
85
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; \
92 char *_kind; \
93 dispatch_function_t _func; \
94 void *_ctxt; \
95 if (_dispatch_object_has_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 = os_atomic_load(&_ds->ds_refs->ds_handler[ \
101 DS_EVENT_HANDLER], relaxed); \
102 _func = _dc ? _dc->dc_func : NULL; \
103 _ctxt = _dc ? _dc->dc_ctxt : NULL; \
104 } else { \
105 _func = (dispatch_function_t)_dispatch_queue_invoke; \
106 _ctxt = _do->do_ctxt; \
107 } \
108 } else { \
109 _dc = (void*)_do; \
110 _ctxt = _dc->dc_ctxt; \
111 if (_dc->dc_flags & DISPATCH_OBJ_SYNC_SLOW_BIT) { \
112 _kind = "semaphore"; \
113 _func = (dispatch_function_t)dispatch_semaphore_signal; \
114 } else if (_dc->dc_flags & DISPATCH_OBJ_BLOCK_BIT) { \
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 #elif DISPATCH_INTROSPECTION
125 #define _dispatch_trace_continuation(_q, _o, _t) \
126 do { (void)(_q); (void)(_o); } while(0)
127 #define DISPATCH_QUEUE_PUSH_ENABLED() 0
128 #define DISPATCH_QUEUE_POP_ENABLED() 0
129 #endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
130
131 #if DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
132 DISPATCH_ALWAYS_INLINE
133 static inline void
134 _dispatch_trace_queue_push_list(dispatch_queue_t dq, dispatch_object_t _head,
135 dispatch_object_t _tail, pthread_priority_t pp, unsigned int n)
136 {
137 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
138 struct dispatch_object_s *dou = _head._do;
139 do {
140 _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH);
141 } while (dou != _tail._do && (dou = dou->do_next));
142 }
143 _dispatch_introspection_queue_push_list(dq, _head, _tail);
144 _dispatch_queue_push_list(dq, _head, _tail, pp, n);
145 }
146
147 DISPATCH_ALWAYS_INLINE
148 static inline void
149 _dispatch_trace_queue_push_inline(dispatch_queue_t dq, dispatch_object_t _tail,
150 pthread_priority_t pp, dispatch_wakeup_flags_t flags)
151 {
152 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
153 struct dispatch_object_s *dou = _tail._do;
154 _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH);
155 }
156 _dispatch_introspection_queue_push(dq, _tail);
157 _dispatch_queue_push_inline(dq, _tail, pp, flags);
158 }
159
160 DISPATCH_ALWAYS_INLINE
161 static inline void
162 _dispatch_trace_continuation_push(dispatch_queue_t dq, dispatch_object_t _tail)
163 {
164 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
165 struct dispatch_object_s *dou = _tail._do;
166 _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH);
167 }
168 _dispatch_introspection_queue_push(dq, _tail);
169 }
170
171 #define _dispatch_queue_push_list _dispatch_trace_queue_push_list
172 #define _dispatch_queue_push_inline _dispatch_trace_queue_push_inline
173
174 DISPATCH_ALWAYS_INLINE
175 static inline void
176 _dispatch_trace_continuation_pop(dispatch_queue_t dq, dispatch_object_t dou)
177 {
178 if (slowpath(DISPATCH_QUEUE_POP_ENABLED())) {
179 _dispatch_trace_continuation(dq, dou._do, DISPATCH_QUEUE_POP);
180 }
181 _dispatch_introspection_queue_pop(dq, dou);
182 }
183 #else
184 #define _dispatch_trace_continuation_push(dq, dou) \
185 do { (void)(dq); (void)(dou); } while(0)
186 #define _dispatch_trace_continuation_pop(dq, dou) \
187 do { (void)(dq); (void)(dou); } while(0)
188 #endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
189
190 #if DISPATCH_USE_DTRACE
191 static inline dispatch_function_t
192 _dispatch_trace_timer_function(dispatch_source_refs_t dr)
193 {
194 dispatch_continuation_t dc;
195 dc = os_atomic_load(&dr->ds_handler[DS_EVENT_HANDLER], relaxed);
196 return dc ? dc->dc_func : NULL;
197 }
198
199 DISPATCH_ALWAYS_INLINE
200 static inline dispatch_trace_timer_params_t
201 _dispatch_trace_timer_params(uintptr_t ident,
202 struct dispatch_timer_source_s *values, uint64_t deadline,
203 dispatch_trace_timer_params_t params)
204 {
205 #define _dispatch_trace_time2nano3(t) (DISPATCH_TIMER_KIND(ident) \
206 == DISPATCH_TIMER_KIND_MACH ? _dispatch_time_mach2nano(t) : (t))
207 #define _dispatch_trace_time2nano2(v, t) ({ uint64_t _t = (t); \
208 (v) >= INT64_MAX ? -1ll : (int64_t)_dispatch_trace_time2nano3(_t);})
209 #define _dispatch_trace_time2nano(v) ({ uint64_t _t; \
210 _t = _dispatch_trace_time2nano3(v); _t >= INT64_MAX ? -1ll : \
211 (int64_t)_t; })
212 if (deadline) {
213 params->deadline = (int64_t)deadline;
214 } else {
215 uint64_t now = (DISPATCH_TIMER_KIND(ident) ==
216 DISPATCH_TIMER_KIND_MACH ? _dispatch_absolute_time() :
217 _dispatch_get_nanoseconds());
218 params->deadline = _dispatch_trace_time2nano2(values->target,
219 values->target < now ? 0 : values->target - now);
220 }
221 params->interval = _dispatch_trace_time2nano(values->interval);
222 params->leeway = _dispatch_trace_time2nano(values->leeway);
223 return params;
224 }
225
226 DISPATCH_ALWAYS_INLINE
227 static inline bool
228 _dispatch_trace_timer_configure_enabled(void)
229 {
230 return slowpath(DISPATCH_TIMER_CONFIGURE_ENABLED());
231 }
232
233 DISPATCH_ALWAYS_INLINE
234 static inline void
235 _dispatch_trace_timer_configure(dispatch_source_t ds, uintptr_t ident,
236 struct dispatch_timer_source_s *values)
237 {
238 struct dispatch_trace_timer_params_s params;
239 DISPATCH_TIMER_CONFIGURE(ds, _dispatch_trace_timer_function(ds->ds_refs),
240 _dispatch_trace_timer_params(ident, values, 0,
241 &params));
242 }
243
244 DISPATCH_ALWAYS_INLINE
245 static inline void
246 _dispatch_trace_timer_program(dispatch_source_refs_t dr, uint64_t deadline)
247 {
248 if (slowpath(DISPATCH_TIMER_PROGRAM_ENABLED())) {
249 if (deadline && dr) {
250 dispatch_source_t ds = _dispatch_source_from_refs(dr);
251 struct dispatch_trace_timer_params_s params;
252 DISPATCH_TIMER_PROGRAM(ds, _dispatch_trace_timer_function(dr),
253 _dispatch_trace_timer_params(ds->ds_ident_hack,
254 &ds_timer(dr), deadline, &params));
255 }
256 }
257 }
258
259 DISPATCH_ALWAYS_INLINE
260 static inline void
261 _dispatch_trace_timer_wake(dispatch_source_refs_t dr)
262 {
263 if (slowpath(DISPATCH_TIMER_WAKE_ENABLED())) {
264 if (dr) {
265 dispatch_source_t ds = _dispatch_source_from_refs(dr);
266 DISPATCH_TIMER_WAKE(ds, _dispatch_trace_timer_function(dr));
267 }
268 }
269 }
270
271 DISPATCH_ALWAYS_INLINE
272 static inline void
273 _dispatch_trace_timer_fire(dispatch_source_refs_t dr, unsigned long data,
274 unsigned long missed)
275 {
276 if (slowpath(DISPATCH_TIMER_FIRE_ENABLED())) {
277 if (!(data - missed) && dr) {
278 dispatch_source_t ds = _dispatch_source_from_refs(dr);
279 DISPATCH_TIMER_FIRE(ds, _dispatch_trace_timer_function(dr));
280 }
281 }
282 }
283
284 #else
285
286 #define _dispatch_trace_timer_configure_enabled() false
287 #define _dispatch_trace_timer_configure(ds, ident, values) \
288 do { (void)(ds); (void)(ident); (void)(values); } while(0)
289 #define _dispatch_trace_timer_program(dr, deadline) \
290 do { (void)(dr); (void)(deadline); } while(0)
291 #define _dispatch_trace_timer_wake(dr) \
292 do { (void)(dr); } while(0)
293 #define _dispatch_trace_timer_fire(dr, data, missed) \
294 do { (void)(dr); (void)(data); (void)(missed); } while(0)
295
296 #endif // DISPATCH_USE_DTRACE
297
298 #endif // DISPATCH_PURE_C
299
300 #endif // __DISPATCH_TRACE__