]> git.saurik.com Git - apple/libdispatch.git/blob - src/event/event.c
libdispatch-913.20.5.tar.gz
[apple/libdispatch.git] / src / event / event.c
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 };