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 */
50enum {
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 */
65enum {
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
72enum {
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
101struct dispatch_kevent_s {
102	TAILQ_ENTRY(dispatch_kevent_s) dk_list;
103	TAILQ_HEAD(, dispatch_source_refs_s) dk_sources;
104	struct kevent64_s dk_kevent;
105};
106
107typedef struct dispatch_kevent_s *dispatch_kevent_t;
108
109struct dispatch_source_type_s {
110	struct kevent64_s ke;
111	uint64_t mask;
112	void (*init)(dispatch_source_t ds, dispatch_source_type_t type,
113			uintptr_t handle, unsigned long mask, dispatch_queue_t q);
114};
115
116struct dispatch_timer_source_s {
117	uint64_t target;
118	uint64_t deadline;
119	uint64_t last_fire;
120	uint64_t interval;
121	uint64_t leeway;
122	unsigned long flags; // dispatch_timer_flags_t
123	unsigned long missed;
124};
125
126// Source state which may contain references to the source object
127// Separately allocated so that 'leaks' can see sources <rdar://problem/9050566>
128typedef struct dispatch_source_refs_s {
129	TAILQ_ENTRY(dispatch_source_refs_s) dr_list;
130	uintptr_t dr_source_wref; // "weak" backref to dispatch_source_t
131	dispatch_function_t ds_handler_func;
132	void *ds_handler_ctxt;
133	void *ds_cancel_handler;
134	void *ds_registration_handler;
135} *dispatch_source_refs_t;
136
137typedef struct dispatch_timer_source_refs_s {
138	struct dispatch_source_refs_s _ds_refs;
139	struct dispatch_timer_source_s _ds_timer;
140	TAILQ_ENTRY(dispatch_timer_source_refs_s) dt_list;
141} *dispatch_timer_source_refs_t;
142
143typedef struct dispatch_timer_source_aggregate_refs_s {
144	struct dispatch_timer_source_refs_s _dsa_refs;
145	TAILQ_ENTRY(dispatch_timer_source_aggregate_refs_s) dra_list;
146	TAILQ_ENTRY(dispatch_timer_source_aggregate_refs_s) dta_list;
147} *dispatch_timer_source_aggregate_refs_t;
148
149#define _dispatch_ptr2wref(ptr) (~(uintptr_t)(ptr))
150#define _dispatch_wref2ptr(ref) ((void*)~(ref))
151#define _dispatch_source_from_refs(dr) \
152		((dispatch_source_t)_dispatch_wref2ptr((dr)->dr_source_wref))
153#define ds_timer(dr) \
154		(((dispatch_timer_source_refs_t)(dr))->_ds_timer)
155#define ds_timer_aggregate(ds) \
156		((dispatch_timer_aggregate_t)((ds)->dq_specific_q))
157
158DISPATCH_ALWAYS_INLINE
159static inline unsigned int
160_dispatch_source_timer_idx(dispatch_source_refs_t dr)
161{
162	return DISPATCH_TIMER_IDENT(ds_timer(dr).flags);
163}
164
165// ds_atomic_flags bits
166#define DSF_CANCELED 1u // cancellation has been requested
167#define DSF_ARMED 2u // source is armed
168
169#define DISPATCH_SOURCE_HEADER(refs) \
170	dispatch_kevent_t ds_dkev; \
171	dispatch_##refs##_refs_t ds_refs; \
172	unsigned int ds_atomic_flags; \
173	unsigned int \
174		ds_is_level:1, \
175		ds_is_adder:1, \
176		ds_is_installed:1, \
177		ds_needs_rearm:1, \
178		ds_is_timer:1, \
179		ds_cancel_is_block:1, \
180		ds_handler_is_block:1, \
181		ds_registration_is_block:1, \
182		dm_connect_handler_called:1, \
183		dm_cancel_handler_called:1; \
184	unsigned long ds_pending_data_mask;
185
186DISPATCH_CLASS_DECL(source);
187struct dispatch_source_s {
188	DISPATCH_STRUCT_HEADER(source);
189	DISPATCH_QUEUE_HEADER;
190	DISPATCH_SOURCE_HEADER(source);
191	unsigned long ds_ident_hack;
192	unsigned long ds_data;
193	unsigned long ds_pending_data;
194};
195
196// Mach channel state which may contain references to the channel object
197// layout must match dispatch_source_refs_s
198struct dispatch_mach_refs_s {
199	TAILQ_ENTRY(dispatch_mach_refs_s) dr_list;
200	uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t
201	dispatch_mach_handler_function_t dm_handler_func;
202	void *dm_handler_ctxt;
203};
204typedef struct dispatch_mach_refs_s *dispatch_mach_refs_t;
205
206struct dispatch_mach_reply_refs_s {
207	TAILQ_ENTRY(dispatch_mach_reply_refs_s) dr_list;
208	uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t
209	dispatch_kevent_t dm_dkev;
210	TAILQ_ENTRY(dispatch_mach_reply_refs_s) dm_list;
211};
212typedef struct dispatch_mach_reply_refs_s *dispatch_mach_reply_refs_t;
213
214struct dispatch_mach_send_refs_s {
215	TAILQ_ENTRY(dispatch_mach_send_refs_s) dr_list;
216	uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t
217	dispatch_mach_msg_t dm_checkin;
218	TAILQ_HEAD(, dispatch_mach_reply_refs_s) dm_replies;
219	uint32_t volatile dm_disconnect_cnt;
220	uint32_t volatile dm_sending;
221	unsigned int dm_needs_mgr:1;
222	struct dispatch_object_s *volatile dm_tail;
223	struct dispatch_object_s *volatile dm_head;
224	mach_port_t dm_send, dm_checkin_port;
225};
226typedef struct dispatch_mach_send_refs_s *dispatch_mach_send_refs_t;
227
228DISPATCH_CLASS_DECL(mach);
229struct dispatch_mach_s {
230	DISPATCH_STRUCT_HEADER(mach);
231	DISPATCH_QUEUE_HEADER;
232	DISPATCH_SOURCE_HEADER(mach);
233	dispatch_kevent_t dm_dkev;
234	dispatch_mach_send_refs_t dm_refs;
235};
236
237DISPATCH_CLASS_DECL(mach_msg);
238struct dispatch_mach_msg_s {
239	DISPATCH_STRUCT_HEADER(mach_msg);
240	dispatch_mach_msg_destructor_t destructor;
241	size_t size;
242	union {
243		mach_msg_header_t *msg;
244		char buf[0];
245	};
246};
247
248#if TARGET_OS_EMBEDDED
249#define DSL_HASH_SIZE  64u // must be a power of two
250#else
251#define DSL_HASH_SIZE 256u // must be a power of two
252#endif
253
254void _dispatch_source_xref_dispose(dispatch_source_t ds);
255void _dispatch_source_dispose(dispatch_source_t ds);
256void _dispatch_source_invoke(dispatch_source_t ds);
257unsigned long _dispatch_source_probe(dispatch_source_t ds);
258size_t _dispatch_source_debug(dispatch_source_t ds, char* buf, size_t bufsiz);
259void _dispatch_source_set_interval(dispatch_source_t ds, uint64_t interval);
260
261void _dispatch_mach_dispose(dispatch_mach_t dm);
262void _dispatch_mach_invoke(dispatch_mach_t dm);
263unsigned long _dispatch_mach_probe(dispatch_mach_t dm);
264size_t _dispatch_mach_debug(dispatch_mach_t dm, char* buf, size_t bufsiz);
265
266void _dispatch_mach_msg_dispose(dispatch_mach_msg_t dmsg);
267void _dispatch_mach_msg_invoke(dispatch_mach_msg_t dmsg);
268size_t _dispatch_mach_msg_debug(dispatch_mach_msg_t dmsg, char* buf, size_t bufsiz);
269
270void _dispatch_mach_barrier_invoke(void *ctxt);
271
272unsigned long _dispatch_mgr_wakeup(dispatch_queue_t dq);
273void _dispatch_mgr_thread(dispatch_queue_t dq);
274
275#endif /* __DISPATCH_SOURCE_INTERNAL__ */
276