xref: /trueos/lib/libdispatch/src/source_internal.h (revision 3be304f06dd39a07bcda5ca03a53a3604eb79d2c)
1 /*
2  * Copyright (c) 2008-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_SOURCE_INTERNAL__
28 #define __DISPATCH_SOURCE_INTERNAL__
29 
30 #ifndef __DISPATCH_INDIRECT__
31 #error "Please #include <dispatch/dispatch.h> instead of this file directly."
32 #include <dispatch/base.h> // for HeaderDoc
33 #endif
34 
35 #define DISPATCH_EVFILT_TIMER		(-EVFILT_SYSCOUNT - 1)
36 #define DISPATCH_EVFILT_CUSTOM_ADD	(-EVFILT_SYSCOUNT - 2)
37 #define DISPATCH_EVFILT_CUSTOM_OR	(-EVFILT_SYSCOUNT - 3)
38 #define DISPATCH_EVFILT_MACH_NOTIFICATION	(-EVFILT_SYSCOUNT - 4)
39 #define DISPATCH_EVFILT_SYSCOUNT	( EVFILT_SYSCOUNT + 4)
40 
41 // NOTE: dispatch_source_mach_send_flags_t and dispatch_source_mach_recv_flags_t
42 //       bit values must not overlap as they share the same kevent fflags !
43 
44 /*!
45  * @enum dispatch_source_mach_send_flags_t
46  *
47  * @constant DISPATCH_MACH_SEND_DELETED
48  * Port-deleted notification. Disabled for source registration.
49  */
50 enum {
51 	DISPATCH_MACH_SEND_DELETED = 0x4,
52 };
53 /*!
54  * @enum dispatch_source_mach_recv_flags_t
55  *
56  * @constant DISPATCH_MACH_RECV_MESSAGE
57  * Receive right has pending messages
58  *
59  * @constant DISPATCH_MACH_RECV_MESSAGE_DIRECT
60  * Receive messages from receive right directly via kevent64()
61  *
62  * @constant DISPATCH_MACH_RECV_NO_SENDERS
63  * Receive right has no more senders. TODO <rdar://problem/8132399>
64  */
65 enum {
66 	DISPATCH_MACH_RECV_MESSAGE = 0x2,
67 	DISPATCH_MACH_RECV_MESSAGE_DIRECT = 0x10,
68 	DISPATCH_MACH_RECV_MESSAGE_DIRECT_ONCE = 0x20,
69 	DISPATCH_MACH_RECV_NO_SENDERS = 0x40,
70 };
71 
72 enum {
73 	DISPATCH_TIMER_WALL_CLOCK = 0x4,
74 	DISPATCH_TIMER_INTERVAL = 0x8,
75 	DISPATCH_TIMER_WITH_AGGREGATE = 0x10,
76 };
77 
78 // low bits are timer QoS class
79 #define DISPATCH_TIMER_QOS_NORMAL 0u
80 #define DISPATCH_TIMER_QOS_CRITICAL 1u
81 #define DISPATCH_TIMER_QOS_BACKGROUND 2u
82 #define DISPATCH_TIMER_QOS_COUNT (DISPATCH_TIMER_QOS_BACKGROUND + 1)
83 #define DISPATCH_TIMER_QOS(tidx) ((uintptr_t)(tidx) & 0x3ul)
84 
85 #define DISPATCH_TIMER_KIND_WALL 0u
86 #define DISPATCH_TIMER_KIND_MACH 1u
87 #define DISPATCH_TIMER_KIND_COUNT (DISPATCH_TIMER_KIND_MACH + 1)
88 #define DISPATCH_TIMER_KIND(tidx) (((uintptr_t)(tidx) >> 2) & 0x1ul)
89 
90 #define DISPATCH_TIMER_INDEX(kind, qos) (((kind) << 2) | (qos))
91 #define DISPATCH_TIMER_INDEX_DISARM \
92 		DISPATCH_TIMER_INDEX(DISPATCH_TIMER_KIND_COUNT, 0)
93 #define DISPATCH_TIMER_INDEX_COUNT (DISPATCH_TIMER_INDEX_DISARM + 1)
94 #define DISPATCH_TIMER_IDENT(flags) ({ unsigned long f = (flags); \
95 		DISPATCH_TIMER_INDEX(f & DISPATCH_TIMER_WALL_CLOCK ? \
96 		DISPATCH_TIMER_KIND_WALL : DISPATCH_TIMER_KIND_MACH, \
97 		f & DISPATCH_TIMER_STRICT ? DISPATCH_TIMER_QOS_CRITICAL : \
98 		f & DISPATCH_TIMER_BACKGROUND ? DISPATCH_TIMER_QOS_BACKGROUND : \
99 		DISPATCH_TIMER_QOS_NORMAL); })
100 
101 
102 struct dispatch_kevent_s {
103 	TAILQ_ENTRY(dispatch_kevent_s) dk_list;
104 	TAILQ_HEAD(, dispatch_source_refs_s) dk_sources;
105 	struct kevent64_s dk_kevent;
106 };
107 
108 typedef struct dispatch_kevent_s *dispatch_kevent_t;
109 
110 struct dispatch_source_type_s {
111 	struct kevent64_s ke;
112 	uint64_t mask;
113 	void (*init)(dispatch_source_t ds, dispatch_source_type_t type,
114 			uintptr_t handle, unsigned long mask, dispatch_queue_t q);
115 };
116 
117 struct dispatch_timer_source_s {
118 	uint64_t target;
119 	uint64_t deadline;
120 	uint64_t last_fire;
121 	uint64_t interval;
122 	uint64_t leeway;
123 	unsigned long flags; // dispatch_timer_flags_t
124 	unsigned long missed;
125 };
126 
127 enum {
128 	DS_EVENT_HANDLER = 0,
129 	DS_CANCEL_HANDLER,
130 	DS_REGISTN_HANDLER,
131 };
132 
133 // Source state which may contain references to the source object
134 // Separately allocated so that 'leaks' can see sources <rdar://problem/9050566>
135 typedef struct dispatch_source_refs_s {
136 	TAILQ_ENTRY(dispatch_source_refs_s) dr_list;
137 	uintptr_t dr_source_wref; // "weak" backref to dispatch_source_t
138 	dispatch_continuation_t ds_handler[3];
139 } *dispatch_source_refs_t;
140 
141 typedef struct dispatch_timer_source_refs_s {
142 	struct dispatch_source_refs_s _ds_refs;
143 	struct dispatch_timer_source_s _ds_timer;
144 	TAILQ_ENTRY(dispatch_timer_source_refs_s) dt_list;
145 } *dispatch_timer_source_refs_t;
146 
147 typedef struct dispatch_timer_source_aggregate_refs_s {
148 	struct dispatch_timer_source_refs_s _dsa_refs;
149 	TAILQ_ENTRY(dispatch_timer_source_aggregate_refs_s) dra_list;
150 	TAILQ_ENTRY(dispatch_timer_source_aggregate_refs_s) dta_list;
151 } *dispatch_timer_source_aggregate_refs_t;
152 
153 #define _dispatch_ptr2wref(ptr) (~(uintptr_t)(ptr))
154 #define _dispatch_wref2ptr(ref) ((void*)~(ref))
155 #define _dispatch_source_from_refs(dr) \
156 		((dispatch_source_t)_dispatch_wref2ptr((dr)->dr_source_wref))
157 #define ds_timer(dr) \
158 		(((dispatch_timer_source_refs_t)(dr))->_ds_timer)
159 #define ds_timer_aggregate(ds) \
160 		((dispatch_timer_aggregate_t)((ds)->dq_specific_q))
161 
162 DISPATCH_ALWAYS_INLINE
163 static inline unsigned int
_dispatch_source_timer_idx(dispatch_source_refs_t dr)164 _dispatch_source_timer_idx(dispatch_source_refs_t dr)
165 {
166 	return DISPATCH_TIMER_IDENT(ds_timer(dr).flags);
167 }
168 
169 // ds_atomic_flags bits
170 #define DSF_CANCELED 1u // cancellation has been requested
171 #define DSF_ARMED 2u // source is armed
172 
173 #define DISPATCH_SOURCE_HEADER(refs) \
174 	dispatch_kevent_t ds_dkev; \
175 	dispatch_##refs##_refs_t ds_refs; \
176 	unsigned int ds_atomic_flags; \
177 	unsigned int \
178 		ds_is_level:1, \
179 		ds_is_adder:1, \
180 		ds_is_installed:1, \
181 		ds_needs_rearm:1, \
182 		ds_is_timer:1, \
183 		ds_vmpressure_override:1, \
184 		ds_memorystatus_override:1, \
185 		dm_handler_is_block:1, \
186 		dm_connect_handler_called:1, \
187 		dm_cancel_handler_called:1; \
188 	unsigned long ds_pending_data_mask;
189 
190 DISPATCH_CLASS_DECL(source);
191 struct dispatch_source_s {
192 	DISPATCH_STRUCT_HEADER(source);
193 	DISPATCH_QUEUE_HEADER;
194 	DISPATCH_SOURCE_HEADER(source);
195 	unsigned long ds_ident_hack;
196 	unsigned long ds_data;
197 	unsigned long ds_pending_data;
198 };
199 
200 // Mach channel state which may contain references to the channel object
201 // layout must match dispatch_source_refs_s
202 struct dispatch_mach_refs_s {
203 	TAILQ_ENTRY(dispatch_mach_refs_s) dr_list;
204 	uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t
205 	dispatch_mach_handler_function_t dm_handler_func;
206 	void *dm_handler_ctxt;
207 };
208 typedef struct dispatch_mach_refs_s *dispatch_mach_refs_t;
209 
210 struct dispatch_mach_reply_refs_s {
211 	TAILQ_ENTRY(dispatch_mach_reply_refs_s) dr_list;
212 	uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t
213 	dispatch_kevent_t dmr_dkev;
214 	void *dmr_ctxt;
215 	pthread_priority_t dmr_priority;
216 	voucher_t dmr_voucher;
217 	TAILQ_ENTRY(dispatch_mach_reply_refs_s) dmr_list;
218 };
219 typedef struct dispatch_mach_reply_refs_s *dispatch_mach_reply_refs_t;
220 
221 struct dispatch_mach_send_refs_s {
222 	TAILQ_ENTRY(dispatch_mach_send_refs_s) dr_list;
223 	uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t
224 	dispatch_mach_msg_t dm_checkin;
225 	TAILQ_HEAD(, dispatch_mach_reply_refs_s) dm_replies;
226 	uint32_t volatile dm_disconnect_cnt;
227 	uint32_t volatile dm_sending;
228 	unsigned int dm_needs_mgr:1;
229 	struct dispatch_object_s *volatile dm_tail;
230 	struct dispatch_object_s *volatile dm_head;
231 	mach_port_t dm_send, dm_checkin_port;
232 };
233 typedef struct dispatch_mach_send_refs_s *dispatch_mach_send_refs_t;
234 
235 DISPATCH_CLASS_DECL(mach);
236 struct dispatch_mach_s {
237 	DISPATCH_STRUCT_HEADER(mach);
238 	DISPATCH_QUEUE_HEADER;
239 	DISPATCH_SOURCE_HEADER(mach);
240 	dispatch_kevent_t dm_dkev;
241 	dispatch_mach_send_refs_t dm_refs;
242 };
243 
244 DISPATCH_CLASS_DECL(mach_msg);
245 struct dispatch_mach_msg_s {
246 	DISPATCH_STRUCT_HEADER(mach_msg);
247 	mach_port_t dmsg_reply;
248 	pthread_priority_t dmsg_priority;
249 	voucher_t dmsg_voucher;
250 	dispatch_mach_msg_destructor_t dmsg_destructor;
251 	size_t dmsg_size;
252 	union {
253 		mach_msg_header_t *dmsg_msg;
254 		char dmsg_buf[0];
255 	};
256 };
257 
258 #if TARGET_OS_EMBEDDED
259 #define DSL_HASH_SIZE  64u // must be a power of two
260 #else
261 #define DSL_HASH_SIZE 256u // must be a power of two
262 #endif
263 
264 void _dispatch_source_xref_dispose(dispatch_source_t ds);
265 void _dispatch_source_dispose(dispatch_source_t ds);
266 void _dispatch_source_invoke(dispatch_source_t ds);
267 unsigned long _dispatch_source_probe(dispatch_source_t ds);
268 size_t _dispatch_source_debug(dispatch_source_t ds, char* buf, size_t bufsiz);
269 void _dispatch_source_set_interval(dispatch_source_t ds, uint64_t interval);
270 void _dispatch_source_set_event_handler_with_context_f(dispatch_source_t ds,
271 		void *ctxt, dispatch_function_t handler);
272 
273 void _dispatch_mach_dispose(dispatch_mach_t dm);
274 void _dispatch_mach_invoke(dispatch_mach_t dm);
275 unsigned long _dispatch_mach_probe(dispatch_mach_t dm);
276 size_t _dispatch_mach_debug(dispatch_mach_t dm, char* buf, size_t bufsiz);
277 
278 void _dispatch_mach_msg_dispose(dispatch_mach_msg_t dmsg);
279 void _dispatch_mach_msg_invoke(dispatch_mach_msg_t dmsg);
280 size_t _dispatch_mach_msg_debug(dispatch_mach_msg_t dmsg, char* buf, size_t bufsiz);
281 
282 void _dispatch_mach_barrier_invoke(void *ctxt);
283 
284 unsigned long _dispatch_mgr_wakeup(dispatch_queue_t dq);
285 void _dispatch_mgr_thread(dispatch_queue_t dq);
286 
287 #endif /* __DISPATCH_SOURCE_INTERNAL__ */
288