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 126enum { 127 DS_EVENT_HANDLER = 0, 128 DS_CANCEL_HANDLER, 129 DS_REGISTN_HANDLER, 130}; 131 132// Source state which may contain references to the source object 133// Separately allocated so that 'leaks' can see sources <rdar://problem/9050566> 134typedef struct dispatch_source_refs_s { 135 TAILQ_ENTRY(dispatch_source_refs_s) dr_list; 136 uintptr_t dr_source_wref; // "weak" backref to dispatch_source_t 137 dispatch_continuation_t ds_handler[3]; 138} *dispatch_source_refs_t; 139 140typedef struct dispatch_timer_source_refs_s { 141 struct dispatch_source_refs_s _ds_refs; 142 struct dispatch_timer_source_s _ds_timer; 143 TAILQ_ENTRY(dispatch_timer_source_refs_s) dt_list; 144} *dispatch_timer_source_refs_t; 145 146typedef struct dispatch_timer_source_aggregate_refs_s { 147 struct dispatch_timer_source_refs_s _dsa_refs; 148 TAILQ_ENTRY(dispatch_timer_source_aggregate_refs_s) dra_list; 149 TAILQ_ENTRY(dispatch_timer_source_aggregate_refs_s) dta_list; 150} *dispatch_timer_source_aggregate_refs_t; 151 152#define _dispatch_ptr2wref(ptr) (~(uintptr_t)(ptr)) 153#define _dispatch_wref2ptr(ref) ((void*)~(ref)) 154#define _dispatch_source_from_refs(dr) \ 155 ((dispatch_source_t)_dispatch_wref2ptr((dr)->dr_source_wref)) 156#define ds_timer(dr) \ 157 (((dispatch_timer_source_refs_t)(dr))->_ds_timer) 158#define ds_timer_aggregate(ds) \ 159 ((dispatch_timer_aggregate_t)((ds)->dq_specific_q)) 160 161DISPATCH_ALWAYS_INLINE 162static inline unsigned int 163_dispatch_source_timer_idx(dispatch_source_refs_t dr) 164{ 165 return DISPATCH_TIMER_IDENT(ds_timer(dr).flags); 166} 167 168// ds_atomic_flags bits 169#define DSF_CANCELED 1u // cancellation has been requested 170#define DSF_ARMED 2u // source is armed 171 172#define DISPATCH_SOURCE_HEADER(refs) \ 173 dispatch_kevent_t ds_dkev; \ 174 dispatch_##refs##_refs_t ds_refs; \ 175 unsigned int ds_atomic_flags; \ 176 unsigned int \ 177 ds_is_level:1, \ 178 ds_is_adder:1, \ 179 ds_is_installed:1, \ 180 ds_needs_rearm:1, \ 181 ds_is_timer:1, \ 182 ds_vmpressure_override:1, \ 183 ds_memorystatus_override:1, \ 184 dm_handler_is_block:1, \ 185 dm_connect_handler_called:1, \ 186 dm_cancel_handler_called:1; \ 187 unsigned long ds_pending_data_mask; 188 189DISPATCH_CLASS_DECL(source); 190struct dispatch_source_s { 191 DISPATCH_STRUCT_HEADER(source); 192 DISPATCH_QUEUE_HEADER; 193 DISPATCH_SOURCE_HEADER(source); 194 unsigned long ds_ident_hack; 195 unsigned long ds_data; 196 unsigned long ds_pending_data; 197}; 198 199// Mach channel state which may contain references to the channel object 200// layout must match dispatch_source_refs_s 201struct dispatch_mach_refs_s { 202 TAILQ_ENTRY(dispatch_mach_refs_s) dr_list; 203 uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t 204 dispatch_mach_handler_function_t dm_handler_func; 205 void *dm_handler_ctxt; 206}; 207typedef struct dispatch_mach_refs_s *dispatch_mach_refs_t; 208 209struct dispatch_mach_reply_refs_s { 210 TAILQ_ENTRY(dispatch_mach_reply_refs_s) dr_list; 211 uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t 212 dispatch_kevent_t dmr_dkev; 213 void *dmr_ctxt; 214 pthread_priority_t dmr_priority; 215 voucher_t dmr_voucher; 216 TAILQ_ENTRY(dispatch_mach_reply_refs_s) dmr_list; 217}; 218typedef struct dispatch_mach_reply_refs_s *dispatch_mach_reply_refs_t; 219 220struct dispatch_mach_send_refs_s { 221 TAILQ_ENTRY(dispatch_mach_send_refs_s) dr_list; 222 uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t 223 dispatch_mach_msg_t dm_checkin; 224 TAILQ_HEAD(, dispatch_mach_reply_refs_s) dm_replies; 225 uint32_t volatile dm_disconnect_cnt; 226 uint32_t volatile dm_sending; 227 unsigned int dm_needs_mgr:1; 228 struct dispatch_object_s *volatile dm_tail; 229 struct dispatch_object_s *volatile dm_head; 230 mach_port_t dm_send, dm_checkin_port; 231}; 232typedef struct dispatch_mach_send_refs_s *dispatch_mach_send_refs_t; 233 234DISPATCH_CLASS_DECL(mach); 235struct dispatch_mach_s { 236 DISPATCH_STRUCT_HEADER(mach); 237 DISPATCH_QUEUE_HEADER; 238 DISPATCH_SOURCE_HEADER(mach); 239 dispatch_kevent_t dm_dkev; 240 dispatch_mach_send_refs_t dm_refs; 241}; 242 243DISPATCH_CLASS_DECL(mach_msg); 244struct dispatch_mach_msg_s { 245 DISPATCH_STRUCT_HEADER(mach_msg); 246 mach_port_t dmsg_reply; 247 pthread_priority_t dmsg_priority; 248 voucher_t dmsg_voucher; 249 dispatch_mach_msg_destructor_t dmsg_destructor; 250 size_t dmsg_size; 251 union { 252 mach_msg_header_t *dmsg_msg; 253 char dmsg_buf[0]; 254 }; 255}; 256 257#if TARGET_OS_EMBEDDED 258#define DSL_HASH_SIZE 64u // must be a power of two 259#else 260#define DSL_HASH_SIZE 256u // must be a power of two 261#endif 262 263void _dispatch_source_xref_dispose(dispatch_source_t ds); 264void _dispatch_source_dispose(dispatch_source_t ds); 265void _dispatch_source_invoke(dispatch_source_t ds); 266unsigned long _dispatch_source_probe(dispatch_source_t ds); 267size_t _dispatch_source_debug(dispatch_source_t ds, char* buf, size_t bufsiz); 268void _dispatch_source_set_interval(dispatch_source_t ds, uint64_t interval); 269void _dispatch_source_set_event_handler_with_context_f(dispatch_source_t ds, 270 void *ctxt, dispatch_function_t handler); 271 272void _dispatch_mach_dispose(dispatch_mach_t dm); 273void _dispatch_mach_invoke(dispatch_mach_t dm); 274unsigned long _dispatch_mach_probe(dispatch_mach_t dm); 275size_t _dispatch_mach_debug(dispatch_mach_t dm, char* buf, size_t bufsiz); 276 277void _dispatch_mach_msg_dispose(dispatch_mach_msg_t dmsg); 278void _dispatch_mach_msg_invoke(dispatch_mach_msg_t dmsg); 279size_t _dispatch_mach_msg_debug(dispatch_mach_msg_t dmsg, char* buf, size_t bufsiz); 280 281void _dispatch_mach_barrier_invoke(void *ctxt); 282 283unsigned long _dispatch_mgr_wakeup(dispatch_queue_t dq); 284void _dispatch_mgr_thread(dispatch_queue_t dq); 285 286#endif /* __DISPATCH_SOURCE_INTERNAL__ */ 287