]> git.saurik.com Git - apple/libdispatch.git/blob - src/trace.h
libdispatch-913.1.6.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_INTROSPECTION
33 #define _dispatch_trace_callout(_c, _f, _dcc) do { \
34 if (slowpath(DISPATCH_CALLOUT_ENTRY_ENABLED()) || \
35 slowpath(DISPATCH_CALLOUT_RETURN_ENABLED())) { \
36 dispatch_queue_t _dq = _dispatch_queue_get_current(); \
37 const char *_label = _dq && _dq->dq_label ? _dq->dq_label : ""; \
38 dispatch_function_t _func = (dispatch_function_t)(_f); \
39 void *_ctxt = (_c); \
40 DISPATCH_CALLOUT_ENTRY(_dq, _label, _func, _ctxt); \
41 _dcc; \
42 DISPATCH_CALLOUT_RETURN(_dq, _label, _func, _ctxt); \
43 } else { \
44 _dcc; \
45 } \
46 } while (0)
47 #elif DISPATCH_INTROSPECTION
48 #define _dispatch_trace_callout(_c, _f, _dcc) \
49 do { (void)(_c); (void)(_f); _dcc; } while (0)
50 #endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
51
52 #if DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
53 DISPATCH_ALWAYS_INLINE
54 static inline void
55 _dispatch_trace_client_callout(void *ctxt, dispatch_function_t f)
56 {
57 dispatch_function_t func = (f == _dispatch_call_block_and_release &&
58 ctxt ? _dispatch_Block_invoke(ctxt) : f);
59 _dispatch_introspection_callout_entry(ctxt, func);
60 _dispatch_trace_callout(ctxt, func, _dispatch_client_callout(ctxt, f));
61 _dispatch_introspection_callout_return(ctxt, func);
62 }
63
64 DISPATCH_ALWAYS_INLINE
65 static inline void
66 _dispatch_trace_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
67 {
68 dispatch_function_t func = (dispatch_function_t)f;
69 _dispatch_introspection_callout_entry(ctxt, func);
70 _dispatch_trace_callout(ctxt, func, _dispatch_client_callout2(ctxt, i, f));
71 _dispatch_introspection_callout_return(ctxt, func);
72 }
73
74 #define _dispatch_client_callout _dispatch_trace_client_callout
75 #define _dispatch_client_callout2 _dispatch_trace_client_callout2
76 #endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
77
78 #if DISPATCH_USE_DTRACE_INTROSPECTION
79 #define _dispatch_trace_continuation(_q, _o, _t) do { \
80 dispatch_queue_t _dq = (_q); \
81 const char *_label = _dq && _dq->dq_label ? _dq->dq_label : ""; \
82 struct dispatch_object_s *_do = (_o); \
83 dispatch_continuation_t _dc; \
84 char *_kind; \
85 dispatch_function_t _func; \
86 void *_ctxt; \
87 if (_dispatch_object_has_vtable(_do)) { \
88 _kind = (char*)dx_kind(_do); \
89 if ((dx_type(_do) & _DISPATCH_META_TYPE_MASK) == \
90 _DISPATCH_SOURCE_TYPE && (_dq) != &_dispatch_mgr_q) { \
91 dispatch_source_t _ds = (dispatch_source_t)_do; \
92 _dc = os_atomic_load(&_ds->ds_refs->ds_handler[ \
93 DS_EVENT_HANDLER], relaxed); \
94 _func = _dc ? _dc->dc_func : NULL; \
95 _ctxt = _dc ? _dc->dc_ctxt : NULL; \
96 } else { \
97 _func = (dispatch_function_t)_dispatch_queue_invoke; \
98 _ctxt = _do->do_ctxt; \
99 } \
100 } else { \
101 _dc = (void*)_do; \
102 _ctxt = _dc->dc_ctxt; \
103 if (_dc->dc_flags & DISPATCH_OBJ_SYNC_WAITER_BIT) { \
104 _kind = "semaphore"; \
105 _func = (dispatch_function_t)dispatch_semaphore_signal; \
106 } else if (_dc->dc_flags & DISPATCH_OBJ_BLOCK_BIT) { \
107 _kind = "block"; \
108 _func = _dispatch_Block_invoke(_dc->dc_ctxt); \
109 } else { \
110 _kind = "function"; \
111 _func = _dc->dc_func; \
112 } \
113 } \
114 _t(_dq, _label, _do, _kind, _func, _ctxt); \
115 } while (0)
116 #elif DISPATCH_INTROSPECTION
117 #define _dispatch_trace_continuation(_q, _o, _t) \
118 do { (void)(_q); (void)(_o); } while(0)
119 #define DISPATCH_QUEUE_PUSH_ENABLED() 0
120 #define DISPATCH_QUEUE_POP_ENABLED() 0
121 #endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
122
123 #if DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
124 DISPATCH_ALWAYS_INLINE
125 static inline void
126 _dispatch_trace_root_queue_push_list(dispatch_queue_t dq,
127 dispatch_object_t _head, dispatch_object_t _tail, int n)
128 {
129 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
130 struct dispatch_object_s *dou = _head._do;
131 do {
132 _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH);
133 } while (dou != _tail._do && (dou = dou->do_next));
134 }
135 _dispatch_introspection_queue_push_list(dq, _head, _tail);
136 _dispatch_root_queue_push_inline(dq, _head, _tail, n);
137 }
138
139 DISPATCH_ALWAYS_INLINE
140 static inline void
141 _dispatch_trace_queue_push_inline(dispatch_queue_t dq, dispatch_object_t _tail,
142 dispatch_qos_t qos)
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_inline(dq, _tail, qos);
150 }
151
152 DISPATCH_ALWAYS_INLINE
153 static inline void
154 _dispatch_trace_continuation_push(dispatch_queue_t dq, dispatch_object_t _tail)
155 {
156 if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) {
157 struct dispatch_object_s *dou = _tail._do;
158 _dispatch_trace_continuation(dq, dou, DISPATCH_QUEUE_PUSH);
159 }
160 _dispatch_introspection_queue_push(dq, _tail);
161 }
162
163 #define _dispatch_root_queue_push_inline _dispatch_trace_root_queue_push_list
164 #define _dispatch_queue_push_inline _dispatch_trace_queue_push_inline
165
166 DISPATCH_ALWAYS_INLINE
167 static inline void
168 _dispatch_trace_continuation_pop(dispatch_queue_t dq, dispatch_object_t dou)
169 {
170 if (slowpath(DISPATCH_QUEUE_POP_ENABLED())) {
171 _dispatch_trace_continuation(dq, dou._do, DISPATCH_QUEUE_POP);
172 }
173 _dispatch_introspection_queue_pop(dq, dou);
174 }
175 #else
176 #define _dispatch_trace_continuation_push(dq, dou) \
177 do { (void)(dq); (void)(dou); } while(0)
178 #define _dispatch_trace_continuation_pop(dq, dou) \
179 do { (void)(dq); (void)(dou); } while(0)
180 #endif // DISPATCH_USE_DTRACE_INTROSPECTION || DISPATCH_INTROSPECTION
181
182 #if DISPATCH_USE_DTRACE
183 static inline dispatch_function_t
184 _dispatch_trace_timer_function(dispatch_timer_source_refs_t dr)
185 {
186 dispatch_continuation_t dc;
187 dc = os_atomic_load(&dr->ds_handler[DS_EVENT_HANDLER], relaxed);
188 return dc ? dc->dc_func : NULL;
189 }
190
191 DISPATCH_ALWAYS_INLINE
192 static inline dispatch_trace_timer_params_t
193 _dispatch_trace_timer_params(dispatch_clock_t clock,
194 struct dispatch_timer_source_s *values, uint64_t deadline,
195 dispatch_trace_timer_params_t params)
196 {
197 #define _dispatch_trace_time2nano3(t) \
198 (clock == DISPATCH_CLOCK_MACH ? _dispatch_time_mach2nano(t) : (t))
199 #define _dispatch_trace_time2nano2(v, t) ({ uint64_t _t = (t); \
200 (v) >= INT64_MAX ? -1ll : (int64_t)_dispatch_trace_time2nano3(_t);})
201 #define _dispatch_trace_time2nano(v) ({ uint64_t _t; \
202 _t = _dispatch_trace_time2nano3(v); _t >= INT64_MAX ? -1ll : \
203 (int64_t)_t; })
204 if (deadline) {
205 params->deadline = (int64_t)deadline;
206 } else {
207 uint64_t now = _dispatch_time_now(clock);
208 params->deadline = _dispatch_trace_time2nano2(values->target,
209 values->target < now ? 0 : values->target - now);
210 }
211 uint64_t leeway = values->deadline - values->target;
212 params->interval = _dispatch_trace_time2nano(values->interval);
213 params->leeway = _dispatch_trace_time2nano(leeway);
214 return params;
215 }
216
217 DISPATCH_ALWAYS_INLINE
218 static inline bool
219 _dispatch_trace_timer_configure_enabled(void)
220 {
221 return slowpath(DISPATCH_TIMER_CONFIGURE_ENABLED());
222 }
223
224 DISPATCH_ALWAYS_INLINE
225 static inline void
226 _dispatch_trace_timer_configure(dispatch_source_t ds, dispatch_clock_t clock,
227 struct dispatch_timer_source_s *values)
228 {
229 dispatch_timer_source_refs_t dr = ds->ds_timer_refs;
230 struct dispatch_trace_timer_params_s params;
231 DISPATCH_TIMER_CONFIGURE(ds, _dispatch_trace_timer_function(dr),
232 _dispatch_trace_timer_params(clock, values, 0, &params));
233 }
234
235 DISPATCH_ALWAYS_INLINE
236 static inline void
237 _dispatch_trace_timer_program(dispatch_timer_source_refs_t dr, uint64_t deadline)
238 {
239 if (slowpath(DISPATCH_TIMER_PROGRAM_ENABLED())) {
240 if (deadline && dr) {
241 dispatch_source_t ds = _dispatch_source_from_refs(dr);
242 dispatch_clock_t clock = DISPATCH_TIMER_CLOCK(dr->du_ident);
243 struct dispatch_trace_timer_params_s params;
244 DISPATCH_TIMER_PROGRAM(ds, _dispatch_trace_timer_function(dr),
245 _dispatch_trace_timer_params(clock, &dr->dt_timer,
246 deadline, &params));
247 }
248 }
249 }
250
251 DISPATCH_ALWAYS_INLINE
252 static inline void
253 _dispatch_trace_timer_wake(dispatch_timer_source_refs_t dr)
254 {
255 if (slowpath(DISPATCH_TIMER_WAKE_ENABLED())) {
256 if (dr) {
257 dispatch_source_t ds = _dispatch_source_from_refs(dr);
258 DISPATCH_TIMER_WAKE(ds, _dispatch_trace_timer_function(dr));
259 }
260 }
261 }
262
263 DISPATCH_ALWAYS_INLINE
264 static inline void
265 _dispatch_trace_timer_fire(dispatch_timer_source_refs_t dr, uint64_t data,
266 uint64_t missed)
267 {
268 if (slowpath(DISPATCH_TIMER_FIRE_ENABLED())) {
269 if (!(data - missed) && dr) {
270 dispatch_source_t ds = _dispatch_source_from_refs(dr);
271 DISPATCH_TIMER_FIRE(ds, _dispatch_trace_timer_function(dr));
272 }
273 }
274 }
275
276 #else
277
278 #define _dispatch_trace_timer_configure_enabled() false
279 #define _dispatch_trace_timer_configure(ds, clock, values) \
280 do { (void)(ds); (void)(clock); (void)(values); } while(0)
281 #define _dispatch_trace_timer_program(dr, deadline) \
282 do { (void)(dr); (void)(deadline); } while(0)
283 #define _dispatch_trace_timer_wake(dr) \
284 do { (void)(dr); } while(0)
285 #define _dispatch_trace_timer_fire(dr, data, missed) \
286 do { (void)(dr); (void)(data); (void)(missed); } while(0)
287
288 #endif // DISPATCH_USE_DTRACE
289
290 #endif // DISPATCH_PURE_C
291
292 #endif // __DISPATCH_TRACE__