2 * Copyright (c) 2008-2016 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
24 static dispatch_unote_t
25 _dispatch_unote_create(dispatch_source_type_t dst
,
26 uintptr_t handle
, unsigned long mask
)
28 dispatch_unote_linkage_t dul
;
29 dispatch_unote_class_t du
;
31 if (mask
& ~dst
->dst_mask
) {
32 return DISPATCH_UNOTE_NULL
;
35 if (dst
->dst_filter
!= DISPATCH_EVFILT_TIMER
) {
36 if (dst
->dst_mask
&& !mask
) {
37 return DISPATCH_UNOTE_NULL
;
41 if ((dst
->dst_flags
& EV_UDATA_SPECIFIC
) ||
42 (dst
->dst_filter
== DISPATCH_EVFILT_TIMER
)) {
43 du
= _dispatch_calloc(1u, dst
->dst_size
);
45 dul
= _dispatch_calloc(1u, sizeof(*dul
) + dst
->dst_size
);
46 du
= _dispatch_unote_linkage_get_unote(dul
)._du
;
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;
56 du
->du_data_action
= DISPATCH_UNOTE_ACTION_DATA_OR
;
57 return (dispatch_unote_t
){ ._du
= du
};
62 _dispatch_unote_create_with_handle(dispatch_source_type_t dst
,
63 uintptr_t handle
, unsigned long mask
)
66 return DISPATCH_UNOTE_NULL
;
68 return _dispatch_unote_create(dst
, handle
, mask
);
73 _dispatch_unote_create_with_fd(dispatch_source_type_t dst
,
74 uintptr_t handle
, unsigned long mask
)
76 #if !TARGET_OS_MAC // <rdar://problem/27756657>
77 if (handle
> INT_MAX
) {
78 return DISPATCH_UNOTE_NULL
;
81 dispatch_unote_t du
= _dispatch_unote_create(dst
, handle
, mask
);
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
;
92 _dispatch_unote_create_without_handle(dispatch_source_type_t dst
,
93 uintptr_t handle
, unsigned long mask
)
96 return DISPATCH_UNOTE_NULL
;
98 return _dispatch_unote_create(dst
, handle
, mask
);
103 _dispatch_unote_dispose(dispatch_unote_t du
)
107 if (du
._du
->dmrr_handler_is_block
) {
108 Block_release(du
._dmrr
->dmrr_handler_ctxt
);
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");
116 if (unlikely(du
._dt
->dt_pending_config
)) {
117 free(du
._dt
->dt_pending_config
);
118 du
._dt
->dt_pending_config
= NULL
;
120 } else if (!du
._du
->du_is_direct
) {
121 ptr
= _dispatch_unote_get_linkage(du
);
126 #pragma mark data or / add
128 static dispatch_unote_t
129 _dispatch_source_data_create(dispatch_source_type_t dst
, uintptr_t handle
,
132 if (handle
|| mask
) {
133 return DISPATCH_UNOTE_NULL
;
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
);
140 du
->du_filter
= dst
->dst_filter
;
141 du
->du_is_direct
= true;
142 return (dispatch_unote_t
){ ._du
= du
};
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
),
151 .dst_create
= _dispatch_source_data_create
,
152 .dst_merge_evt
= NULL
,
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
),
161 .dst_create
= _dispatch_source_data_create
,
162 .dst_merge_evt
= NULL
,
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
),
171 .dst_create
= _dispatch_source_data_create
,
172 .dst_merge_evt
= NULL
,
175 #pragma mark file descriptors
177 const dispatch_source_type_s _dispatch_source_type_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
,
186 #endif // DISPATCH_EVENT_BACKEND_KEVENT
187 .dst_size
= sizeof(struct dispatch_source_refs_s
),
189 .dst_create
= _dispatch_unote_create_with_fd
,
190 .dst_merge_evt
= _dispatch_source_merge_evt
,
193 const dispatch_source_type_s _dispatch_source_type_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
,
202 #endif // DISPATCH_EVENT_BACKEND_KEVENT
203 .dst_size
= sizeof(struct dispatch_source_refs_s
),
205 .dst_create
= _dispatch_unote_create_with_fd
,
206 .dst_merge_evt
= _dispatch_source_merge_evt
,
211 static dispatch_unote_t
212 _dispatch_source_signal_create(dispatch_source_type_t dst
, uintptr_t handle
,
215 if (handle
>= NSIG
) {
216 return DISPATCH_UNOTE_NULL
;
218 dispatch_unote_t du
= _dispatch_unote_create_with_handle(dst
, handle
, mask
);
220 du
._du
->du_data_action
= DISPATCH_UNOTE_ACTION_DATA_ADD
;
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
),
231 .dst_create
= _dispatch_source_signal_create
,
232 .dst_merge_evt
= _dispatch_source_merge_evt
,
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
;
242 #define DISPATCH_TIMER_HEAP_INITIALIZER(tidx) \
244 .dth_target = UINT64_MAX, \
245 .dth_deadline = UINT64_MAX, \
247 #define DISPATCH_TIMER_HEAP_INIT(kind, qos) \
248 DISPATCH_TIMER_HEAP_INITIALIZER(DISPATCH_TIMER_INDEX( \
249 DISPATCH_CLOCK_##kind, DISPATCH_TIMER_QOS_##qos))
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
),
262 static dispatch_unote_t
263 _dispatch_source_timer_create(dispatch_source_type_t dst
,
264 uintptr_t handle
, unsigned long mask
)
266 uint32_t fflags
= dst
->dst_fflags
;
270 if (mask
& DISPATCH_TIMER_STRICT
) {
271 mask
&= ~(unsigned long)DISPATCH_TIMER_BACKGROUND
;
274 if (fflags
& DISPATCH_TIMER_INTERVAL
) {
275 if (!handle
) return DISPATCH_UNOTE_NULL
;
276 du
= _dispatch_unote_create_without_handle(dst
, 0, mask
);
278 du
= _dispatch_unote_create_without_handle(dst
, handle
, mask
);
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
;
295 const dispatch_source_type_s _dispatch_source_type_timer
= {
297 .dst_filter
= DISPATCH_EVFILT_TIMER
,
298 .dst_flags
= EV_DISPATCH
,
299 .dst_mask
= DISPATCH_TIMER_STRICT
|DISPATCH_TIMER_BACKGROUND
,
301 .dst_size
= sizeof(struct dispatch_timer_source_refs_s
),
303 .dst_create
= _dispatch_source_timer_create
,
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
,
311 .dst_fflags
= DISPATCH_TIMER_AFTER
,
312 .dst_size
= sizeof(struct dispatch_timer_source_refs_s
),
314 .dst_create
= _dispatch_source_timer_create
,
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
),
326 .dst_create
= _dispatch_source_timer_create
,