X-Git-Url: https://git.saurik.com/apple/libdispatch.git/blobdiff_plain/98cf8cd208104c07d83445c24626e57ca11b5775..refs/heads/master:/src/source_internal.h diff --git a/src/source_internal.h b/src/source_internal.h index 12ccdda..55b81e7 100644 --- a/src/source_internal.h +++ b/src/source_internal.h @@ -32,255 +32,100 @@ #include // for HeaderDoc #endif -#define DISPATCH_EVFILT_TIMER (-EVFILT_SYSCOUNT - 1) -#define DISPATCH_EVFILT_CUSTOM_ADD (-EVFILT_SYSCOUNT - 2) -#define DISPATCH_EVFILT_CUSTOM_OR (-EVFILT_SYSCOUNT - 3) -#define DISPATCH_EVFILT_MACH_NOTIFICATION (-EVFILT_SYSCOUNT - 4) -#define DISPATCH_EVFILT_SYSCOUNT ( EVFILT_SYSCOUNT + 4) - -// NOTE: dispatch_source_mach_send_flags_t and dispatch_source_mach_recv_flags_t -// bit values must not overlap as they share the same kevent fflags ! - -/*! - * @enum dispatch_source_mach_send_flags_t - * - * @constant DISPATCH_MACH_SEND_DELETED - * Port-deleted notification. Disabled for source registration. - */ -enum { - DISPATCH_MACH_SEND_DELETED = 0x4, -}; -/*! - * @enum dispatch_source_mach_recv_flags_t - * - * @constant DISPATCH_MACH_RECV_MESSAGE - * Receive right has pending messages - * - * @constant DISPATCH_MACH_RECV_MESSAGE_DIRECT - * Receive messages from receive right directly via kevent64() - * - * @constant DISPATCH_MACH_RECV_NO_SENDERS - * Receive right has no more senders. TODO - */ -enum { - DISPATCH_MACH_RECV_MESSAGE = 0x2, - DISPATCH_MACH_RECV_MESSAGE_DIRECT = 0x10, - DISPATCH_MACH_RECV_MESSAGE_DIRECT_ONCE = 0x20, - DISPATCH_MACH_RECV_NO_SENDERS = 0x40, -}; - enum { - DISPATCH_TIMER_WALL_CLOCK = 0x4, + /* DISPATCH_TIMER_STRICT 0x1 */ + /* DISPATCH_TIMER_BACKGROUND = 0x2, */ + DISPATCH_TIMER_CLOCK_MACH = 0x4, DISPATCH_TIMER_INTERVAL = 0x8, - DISPATCH_TIMER_WITH_AGGREGATE = 0x10, -}; - -// low bits are timer QoS class -#define DISPATCH_TIMER_QOS_NORMAL 0u -#define DISPATCH_TIMER_QOS_CRITICAL 1u -#define DISPATCH_TIMER_QOS_BACKGROUND 2u -#define DISPATCH_TIMER_QOS_COUNT (DISPATCH_TIMER_QOS_BACKGROUND + 1) -#define DISPATCH_TIMER_QOS(tidx) ((uintptr_t)(tidx) & 0x3ul) - -#define DISPATCH_TIMER_KIND_WALL 0u -#define DISPATCH_TIMER_KIND_MACH 1u -#define DISPATCH_TIMER_KIND_COUNT (DISPATCH_TIMER_KIND_MACH + 1) -#define DISPATCH_TIMER_KIND(tidx) (((uintptr_t)(tidx) >> 2) & 0x1ul) - -#define DISPATCH_TIMER_INDEX(kind, qos) (((kind) << 2) | (qos)) -#define DISPATCH_TIMER_INDEX_DISARM \ - DISPATCH_TIMER_INDEX(DISPATCH_TIMER_KIND_COUNT, 0) -#define DISPATCH_TIMER_INDEX_COUNT (DISPATCH_TIMER_INDEX_DISARM + 1) -#define DISPATCH_TIMER_IDENT(flags) ({ unsigned long f = (flags); \ - DISPATCH_TIMER_INDEX(f & DISPATCH_TIMER_WALL_CLOCK ? \ - DISPATCH_TIMER_KIND_WALL : DISPATCH_TIMER_KIND_MACH, \ - f & DISPATCH_TIMER_STRICT ? DISPATCH_TIMER_QOS_CRITICAL : \ - f & DISPATCH_TIMER_BACKGROUND ? DISPATCH_TIMER_QOS_BACKGROUND : \ - DISPATCH_TIMER_QOS_NORMAL); }) - -struct dispatch_kevent_s { - TAILQ_ENTRY(dispatch_kevent_s) dk_list; - TAILQ_HEAD(, dispatch_source_refs_s) dk_sources; - struct kevent64_s dk_kevent; + DISPATCH_TIMER_AFTER = 0x10, + /* DISPATCH_INTERVAL_UI_ANIMATION = 0x20 */ }; -typedef struct dispatch_kevent_s *dispatch_kevent_t; - -struct dispatch_source_type_s { - struct kevent64_s ke; - uint64_t mask; - void (*init)(dispatch_source_t ds, dispatch_source_type_t type, - uintptr_t handle, unsigned long mask, dispatch_queue_t q); -}; - -struct dispatch_timer_source_s { - uint64_t target; - uint64_t deadline; - uint64_t last_fire; - uint64_t interval; - uint64_t leeway; - unsigned long flags; // dispatch_timer_flags_t - unsigned long missed; -}; - -enum { - DS_EVENT_HANDLER = 0, - DS_CANCEL_HANDLER, - DS_REGISTN_HANDLER, -}; - -// Source state which may contain references to the source object -// Separately allocated so that 'leaks' can see sources -typedef struct dispatch_source_refs_s { - TAILQ_ENTRY(dispatch_source_refs_s) dr_list; - uintptr_t dr_source_wref; // "weak" backref to dispatch_source_t - dispatch_continuation_t ds_handler[3]; -} *dispatch_source_refs_t; - -typedef struct dispatch_timer_source_refs_s { - struct dispatch_source_refs_s _ds_refs; - struct dispatch_timer_source_s _ds_timer; - TAILQ_ENTRY(dispatch_timer_source_refs_s) dt_list; -} *dispatch_timer_source_refs_t; - -typedef struct dispatch_timer_source_aggregate_refs_s { - struct dispatch_timer_source_refs_s _dsa_refs; - TAILQ_ENTRY(dispatch_timer_source_aggregate_refs_s) dra_list; - TAILQ_ENTRY(dispatch_timer_source_aggregate_refs_s) dta_list; -} *dispatch_timer_source_aggregate_refs_t; - -#define _dispatch_ptr2wref(ptr) (~(uintptr_t)(ptr)) -#define _dispatch_wref2ptr(ref) ((void*)~(ref)) -#define _dispatch_source_from_refs(dr) \ - ((dispatch_source_t)_dispatch_wref2ptr((dr)->dr_source_wref)) -#define ds_timer(dr) \ - (((dispatch_timer_source_refs_t)(dr))->_ds_timer) -#define ds_timer_aggregate(ds) \ - ((dispatch_timer_aggregate_t)((ds)->dq_specific_q)) - DISPATCH_ALWAYS_INLINE static inline unsigned int -_dispatch_source_timer_idx(dispatch_source_refs_t dr) +_dispatch_source_timer_idx(dispatch_unote_t du) { - return DISPATCH_TIMER_IDENT(ds_timer(dr).flags); -} + uint32_t clock, qos = 0, fflags = du._dt->du_fflags; + + dispatch_assert(DISPATCH_CLOCK_MACH == 1); + dispatch_assert(DISPATCH_CLOCK_WALL == 0); + clock = (fflags & DISPATCH_TIMER_CLOCK_MACH) / DISPATCH_TIMER_CLOCK_MACH; + +#if DISPATCH_HAVE_TIMER_QOS + dispatch_assert(DISPATCH_TIMER_STRICT == DISPATCH_TIMER_QOS_CRITICAL); + dispatch_assert(DISPATCH_TIMER_BACKGROUND == DISPATCH_TIMER_QOS_BACKGROUND); + qos = fflags & (DISPATCH_TIMER_STRICT | DISPATCH_TIMER_BACKGROUND); + // flags are normalized so this should never happen + dispatch_assert(qos < DISPATCH_TIMER_QOS_COUNT); +#endif -// ds_atomic_flags bits -#define DSF_CANCELED 1u // cancellation has been requested -#define DSF_ARMED 2u // source is armed + return DISPATCH_TIMER_INDEX(clock, qos); +} -#define DISPATCH_SOURCE_HEADER(refs) \ - dispatch_kevent_t ds_dkev; \ - dispatch_##refs##_refs_t ds_refs; \ - unsigned int ds_atomic_flags; \ +#define _DISPATCH_SOURCE_HEADER(refs) \ + DISPATCH_QUEUE_HEADER(refs); \ unsigned int \ - ds_is_level:1, \ - ds_is_adder:1, \ ds_is_installed:1, \ - ds_needs_rearm:1, \ - ds_is_timer:1, \ - ds_vmpressure_override:1, \ - ds_memorystatus_override:1, \ - dm_handler_is_block:1, \ + dm_needs_mgr:1, \ dm_connect_handler_called:1, \ - dm_cancel_handler_called:1; \ - unsigned long ds_pending_data_mask; + dm_uninstalled:1, \ + dm_cancel_handler_called:1, \ + dm_is_xpc:1 -DISPATCH_CLASS_DECL(source); -struct dispatch_source_s { - DISPATCH_STRUCT_HEADER(source); - DISPATCH_QUEUE_HEADER; - DISPATCH_SOURCE_HEADER(source); - unsigned long ds_ident_hack; - unsigned long ds_data; - unsigned long ds_pending_data; -}; +#define DISPATCH_SOURCE_HEADER(refs) \ + struct dispatch_source_s _as_ds[0]; \ + _DISPATCH_SOURCE_HEADER(refs) -// Mach channel state which may contain references to the channel object -// layout must match dispatch_source_refs_s -struct dispatch_mach_refs_s { - TAILQ_ENTRY(dispatch_mach_refs_s) dr_list; - uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t - dispatch_mach_handler_function_t dm_handler_func; - void *dm_handler_ctxt; -}; -typedef struct dispatch_mach_refs_s *dispatch_mach_refs_t; +DISPATCH_CLASS_DECL_BARE(source); +_OS_OBJECT_CLASS_IMPLEMENTS_PROTOCOL(dispatch_source, dispatch_object); -struct dispatch_mach_reply_refs_s { - TAILQ_ENTRY(dispatch_mach_reply_refs_s) dr_list; - uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t - dispatch_kevent_t dmr_dkev; - void *dmr_ctxt; - pthread_priority_t dmr_priority; - voucher_t dmr_voucher; - TAILQ_ENTRY(dispatch_mach_reply_refs_s) dmr_list; -}; -typedef struct dispatch_mach_reply_refs_s *dispatch_mach_reply_refs_t; +#ifndef __cplusplus +struct dispatch_source_s { + _DISPATCH_SOURCE_HEADER(source); + uint64_t ds_data DISPATCH_ATOMIC64_ALIGN; + uint64_t ds_pending_data DISPATCH_ATOMIC64_ALIGN; +} DISPATCH_ATOMIC64_ALIGN; -struct dispatch_mach_send_refs_s { - TAILQ_ENTRY(dispatch_mach_send_refs_s) dr_list; - uintptr_t dr_source_wref; // "weak" backref to dispatch_mach_t - dispatch_mach_msg_t dm_checkin; - TAILQ_HEAD(, dispatch_mach_reply_refs_s) dm_replies; - uint32_t volatile dm_disconnect_cnt; - uint32_t volatile dm_sending; - unsigned int dm_needs_mgr:1; - struct dispatch_object_s *volatile dm_tail; - struct dispatch_object_s *volatile dm_head; - mach_port_t dm_send, dm_checkin_port; -}; -typedef struct dispatch_mach_send_refs_s *dispatch_mach_send_refs_t; +// Extracts source data from the ds_data field +#define DISPATCH_SOURCE_GET_DATA(d) ((d) & 0xFFFFFFFF) -DISPATCH_CLASS_DECL(mach); -struct dispatch_mach_s { - DISPATCH_STRUCT_HEADER(mach); - DISPATCH_QUEUE_HEADER; - DISPATCH_SOURCE_HEADER(mach); - dispatch_kevent_t dm_dkev; - dispatch_mach_send_refs_t dm_refs; -}; +// Extracts status from the ds_data field +#define DISPATCH_SOURCE_GET_STATUS(d) ((d) >> 32) -DISPATCH_CLASS_DECL(mach_msg); -struct dispatch_mach_msg_s { - DISPATCH_STRUCT_HEADER(mach_msg); - mach_port_t dmsg_reply; - pthread_priority_t dmsg_priority; - voucher_t dmsg_voucher; - dispatch_mach_msg_destructor_t dmsg_destructor; - size_t dmsg_size; - union { - mach_msg_header_t *dmsg_msg; - char dmsg_buf[0]; - }; -}; +// Combine data and status for the ds_data field +#define DISPATCH_SOURCE_COMBINE_DATA_AND_STATUS(data, status) \ + ((((uint64_t)(status)) << 32) | (data)) -#if TARGET_OS_EMBEDDED -#define DSL_HASH_SIZE 64u // must be a power of two -#else -#define DSL_HASH_SIZE 256u // must be a power of two -#endif +#endif // __cplusplus +void _dispatch_source_refs_register(dispatch_source_t ds, + dispatch_wlh_t wlh, dispatch_priority_t bp); +void _dispatch_source_refs_unregister(dispatch_source_t ds, uint32_t options); void _dispatch_source_xref_dispose(dispatch_source_t ds); -void _dispatch_source_dispose(dispatch_source_t ds); -void _dispatch_source_invoke(dispatch_source_t ds); -unsigned long _dispatch_source_probe(dispatch_source_t ds); +void _dispatch_source_dispose(dispatch_source_t ds, bool *allow_free); +void _dispatch_source_finalize_activation(dispatch_source_t ds, + bool *allow_resume); +void _dispatch_source_invoke(dispatch_source_t ds, + dispatch_invoke_context_t dic, dispatch_invoke_flags_t flags); +void _dispatch_source_wakeup(dispatch_source_t ds, dispatch_qos_t qos, + dispatch_wakeup_flags_t flags); +void _dispatch_source_merge_evt(dispatch_unote_t du, uint32_t flags, + uintptr_t data, uintptr_t status, pthread_priority_t pp); size_t _dispatch_source_debug(dispatch_source_t ds, char* buf, size_t bufsiz); -void _dispatch_source_set_interval(dispatch_source_t ds, uint64_t interval); -void _dispatch_source_set_event_handler_with_context_f(dispatch_source_t ds, - void *ctxt, dispatch_function_t handler); - -void _dispatch_mach_dispose(dispatch_mach_t dm); -void _dispatch_mach_invoke(dispatch_mach_t dm); -unsigned long _dispatch_mach_probe(dispatch_mach_t dm); -size_t _dispatch_mach_debug(dispatch_mach_t dm, char* buf, size_t bufsiz); - -void _dispatch_mach_msg_dispose(dispatch_mach_msg_t dmsg); -void _dispatch_mach_msg_invoke(dispatch_mach_msg_t dmsg); -size_t _dispatch_mach_msg_debug(dispatch_mach_msg_t dmsg, char* buf, size_t bufsiz); - -void _dispatch_mach_barrier_invoke(void *ctxt); -unsigned long _dispatch_mgr_wakeup(dispatch_queue_t dq); -void _dispatch_mgr_thread(dispatch_queue_t dq); +DISPATCH_EXPORT // for firehose server +void _dispatch_source_merge_data(dispatch_source_t ds, pthread_priority_t pp, + unsigned long val); + +void _dispatch_mgr_queue_push(dispatch_queue_t dq, dispatch_object_t dou, + dispatch_qos_t qos); +void _dispatch_mgr_queue_wakeup(dispatch_queue_t dq, dispatch_qos_t qos, + dispatch_wakeup_flags_t flags); +void _dispatch_mgr_thread(dispatch_queue_t dq, dispatch_invoke_context_t dic, + dispatch_invoke_flags_t flags); +#if DISPATCH_USE_KEVENT_WORKQUEUE +void _dispatch_kevent_worker_thread(dispatch_kevent_t *events, + int *nevents); +#endif // DISPATCH_USE_KEVENT_WORKQUEUE #endif /* __DISPATCH_SOURCE_INTERNAL__ */