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