/*
- * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
*
* @APPLE_APACHE_LICENSE_HEADER_START@
*
#include <dispatch/base.h> // for HeaderDoc
#endif
-// 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_NO_SENDERS
- * Receive right has no more senders. TODO <rdar://problem/8132399>
- */
-enum {
- DISPATCH_MACH_RECV_MESSAGE = 0x2,
- DISPATCH_MACH_RECV_NO_SENDERS = 0x10,
-};
-
enum {
- DISPATCH_TIMER_WALL_CLOCK = 0x4,
-};
-
-#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_SYSCOUNT ( EVFILT_SYSCOUNT + 3)
-
-#define DISPATCH_TIMER_INDEX_WALL 0
-#define DISPATCH_TIMER_INDEX_MACH 1
-#define DISPATCH_TIMER_INDEX_DISARM 2
-
-struct dispatch_source_vtable_s {
- DISPATCH_VTABLE_HEADER(dispatch_source_s);
-};
-
-extern const struct dispatch_source_vtable_s _dispatch_source_kevent_vtable;
-
-struct dispatch_kevent_s {
- TAILQ_ENTRY(dispatch_kevent_s) dk_list;
- TAILQ_HEAD(, dispatch_source_refs_s) dk_sources;
- struct kevent dk_kevent;
-};
-
-typedef struct dispatch_kevent_s *dispatch_kevent_t;
-
-struct dispatch_source_type_s {
- struct kevent 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);
+ /* DISPATCH_TIMER_STRICT 0x1 */
+ /* DISPATCH_TIMER_BACKGROUND = 0x2, */
+ DISPATCH_TIMER_CLOCK_MACH = 0x4,
+ DISPATCH_TIMER_INTERVAL = 0x8,
+ DISPATCH_TIMER_AFTER = 0x10,
+ /* DISPATCH_INTERVAL_UI_ANIMATION = 0x20 */
};
-struct dispatch_timer_source_s {
- uint64_t target;
- uint64_t last_fire;
- uint64_t interval;
- uint64_t leeway;
- uint64_t flags; // dispatch_timer_flags_t
- unsigned long missed;
-};
+DISPATCH_ALWAYS_INLINE
+static inline unsigned int
+_dispatch_source_timer_idx(dispatch_unote_t du)
+{
+ 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
-// Source state which may contain references to the source object
-// Separately allocated so that 'leaks' can see sources <rdar://problem/9050566>
-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_function_t ds_handler_func;
- void *ds_handler_ctxt;
- void *ds_cancel_handler;
- void *ds_registration_handler;
-};
+ return DISPATCH_TIMER_INDEX(clock, qos);
+}
-typedef struct dispatch_source_refs_s *dispatch_source_refs_t;
+#define _DISPATCH_SOURCE_HEADER(refs) \
+ DISPATCH_QUEUE_HEADER(refs); \
+ unsigned int \
+ ds_is_installed:1, \
+ dm_needs_mgr:1, \
+ dm_connect_handler_called:1, \
+ dm_uninstalled:1, \
+ dm_cancel_handler_called:1, \
+ dm_is_xpc:1
-struct dispatch_timer_source_refs_s {
- struct dispatch_source_refs_s _ds_refs;
- struct dispatch_timer_source_s _ds_timer;
-};
+#define DISPATCH_SOURCE_HEADER(refs) \
+ struct dispatch_source_s _as_ds[0]; \
+ _DISPATCH_SOURCE_HEADER(refs)
-#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) \
- (((struct dispatch_timer_source_refs_s *)(dr))->_ds_timer)
-
-// ds_atomic_flags bits
-#define DSF_CANCELED 1u // cancellation has been requested
-#define DSF_ARMED 2u // source is armed
+DISPATCH_CLASS_DECL_BARE(source);
+_OS_OBJECT_CLASS_IMPLEMENTS_PROTOCOL(dispatch_source, dispatch_object);
+#ifndef __cplusplus
struct dispatch_source_s {
- DISPATCH_STRUCT_HEADER(dispatch_source_s, dispatch_source_vtable_s);
- DISPATCH_QUEUE_HEADER;
- // Instruments always copies DISPATCH_QUEUE_MIN_LABEL_SIZE, which is 64,
- // so the remainder of the structure must be big enough
- union {
- char _ds_pad[DISPATCH_QUEUE_MIN_LABEL_SIZE];
- struct {
- char dq_label[8];
- dispatch_kevent_t ds_dkev;
- dispatch_source_refs_t ds_refs;
- unsigned int ds_atomic_flags;
- unsigned int
- ds_is_level:1,
- ds_is_adder:1,
- ds_is_installed:1,
- ds_needs_rearm:1,
- ds_is_timer:1,
- ds_cancel_is_block:1,
- ds_handler_is_block:1,
- ds_registration_is_block:1;
- unsigned long ds_data;
- unsigned long ds_pending_data;
- unsigned long ds_pending_data_mask;
- unsigned long ds_ident_hack;
- };
- };
-};
-
-void _dispatch_source_xref_release(dispatch_source_t ds);
-void _dispatch_mach_notify_source_init(void *context);
+ _DISPATCH_SOURCE_HEADER(source);
+ uint64_t ds_data DISPATCH_ATOMIC64_ALIGN;
+ uint64_t ds_pending_data DISPATCH_ATOMIC64_ALIGN;
+} DISPATCH_ATOMIC64_ALIGN;
+
+// Extracts source data from the ds_data field
+#define DISPATCH_SOURCE_GET_DATA(d) ((d) & 0xFFFFFFFF)
+
+// Extracts status from the ds_data field
+#define DISPATCH_SOURCE_GET_STATUS(d) ((d) >> 32)
+
+// Combine data and status for the ds_data field
+#define DISPATCH_SOURCE_COMBINE_DATA_AND_STATUS(data, status) \
+ ((((uint64_t)(status)) << 32) | (data))
+
+#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, 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);
+
+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__ */