]>
Commit | Line | Data |
---|---|---|
6b746eb4 A |
1 | /* |
2 | * Copyright (c) 2008-2016 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 | #include "internal.h" | |
22 | ||
23 | DISPATCH_NOINLINE | |
24 | static dispatch_unote_t | |
25 | _dispatch_unote_create(dispatch_source_type_t dst, | |
26 | uintptr_t handle, unsigned long mask) | |
27 | { | |
28 | dispatch_unote_linkage_t dul; | |
29 | dispatch_unote_class_t du; | |
30 | ||
31 | if (mask & ~dst->dst_mask) { | |
32 | return DISPATCH_UNOTE_NULL; | |
33 | } | |
34 | ||
35 | if (dst->dst_filter != DISPATCH_EVFILT_TIMER) { | |
36 | if (dst->dst_mask && !mask) { | |
37 | return DISPATCH_UNOTE_NULL; | |
38 | } | |
39 | } | |
40 | ||
41 | if ((dst->dst_flags & EV_UDATA_SPECIFIC) || | |
42 | (dst->dst_filter == DISPATCH_EVFILT_TIMER)) { | |
43 | du = _dispatch_calloc(1u, dst->dst_size); | |
44 | } else { | |
45 | dul = _dispatch_calloc(1u, sizeof(*dul) + dst->dst_size); | |
46 | du = _dispatch_unote_linkage_get_unote(dul)._du; | |
47 | } | |
48 | du->du_type = dst; | |
49 | du->du_can_be_wlh = dst->dst_per_trigger_qos; | |
50 | du->du_ident = (uint32_t)handle; | |
51 | du->du_filter = dst->dst_filter; | |
52 | du->du_fflags = (typeof(du->du_fflags))mask; | |
53 | if (dst->dst_flags & EV_UDATA_SPECIFIC) { | |
54 | du->du_is_direct = true; | |
55 | } | |
56 | du->du_data_action = DISPATCH_UNOTE_ACTION_DATA_OR; | |
57 | return (dispatch_unote_t){ ._du = du }; | |
58 | } | |
59 | ||
60 | DISPATCH_NOINLINE | |
61 | dispatch_unote_t | |
62 | _dispatch_unote_create_with_handle(dispatch_source_type_t dst, | |
63 | uintptr_t handle, unsigned long mask) | |
64 | { | |
65 | if (!handle) { | |
66 | return DISPATCH_UNOTE_NULL; | |
67 | } | |
68 | return _dispatch_unote_create(dst, handle, mask); | |
69 | } | |
70 | ||
71 | DISPATCH_NOINLINE | |
72 | dispatch_unote_t | |
73 | _dispatch_unote_create_with_fd(dispatch_source_type_t dst, | |
74 | uintptr_t handle, unsigned long mask) | |
75 | { | |
76 | #if !TARGET_OS_MAC // <rdar://problem/27756657> | |
77 | if (handle > INT_MAX) { | |
78 | return DISPATCH_UNOTE_NULL; | |
79 | } | |
80 | #endif | |
81 | dispatch_unote_t du = _dispatch_unote_create(dst, handle, mask); | |
82 | if (du._du) { | |
83 | int16_t filter = dst->dst_filter; | |
84 | du._du->du_data_action = (filter == EVFILT_READ||filter == EVFILT_WRITE) | |
85 | ? DISPATCH_UNOTE_ACTION_DATA_SET : DISPATCH_UNOTE_ACTION_DATA_OR; | |
86 | } | |
87 | return du; | |
88 | } | |
89 | ||
90 | DISPATCH_NOINLINE | |
91 | dispatch_unote_t | |
92 | _dispatch_unote_create_without_handle(dispatch_source_type_t dst, | |
93 | uintptr_t handle, unsigned long mask) | |
94 | { | |
95 | if (handle) { | |
96 | return DISPATCH_UNOTE_NULL; | |
97 | } | |
98 | return _dispatch_unote_create(dst, handle, mask); | |
99 | } | |
100 | ||
101 | DISPATCH_NOINLINE | |
102 | void | |
103 | _dispatch_unote_dispose(dispatch_unote_t du) | |
104 | { | |
105 | void *ptr = du._du; | |
106 | #if HAVE_MACH | |
107 | if (du._du->dmrr_handler_is_block) { | |
108 | Block_release(du._dmrr->dmrr_handler_ctxt); | |
109 | } | |
110 | #endif | |
111 | if (du._du->du_is_timer) { | |
112 | if (unlikely(du._dt->dt_heap_entry[DTH_TARGET_ID] != DTH_INVALID_ID || | |
113 | du._dt->dt_heap_entry[DTH_DEADLINE_ID] != DTH_INVALID_ID)) { | |
114 | DISPATCH_INTERNAL_CRASH(0, "Disposing of timer still in its heap"); | |
115 | } | |
116 | if (unlikely(du._dt->dt_pending_config)) { | |
117 | free(du._dt->dt_pending_config); | |
118 | du._dt->dt_pending_config = NULL; | |
119 | } | |
120 | } else if (!du._du->du_is_direct) { | |
121 | ptr = _dispatch_unote_get_linkage(du); | |
122 | } | |
123 | free(ptr); | |
124 | } | |
125 | ||
126 | #pragma mark data or / add | |
127 | ||
128 | static dispatch_unote_t | |
129 | _dispatch_source_data_create(dispatch_source_type_t dst, uintptr_t handle, | |
130 | unsigned long mask) | |
131 | { | |
132 | if (handle || mask) { | |
133 | return DISPATCH_UNOTE_NULL; | |
134 | } | |
135 | ||
136 | // bypass _dispatch_unote_create() because this is always "direct" | |
137 | // even when EV_UDATA_SPECIFIC is 0 | |
138 | dispatch_unote_class_t du = _dispatch_calloc(1u, dst->dst_size); | |
139 | du->du_type = dst; | |
140 | du->du_filter = dst->dst_filter; | |
141 | du->du_is_direct = true; | |
142 | return (dispatch_unote_t){ ._du = du }; | |
143 | } | |
144 | ||
145 | const dispatch_source_type_s _dispatch_source_type_data_add = { | |
146 | .dst_kind = "data-add", | |
147 | .dst_filter = DISPATCH_EVFILT_CUSTOM_ADD, | |
148 | .dst_flags = EV_UDATA_SPECIFIC|EV_CLEAR, | |
149 | .dst_size = sizeof(struct dispatch_source_refs_s), | |
150 | ||
151 | .dst_create = _dispatch_source_data_create, | |
152 | .dst_merge_evt = NULL, | |
153 | }; | |
154 | ||
155 | const dispatch_source_type_s _dispatch_source_type_data_or = { | |
156 | .dst_kind = "data-or", | |
157 | .dst_filter = DISPATCH_EVFILT_CUSTOM_OR, | |
158 | .dst_flags = EV_UDATA_SPECIFIC|EV_CLEAR, | |
159 | .dst_size = sizeof(struct dispatch_source_refs_s), | |
160 | ||
161 | .dst_create = _dispatch_source_data_create, | |
162 | .dst_merge_evt = NULL, | |
163 | }; | |
164 | ||
165 | const dispatch_source_type_s _dispatch_source_type_data_replace = { | |
166 | .dst_kind = "data-replace", | |
167 | .dst_filter = DISPATCH_EVFILT_CUSTOM_REPLACE, | |
168 | .dst_flags = EV_UDATA_SPECIFIC|EV_CLEAR, | |
169 | .dst_size = sizeof(struct dispatch_source_refs_s), | |
170 | ||
171 | .dst_create = _dispatch_source_data_create, | |
172 | .dst_merge_evt = NULL, | |
173 | }; | |
174 | ||
175 | #pragma mark file descriptors | |
176 | ||
177 | const dispatch_source_type_s _dispatch_source_type_read = { | |
178 | .dst_kind = "read", | |
179 | .dst_filter = EVFILT_READ, | |
180 | .dst_flags = EV_UDATA_SPECIFIC|EV_DISPATCH|EV_VANISHED, | |
181 | #if DISPATCH_EVENT_BACKEND_KEVENT | |
182 | #if HAVE_DECL_NOTE_LOWAT | |
183 | .dst_fflags = NOTE_LOWAT, | |
184 | #endif | |
185 | .dst_data = 1, | |
186 | #endif // DISPATCH_EVENT_BACKEND_KEVENT | |
187 | .dst_size = sizeof(struct dispatch_source_refs_s), | |
188 | ||
189 | .dst_create = _dispatch_unote_create_with_fd, | |
190 | .dst_merge_evt = _dispatch_source_merge_evt, | |
191 | }; | |
192 | ||
193 | const dispatch_source_type_s _dispatch_source_type_write = { | |
194 | .dst_kind = "write", | |
195 | .dst_filter = EVFILT_WRITE, | |
196 | .dst_flags = EV_UDATA_SPECIFIC|EV_DISPATCH|EV_VANISHED, | |
197 | #if DISPATCH_EVENT_BACKEND_KEVENT | |
198 | #if HAVE_DECL_NOTE_LOWAT | |
199 | .dst_fflags = NOTE_LOWAT, | |
200 | #endif | |
201 | .dst_data = 1, | |
202 | #endif // DISPATCH_EVENT_BACKEND_KEVENT | |
203 | .dst_size = sizeof(struct dispatch_source_refs_s), | |
204 | ||
205 | .dst_create = _dispatch_unote_create_with_fd, | |
206 | .dst_merge_evt = _dispatch_source_merge_evt, | |
207 | }; | |
208 | ||
209 | #pragma mark signals | |
210 | ||
211 | static dispatch_unote_t | |
212 | _dispatch_source_signal_create(dispatch_source_type_t dst, uintptr_t handle, | |
213 | unsigned long mask) | |
214 | { | |
215 | if (handle >= NSIG) { | |
216 | return DISPATCH_UNOTE_NULL; | |
217 | } | |
218 | dispatch_unote_t du = _dispatch_unote_create_with_handle(dst, handle, mask); | |
219 | if (du._du) { | |
220 | du._du->du_data_action = DISPATCH_UNOTE_ACTION_DATA_ADD; | |
221 | } | |
222 | return du; | |
223 | } | |
224 | ||
225 | const dispatch_source_type_s _dispatch_source_type_signal = { | |
226 | .dst_kind = "signal", | |
227 | .dst_filter = EVFILT_SIGNAL, | |
228 | .dst_flags = DISPATCH_EV_DIRECT|EV_CLEAR, | |
229 | .dst_size = sizeof(struct dispatch_source_refs_s), | |
230 | ||
231 | .dst_create = _dispatch_source_signal_create, | |
232 | .dst_merge_evt = _dispatch_source_merge_evt, | |
233 | }; | |
234 | ||
235 | #pragma mark timers | |
236 | ||
237 | bool _dispatch_timers_reconfigure, _dispatch_timers_expired; | |
238 | uint32_t _dispatch_timers_processing_mask; | |
239 | #if DISPATCH_USE_DTRACE | |
240 | uint32_t _dispatch_timers_will_wake; | |
241 | #endif | |
242 | #define DISPATCH_TIMER_HEAP_INITIALIZER(tidx) \ | |
243 | [tidx] = { \ | |
244 | .dth_target = UINT64_MAX, \ | |
245 | .dth_deadline = UINT64_MAX, \ | |
246 | } | |
247 | #define DISPATCH_TIMER_HEAP_INIT(kind, qos) \ | |
248 | DISPATCH_TIMER_HEAP_INITIALIZER(DISPATCH_TIMER_INDEX( \ | |
249 | DISPATCH_CLOCK_##kind, DISPATCH_TIMER_QOS_##qos)) | |
250 | ||
251 | struct dispatch_timer_heap_s _dispatch_timers_heap[] = { | |
252 | DISPATCH_TIMER_HEAP_INIT(WALL, NORMAL), | |
253 | DISPATCH_TIMER_HEAP_INIT(MACH, NORMAL), | |
254 | #if DISPATCH_HAVE_TIMER_QOS | |
255 | DISPATCH_TIMER_HEAP_INIT(WALL, CRITICAL), | |
256 | DISPATCH_TIMER_HEAP_INIT(MACH, CRITICAL), | |
257 | DISPATCH_TIMER_HEAP_INIT(WALL, BACKGROUND), | |
258 | DISPATCH_TIMER_HEAP_INIT(MACH, BACKGROUND), | |
259 | #endif | |
260 | }; | |
261 | ||
262 | static dispatch_unote_t | |
263 | _dispatch_source_timer_create(dispatch_source_type_t dst, | |
264 | uintptr_t handle, unsigned long mask) | |
265 | { | |
266 | uint32_t fflags = dst->dst_fflags; | |
267 | dispatch_unote_t du; | |
268 | ||
269 | // normalize flags | |
270 | if (mask & DISPATCH_TIMER_STRICT) { | |
271 | mask &= ~(unsigned long)DISPATCH_TIMER_BACKGROUND; | |
272 | } | |
273 | ||
274 | if (fflags & DISPATCH_TIMER_INTERVAL) { | |
275 | if (!handle) return DISPATCH_UNOTE_NULL; | |
276 | du = _dispatch_unote_create_without_handle(dst, 0, mask); | |
277 | } else { | |
278 | du = _dispatch_unote_create_without_handle(dst, handle, mask); | |
279 | } | |
280 | ||
281 | if (du._dt) { | |
282 | du._dt->du_is_timer = true; | |
283 | du._dt->du_data_action = DISPATCH_UNOTE_ACTION_DATA_ADD; | |
284 | du._dt->du_fflags |= fflags; | |
285 | du._dt->du_ident = _dispatch_source_timer_idx(du); | |
286 | du._dt->dt_timer.target = UINT64_MAX; | |
287 | du._dt->dt_timer.deadline = UINT64_MAX; | |
288 | du._dt->dt_timer.interval = UINT64_MAX; | |
289 | du._dt->dt_heap_entry[DTH_TARGET_ID] = DTH_INVALID_ID; | |
290 | du._dt->dt_heap_entry[DTH_DEADLINE_ID] = DTH_INVALID_ID; | |
291 | } | |
292 | return du; | |
293 | } | |
294 | ||
295 | const dispatch_source_type_s _dispatch_source_type_timer = { | |
296 | .dst_kind = "timer", | |
297 | .dst_filter = DISPATCH_EVFILT_TIMER, | |
298 | .dst_flags = EV_DISPATCH, | |
299 | .dst_mask = DISPATCH_TIMER_STRICT|DISPATCH_TIMER_BACKGROUND, | |
300 | .dst_fflags = 0, | |
301 | .dst_size = sizeof(struct dispatch_timer_source_refs_s), | |
302 | ||
303 | .dst_create = _dispatch_source_timer_create, | |
304 | }; | |
305 | ||
306 | const dispatch_source_type_s _dispatch_source_type_after = { | |
307 | .dst_kind = "timer (after)", | |
308 | .dst_filter = DISPATCH_EVFILT_TIMER, | |
309 | .dst_flags = EV_DISPATCH, | |
310 | .dst_mask = 0, | |
311 | .dst_fflags = DISPATCH_TIMER_AFTER, | |
312 | .dst_size = sizeof(struct dispatch_timer_source_refs_s), | |
313 | ||
314 | .dst_create = _dispatch_source_timer_create, | |
315 | }; | |
316 | ||
317 | const dispatch_source_type_s _dispatch_source_type_interval = { | |
318 | .dst_kind = "timer (interval)", | |
319 | .dst_filter = DISPATCH_EVFILT_TIMER, | |
320 | .dst_flags = EV_DISPATCH, | |
321 | .dst_mask = DISPATCH_TIMER_STRICT|DISPATCH_TIMER_BACKGROUND | |
322 | |DISPATCH_INTERVAL_UI_ANIMATION, | |
323 | .dst_fflags = DISPATCH_TIMER_INTERVAL|DISPATCH_TIMER_CLOCK_MACH, | |
324 | .dst_size = sizeof(struct dispatch_timer_source_refs_s), | |
325 | ||
326 | .dst_create = _dispatch_source_timer_create, | |
327 | }; |