From 4d5eff0e0269ba45028c81d79a199adcda7558e3 Mon Sep 17 00:00:00 2001 From: David Grove Date: Wed, 15 Jun 2016 10:16:37 -0400 Subject: [PATCH 01/67] Linux port of libdispatch-685 merge Minimal set of changes to get sources merged from libdispatch-685 to compile and run on Linux. Signed-off-by: Daniel A. Steffen --- dispatch/dispatch.h | 31 ++++++++ os/linux_base.h | 128 +++++++++++-------------------- os/voucher_private.h | 2 +- src/firehose/firehose_internal.h | 4 + src/init.c | 4 + src/inline_internal.h | 20 ++--- src/internal.h | 16 +++- src/object.c | 2 +- src/object_internal.h | 2 +- src/queue.c | 30 ++++++-- src/shims.h | 8 +- src/shims/linux_stubs.h | 83 +++++++++++++++++++- src/shims/lock.c | 35 +++++---- src/shims/lock.h | 19 ++++- src/source.c | 12 ++- src/voucher_internal.h | 5 +- 16 files changed, 271 insertions(+), 130 deletions(-) diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index 8d854412c..349dd5983 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -41,6 +41,37 @@ #ifndef __OSX_AVAILABLE_STARTING #define __OSX_AVAILABLE_STARTING(x, y) #endif +#ifndef __OSX_AVAILABLE_BUT_DEPRECATED +#define __OSX_AVAILABLE_BUT_DEPRECATED(...) +#endif +#ifndef __OSX_AVAILABLE_BUT_DEPRECATED_MSG +#define __OSX_AVAILABLE_BUT_DEPRECATED_MSG(...) +#endif + +#ifndef __OSX_AVAILABLE +#define __OSX_AVAILABLE(...) +#endif +#ifndef __IOS_AVAILABLE +#define __IOS_AVAILABLE(...) +#endif +#ifndef __TVOS_AVAILABLE +#define __TVOS_AVAILABLE(...) +#endif +#ifndef __WATCHOS_AVAILABLE +#define __WATCHOS_AVAILABLE(...) +#endif +#ifndef __OSX_DEPRECATED +#define __OSX_DEPRECATED(...) +#endif +#ifndef __IOS_DEPRECATED +#define __IOS_DEPRECATED(...) +#endif +#ifndef __TVOS_DEPRECATED +#define __TVOS_DEPRECATED(...) +#endif +#ifndef __WATCHOS_DEPRECATED +#define __WATCHOS_DEPRECATED(...) +#endif #define DISPATCH_API_VERSION 20160612 diff --git a/os/linux_base.h b/os/linux_base.h index 3d54fa29a..96a3c825b 100644 --- a/os/linux_base.h +++ b/os/linux_base.h @@ -13,92 +13,60 @@ #ifndef __OS_LINUX_BASE__ #define __OS_LINUX_BASE__ -// #include #include +#include -// marker for hacks we have made to make progress -#define __LINUX_PORT_HDD__ 1 - -/* - * Stub out defines for some mach types and related macros - */ - -typedef uint32_t mach_port_t; - -#define MACH_PORT_NULL (0) -#define MACH_PORT_DEAD (-1) - -#define EVFILT_MACHPORT (-8) - -typedef uint32_t mach_error_t; - -typedef uint32_t mach_vm_size_t; - -typedef uint32_t mach_msg_return_t; - -typedef uintptr_t mach_vm_address_t; - -typedef uint32_t dispatch_mach_msg_t; - -typedef uint32_t dispatch_mach_t; - -typedef uint32_t dispatch_mach_reason_t; - -typedef uint32_t voucher_activity_mode_t; - -typedef uint32_t voucher_activity_trace_id_t; - -typedef uint32_t voucher_activity_id_t; - -typedef uint32_t _voucher_activity_buffer_hook_t;; - -typedef uint32_t voucher_activity_flag_t; - -typedef struct -{ -} mach_msg_header_t; - - -typedef void (*dispatch_mach_handler_function_t)(void*, dispatch_mach_reason_t, - dispatch_mach_msg_t, mach_error_t); - -typedef void (*dispatch_mach_msg_destructor_t)(void*); - -// Print a warning when an unported code path executes. -#define LINUX_PORT_ERROR() do { printf("LINUX_PORT_ERROR_CALLED %s:%d: %s\n",__FILE__,__LINE__,__FUNCTION__); } while (0) - -/* - * Stub out defines for other missing types - */ - -#if __linux__ -// we fall back to use kevent -#define kevent64_s kevent -#define kevent64(kq,cl,nc,el,ne,f,to) kevent(kq,cl,nc,el,ne,to) +#if __GNUC__ +#define OS_EXPECT(x, v) __builtin_expect((x), (v)) +#else +#define OS_EXPECT(x, v) (x) #endif -// SIZE_T_MAX should not be hardcoded like this here. -#define SIZE_T_MAX (0x7fffffff) +#ifndef os_likely +#define os_likely(x) OS_EXPECT(!!(x), 1) +#endif +#ifndef os_unlikely +#define os_unlikely(x) OS_EXPECT(!!(x), 0) +#endif -// Define to 0 the NOTE_ values that are not present on Linux. -// Revisit this...would it be better to ifdef out the uses instead?? +#if __has_feature(assume_nonnull) +#define OS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin") +#define OS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end") +#else +#define OS_ASSUME_NONNULL_BEGIN +#define OS_ASSUME_NONNULL_END +#endif -// The following values are passed as part of the EVFILT_TIMER requests +#if __has_builtin(__builtin_assume) +#define OS_COMPILER_CAN_ASSUME(expr) __builtin_assume(expr) +#else +#define OS_COMPILER_CAN_ASSUME(expr) ((void)(expr)) +#endif -#define IGNORE_KEVENT64_EXT /* will force the kevent64_s.ext[] to not be used -> leeway ignored */ +#if __has_feature(attribute_availability_swift) +// equivalent to __SWIFT_UNAVAILABLE from Availability.h +#define OS_SWIFT_UNAVAILABLE(_msg) \ + __attribute__((__availability__(swift, unavailable, message=_msg))) +#else +#define OS_SWIFT_UNAVAILABLE(_msg) +#endif -#define NOTE_SECONDS 0x01 -#define NOTE_USECONDS 0x02 -#define NOTE_NSECONDS 0x04 -#define NOTE_ABSOLUTE 0x08 -#define NOTE_CRITICAL 0x10 -#define NOTE_BACKGROUND 0x20 -#define NOTE_LEEWAY 0x40 +#if __has_attribute(swift_private) +# define OS_REFINED_FOR_SWIFT __attribute__((__swift_private__)) +#else +# define OS_REFINED_FOR_SWIFT +#endif -// need to catch the following usage if it happens .. -// we simply return '0' as a value probably not correct +#if __has_attribute(swift_name) +# define OS_SWIFT_NAME(_name) __attribute__((__swift_name__(#_name))) +#else +# define OS_SWIFT_NAME(_name) +#endif -#define NOTE_VM_PRESSURE ({LINUX_PORT_ERROR(); 0;}) +#define __OS_STRINGIFY(s) #s +#define OS_STRINGIFY(s) __OS_STRINGIFY(s) +#define __OS_CONCAT(x, y) x ## y +#define OS_CONCAT(x, y) __OS_CONCAT(x, y) /* * Stub out misc linking and compilation attributes @@ -123,12 +91,4 @@ typedef void (*dispatch_mach_msg_destructor_t)(void*); #endif #define OS_NOTHROW - -// These and similar macros come from Availabilty.h on OS X -// Need a better way to do this long term. -#define __OSX_AVAILABLE_BUT_DEPRECATED(a,b,c,d) // -#define __OSX_AVAILABLE_BUT_DEPRECATED_MSG(a,b,c,d,msg) // - - - #endif /* __OS_LINUX_BASE__ */ diff --git a/os/voucher_private.h b/os/voucher_private.h index 3ecddfb40..9d97b885e 100644 --- a/os/voucher_private.h +++ b/os/voucher_private.h @@ -416,6 +416,7 @@ dispatch_queue_create_with_accounting_override_voucher( dispatch_queue_attr_t _Nullable attr, voucher_t _Nullable voucher); +#ifdef __APPLE__ /*! * @group Voucher Mach SPI * SPI intended for clients that need to interact with mach messages or mach @@ -444,7 +445,6 @@ OS_VOUCHER_EXPORT OS_OBJECT_RETURNS_RETAINED OS_WARN_RESULT OS_NOTHROW voucher_t _Nullable voucher_create_with_mach_msg(mach_msg_header_t *msg); -#ifdef __APPLE__ /*! * @group Voucher Persona SPI * SPI intended for clients that need to interact with personas. diff --git a/src/firehose/firehose_internal.h b/src/firehose/firehose_internal.h index 0f84b8efa..29d1ad240 100644 --- a/src/firehose/firehose_internal.h +++ b/src/firehose/firehose_internal.h @@ -21,6 +21,8 @@ #ifndef __FIREHOSE_INTERNAL__ #define __FIREHOSE_INTERNAL__ +#if OS_FIREHOSE_SPI + // make sure this is defined so that we get MIG_SERVER_DIED when a send once // notification is sent back because of a crashed server #ifndef __MigTypeCheck @@ -44,4 +46,6 @@ #endif #include "firehose_inline_internal.h" +#endif // OS_FIREHOSE_SPI + #endif // __FIREHOSE_INTERNAL__ diff --git a/src/init.c b/src/init.c index 29ae2398b..e204e7d10 100644 --- a/src/init.c +++ b/src/init.c @@ -486,6 +486,7 @@ const struct dispatch_continuation_vtable_s _dispatch_continuation_vtables[] = { DC_VTABLE_ENTRY(ASYNC_REDIRECT, .do_kind = "dc-redirect", .do_invoke = _dispatch_async_redirect_invoke), +#if HAVE_MACH DC_VTABLE_ENTRY(MACH_SEND_BARRRIER_DRAIN, .do_kind = "dc-mach-send-drain", .do_invoke = _dispatch_mach_send_barrier_drain_invoke), @@ -495,6 +496,7 @@ const struct dispatch_continuation_vtable_s _dispatch_continuation_vtables[] = { DC_VTABLE_ENTRY(MACH_RECV_BARRIER, .do_kind = "dc-mach-recv-barrier", .do_invoke = _dispatch_mach_barrier_invoke), +#endif #if HAVE_PTHREAD_WORKQUEUE_QOS DC_VTABLE_ENTRY(OVERRIDE_STEALING, .do_kind = "dc-override-stealing", @@ -1195,7 +1197,9 @@ dispatch_source_type_readwrite_init(dispatch_source_t ds, { ds->ds_is_level = true; // bypass kernel check for device kqueue support rdar://19004921 +#ifdef NOTE_LOWAT ds->ds_dkev->dk_kevent.fflags = NOTE_LOWAT; +#endif ds->ds_dkev->dk_kevent.data = 1; } diff --git a/src/inline_internal.h b/src/inline_internal.h index f7cc3371a..f4e44a183 100644 --- a/src/inline_internal.h +++ b/src/inline_internal.h @@ -977,7 +977,7 @@ _dispatch_queue_drain_try_lock(dispatch_queue_t dq, uint64_t pending_barrier_width = (dq->dq_width - 1) * DISPATCH_QUEUE_WIDTH_INTERVAL; uint64_t xor_owner_and_set_full_width = - _dispatch_thread_port() | DISPATCH_QUEUE_WIDTH_FULL_BIT; + _dispatch_tid_self() | DISPATCH_QUEUE_WIDTH_FULL_BIT; uint64_t clear_enqueued_bit, old_state, new_state; if (flags & DISPATCH_INVOKE_STEALING) { @@ -1041,7 +1041,7 @@ static inline bool _dispatch_queue_try_acquire_barrier_sync(dispatch_queue_t dq) { uint64_t value = DISPATCH_QUEUE_WIDTH_FULL_BIT | DISPATCH_QUEUE_IN_BARRIER; - value |= _dispatch_thread_port(); + value |= _dispatch_tid_self(); return os_atomic_cmpxchg2o(dq, dq_state, DISPATCH_QUEUE_STATE_INIT_VALUE(dq->dq_width), value, acquire); @@ -1577,7 +1577,7 @@ _dispatch_root_queue_identity_assume(struct _dispatch_identity_s *di, if (!pp) pp = di->old_pri; if ((pp & _PTHREAD_PRIORITY_QOS_CLASS_MASK) > (assumed_rq->dq_priority & _PTHREAD_PRIORITY_QOS_CLASS_MASK)) { - _dispatch_wqthread_override_start(_dispatch_thread_port(), pp); + _dispatch_wqthread_override_start(_dispatch_tid_self(), pp); // Ensure that the root queue sees that this thread was overridden. _dispatch_set_defaultpriority_override(); } @@ -1630,7 +1630,7 @@ _dispatch_queue_class_invoke(dispatch_object_t dou, drain_pending_barrier: if (overriding) { _dispatch_object_debug(dq, "stolen onto thread 0x%x, 0x%lx", - _dispatch_thread_port(), _dispatch_get_defaultpriority()); + _dispatch_tid_self(), _dispatch_get_defaultpriority()); _dispatch_root_queue_identity_assume(&di, 0, 0); } @@ -1640,7 +1640,7 @@ _dispatch_queue_class_invoke(dispatch_object_t dou, old_dp = _dispatch_set_defaultpriority(dq->dq_priority, &dp); op = dq->dq_override; if (op > (dp & _PTHREAD_PRIORITY_QOS_CLASS_MASK)) { - _dispatch_wqthread_override_start(_dispatch_thread_port(), op); + _dispatch_wqthread_override_start(_dispatch_tid_self(), op); // Ensure that the root queue sees that this thread was overridden. _dispatch_set_defaultpriority_override(); } @@ -1825,7 +1825,7 @@ _dispatch_queue_set_bound_thread(dispatch_queue_t dq) { // Tag thread-bound queues with the owning thread dispatch_assert(_dispatch_queue_is_thread_bound(dq)); - mach_port_t old_owner, self = _dispatch_thread_port(); + mach_port_t old_owner, self = _dispatch_tid_self(); uint64_t dq_state = os_atomic_or_orig2o(dq, dq_state, self, relaxed); if (unlikely(old_owner = _dq_state_drain_owner(dq_state))) { DISPATCH_INTERNAL_CRASH(old_owner, "Queue bound twice"); @@ -1888,7 +1888,7 @@ _dispatch_reset_defaultpriority(pthread_priority_t pp) pp |= old_pp & _PTHREAD_PRIORITY_OVERRIDE_FLAG; _dispatch_thread_setspecific(dispatch_defaultpriority_key, (void*)pp); #else - (void)priority; + (void)pp; #endif } @@ -1994,7 +1994,7 @@ _dispatch_priority_adopt(pthread_priority_t pp, unsigned long flags) return defaultpri; } #else - (void)priority; (void)flags; + (void)pp; (void)flags; return 0; #endif } @@ -2037,6 +2037,7 @@ static inline pthread_priority_t _dispatch_priority_compute_update(pthread_priority_t pp, _dispatch_thread_set_self_t flags) { +#if HAVE_PTHREAD_WORKQUEUE_QOS dispatch_assert(pp != DISPATCH_NO_PRIORITY); if (!_dispatch_set_qos_class_enabled) return 0; // the priority in _dispatch_get_priority() only tracks manager-ness @@ -2047,7 +2048,6 @@ _dispatch_priority_compute_update(pthread_priority_t pp, // the manager bit is invalid input, but we keep it to get meaningful // assertions in _dispatch_set_priority_and_voucher_slow() pp &= _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG | ~_PTHREAD_PRIORITY_FLAGS_MASK; -#if HAVE_PTHREAD_WORKQUEUE_QOS pthread_priority_t cur_priority = _dispatch_get_priority(); pthread_priority_t unbind = _PTHREAD_PRIORITY_NEEDS_UNBIND_FLAG; pthread_priority_t overcommit = _PTHREAD_PRIORITY_OVERCOMMIT_FLAG; @@ -2064,6 +2064,8 @@ _dispatch_priority_compute_update(pthread_priority_t pp, cur_priority &= ~overcommit; } if (unlikely(pp != cur_priority)) return pp; +#else + (void)pp; (void)flags; #endif return 0; } diff --git a/src/internal.h b/src/internal.h index 2e91ea797..bba72f658 100644 --- a/src/internal.h +++ b/src/internal.h @@ -144,7 +144,11 @@ #include #endif -#define DISPATCH_PURE_C (!defined(__OBJC__) && !defined(__cplusplus)) +#if defined(__OBJC__) || defined(__cplusplus) +#define DISPATCH_PURE_C 0 +#else +#define DISPATCH_PURE_C 1 +#endif /* private.h must be included last to avoid picking up installed headers. */ #include "os/object_private.h" @@ -934,6 +938,16 @@ _dispatch_ktrace_impl(uint32_t code, uint64_t a, uint64_t b, #define VOUCHER_USE_BANK_AUTOREDEEM 1 #endif +#if OS_FIREHOSE_SPI +#include +#else +typedef uint64_t firehose_activity_id_t; +typedef uint64_t firehose_tracepoint_id_t; +typedef unsigned long firehose_activity_flags_t; +typedef uint8_t firehose_stream_t; +typedef void * voucher_activity_hooks_t; +#endif + #if !VOUCHER_USE_MACH_VOUCHER || \ !__has_include() || \ !DISPATCH_HOST_SUPPORTS_OSX(101200) diff --git a/src/object.c b/src/object.c index 56f6dc88a..1928df53f 100644 --- a/src/object.c +++ b/src/object.c @@ -240,7 +240,7 @@ dispatch_set_target_queue(dispatch_object_t dou, dispatch_queue_t tq) } else if (dou._do->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT && !slowpath(dx_hastypeflag(dou._do, QUEUE_ROOT))) { if (slowpath(!tq)) { - tq = _dispatch_get_root_queue(QOS_CLASS_DEFAULT, false); + tq = _dispatch_get_root_queue(_DISPATCH_QOS_CLASS_DEFAULT, false); } _dispatch_object_set_target_queue_inline(dou._do, tq); } diff --git a/src/object_internal.h b/src/object_internal.h index 1ae8ae6ef..80bb10251 100644 --- a/src/object_internal.h +++ b/src/object_internal.h @@ -490,7 +490,7 @@ void _dispatch_last_resort_autorelease_pool_pop(void *context); }) #else #define dispatch_invoke_with_autoreleasepool(flags, ...) \ - do { __VA_ARGS__; } while (0) + do { (void)flags; __VA_ARGS__; } while (0) #endif diff --git a/src/queue.c b/src/queue.c index 9b069f150..1670783d3 100644 --- a/src/queue.c +++ b/src/queue.c @@ -907,10 +907,12 @@ libdispatch_init(void) #if DISPATCH_PERF_MON && !DISPATCH_INTROSPECTION _dispatch_thread_key_create(&dispatch_bcounter_key, NULL); #endif +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK if (DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK) { _dispatch_thread_key_create(&dispatch_sema4_key, _dispatch_thread_semaphore_dispose); } +#endif #if DISPATCH_USE_RESOLVERS // rdar://problem/8541707 _dispatch_main_q.do_targetq = &_dispatch_root_queues[ @@ -1074,7 +1076,7 @@ _dispatch_get_queue_attr(qos_class_t qos, int prio, dispatch_queue_attr_t _dispatch_get_default_queue_attr(void) { - return _dispatch_get_queue_attr(QOS_CLASS_UNSPECIFIED, 0, + return _dispatch_get_queue_attr(_DISPATCH_QOS_CLASS_UNSPECIFIED, 0, _dispatch_queue_attr_overcommit_unspecified, DISPATCH_AUTORELEASE_FREQUENCY_INHERIT, false, false); } @@ -1236,10 +1238,15 @@ _dispatch_queue_create_with_target(const char *label, dispatch_queue_attr_t dqa, } } if (qos == _DISPATCH_QOS_CLASS_UNSPECIFIED) { - qos = _pthread_qos_class_decode(tq->dq_priority, NULL, NULL); - // force going through _dispatch_queue_priority_inherit_from_target - tq = _dispatch_get_root_queue(qos, overcommit == - _dispatch_queue_attr_overcommit_enabled); + if (overcommit == _dispatch_queue_attr_overcommit_enabled) { + if (!(tq->dq_priority & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG)) { + tq++; + } + } else { + if (tq->dq_priority & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG) { + tq--; + } + } } else { tq = NULL; } @@ -2344,7 +2351,7 @@ _dispatch_queue_debug_attr(dispatch_queue_t dq, char* buf, size_t bufsiz) offset += dsnprintf(&buf[offset], bufsiz - offset, "target = %s[%p], width = 0x%x, state = 0x%016llx", target && target->dq_label ? target->dq_label : "", target, - dq->dq_width, dq_state); + dq->dq_width, (unsigned long long)dq_state); if (_dq_state_is_suspended(dq_state)) { offset += dsnprintf(&buf[offset], bufsiz - offset, ", suspended = %d", _dq_state_suspend_cnt(dq_state)); @@ -2651,6 +2658,7 @@ _dispatch_block_create_with_voucher_and_priority(dispatch_block_flags_t flags, voucher_t voucher, pthread_priority_t pri, dispatch_block_t block) { flags = _dispatch_block_normalize_flags(flags); +#if HAVE_PTHREAD_WORKQUEUE_QOS bool assign = (flags & DISPATCH_BLOCK_ASSIGN_CURRENT); if (assign && !(flags & DISPATCH_BLOCK_HAS_VOUCHER)) { @@ -2664,6 +2672,7 @@ _dispatch_block_create_with_voucher_and_priority(dispatch_block_flags_t flags, pri = _dispatch_priority_propagate(); flags |= DISPATCH_BLOCK_HAS_PRIORITY; } +#endif dispatch_block_t db = _dispatch_block_create(flags, voucher, pri, block); #if DISPATCH_DEBUG dispatch_assert(_dispatch_block_get_data(db)); @@ -3986,8 +3995,10 @@ _dispatch_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, } if (target) { return _dispatch_queue_class_wakeup(dq, pp, flags, target); +#if HAVE_PTHREAD_WORKQUEUE_QOS } else if (pp) { return _dispatch_queue_class_override_drainer(dq, pp, flags); +#endif } else if (flags & DISPATCH_WAKEUP_CONSUME) { return _dispatch_release_tailcall(dq); } @@ -4021,6 +4032,13 @@ _dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, return _dispatch_release_tailcall(dq); } } +#else +void +_dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, + dispatch_wakeup_flags_t flags) +{ + LINUX_PORT_ERROR(); +} #endif void diff --git a/src/shims.h b/src/shims.h index b26884396..db288225e 100644 --- a/src/shims.h +++ b/src/shims.h @@ -93,6 +93,10 @@ typedef unsigned long pthread_priority_t; #define _PTHREAD_PRIORITY_SCHED_PRI_FLAG 0x20000000 #endif // HAVE_PTHREAD_QOS_H +#ifdef __linux__ +#include "shims/linux_stubs.h" +#endif + typedef uint32_t dispatch_priority_t; #define DISPATCH_SATURATED_OVERRIDE ((dispatch_priority_t)UINT32_MAX) @@ -220,10 +224,6 @@ void __builtin_trap(void); #endif -#ifdef __linux__ -#include "shims/linux_stubs.h" -#endif - #ifndef __OS_INTERNAL_ATOMIC__ #include "shims/atomic.h" #endif diff --git a/src/shims/linux_stubs.h b/src/shims/linux_stubs.h index b5946a4c9..7726e9073 100644 --- a/src/shims/linux_stubs.h +++ b/src/shims/linux_stubs.h @@ -16,11 +16,88 @@ #ifndef __DISPATCH__STUBS__INTERNAL #define __DISPATCH__STUBS__INTERNAL -mach_port_t pthread_mach_thread_np(); +// marker for hacks we have made to make progress +#define __LINUX_PORT_HDD__ 1 + +/* + * Stub out defines for some mach types and related macros + */ + +typedef uint32_t mach_port_t; + +#define MACH_PORT_NULL (0) +#define MACH_PORT_DEAD (-1) + +typedef uint32_t mach_error_t; + +typedef uint32_t mach_vm_size_t; + +typedef uint32_t mach_msg_return_t; + +typedef uint32_t mach_msg_bits_t; + +typedef uintptr_t mach_vm_address_t; + +typedef uint32_t dispatch_mach_msg_t; + +typedef uint32_t dispatch_mach_t; + +typedef uint32_t dispatch_mach_reason_t; + +typedef uint32_t voucher_activity_mode_t; + +typedef uint32_t voucher_activity_trace_id_t; + +typedef uint32_t voucher_activity_id_t; + +typedef uint32_t _voucher_activity_buffer_hook_t;; + +typedef uint32_t voucher_activity_flag_t; + +typedef struct { } mach_msg_header_t; + + +typedef void (*dispatch_mach_handler_function_t)(void*, dispatch_mach_reason_t, + dispatch_mach_msg_t, mach_error_t); + +typedef void (*dispatch_mach_msg_destructor_t)(void*); mach_port_t mach_task_self(); -void mach_vm_deallocate(mach_port_t, mach_vm_address_t, mach_vm_size_t); +// Print a warning when an unported code path executes. +#define LINUX_PORT_ERROR() do { printf("LINUX_PORT_ERROR_CALLED %s:%d: %s\n",__FILE__,__LINE__,__FUNCTION__); } while (0) + +/* + * Stub out defines for other missing types + */ + +#if __linux__ +// we fall back to use kevent +#define kevent64_s kevent +#define kevent64(kq,cl,nc,el,ne,f,to) kevent(kq,cl,nc,el,ne,to) +#endif + +// SIZE_T_MAX should not be hardcoded like this here. +#define SIZE_T_MAX (0x7fffffff) + +// Define to 0 the NOTE_ values that are not present on Linux. +// Revisit this...would it be better to ifdef out the uses instead?? + +// The following values are passed as part of the EVFILT_TIMER requests + +#define IGNORE_KEVENT64_EXT /* will force the kevent64_s.ext[] to not be used -> leeway ignored */ + +#define NOTE_SECONDS 0x01 +#define NOTE_USECONDS 0x02 +#define NOTE_NSECONDS 0x04 +#define NOTE_ABSOLUTE 0x08 +#define NOTE_CRITICAL 0x10 +#define NOTE_BACKGROUND 0x20 +#define NOTE_LEEWAY 0x40 + +// need to catch the following usage if it happens .. +// we simply return '0' as a value probably not correct + +#define NOTE_VM_PRESSURE ({LINUX_PORT_ERROR(); 0;}) -char* mach_error_string(mach_msg_return_t); #endif diff --git a/src/shims/lock.c b/src/shims/lock.c index dfca11ba8..2fab69107 100644 --- a/src/shims/lock.c +++ b/src/shims/lock.c @@ -117,7 +117,6 @@ _dispatch_unfair_lock_wake(uint32_t *uaddr, uint32_t flags) #pragma mark - futex wrappers #if HAVE_FUTEX #include -#include #include DISPATCH_ALWAYS_INLINE @@ -140,7 +139,7 @@ _dispatch_futex_wait(uint32_t *uaddr, uint32_t val, ); } -static int +static void _dispatch_futex_wake(uint32_t *uaddr, int wake, int opflags) { int rc; @@ -157,7 +156,7 @@ _dispatch_futex_lock_pi(uint32_t *uaddr, struct timespec *timeout, int detect, { _dlock_syscall_switch(err, _dispatch_futex(uaddr, FUTEX_LOCK_PI, detect, timeout, - NULL, 0, opflags); + NULL, 0, opflags), case 0: return; default: DISPATCH_CLIENT_CRASH(errno, "futex_lock_pi() failed"); ); @@ -167,7 +166,7 @@ static void _dispatch_futex_unlock_pi(uint32_t *uaddr, int opflags) { _dlock_syscall_switch(err, - _dispatch_futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags); + _dispatch_futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags), case 0: return; default: DISPATCH_CLIENT_CRASH(errno, "futex_unlock_pi() failed"); ); @@ -183,7 +182,7 @@ _dispatch_wait_on_address(uint32_t volatile *address, uint32_t value, #if HAVE_UL_COMPARE_AND_WAIT _dispatch_ulock_wait((uint32_t *)address, value, 0, flags); #elif HAVE_FUTEX - _dispatch_futex_wait((uint32_t *)address, value, NULL, FUTEX_FLAG_PRIVATE); + _dispatch_futex_wait((uint32_t *)address, value, NULL, FUTEX_PRIVATE_FLAG); #else mach_msg_timeout_t timeout = 1; while (os_atomic_load(address, relaxed) == value) { @@ -199,7 +198,7 @@ _dispatch_wake_by_address(uint32_t volatile *address) #if HAVE_UL_COMPARE_AND_WAIT _dispatch_ulock_wake((uint32_t *)address, ULF_WAKE_ALL); #elif HAVE_FUTEX - _dispatch_futex_wake((uint32_t *)address, INT_MAX, FUTEX_FLAG_PRIVATE); + _dispatch_futex_wake((uint32_t *)address, INT_MAX, FUTEX_PRIVATE_FLAG); #else (void)address; #endif @@ -207,6 +206,7 @@ _dispatch_wake_by_address(uint32_t volatile *address) #pragma mark - thread event +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK semaphore_t _dispatch_thread_semaphore_create(void) { @@ -228,19 +228,22 @@ _dispatch_thread_semaphore_dispose(void *ctxt) DISPATCH_VERIFY_MIG(kr); DISPATCH_SEMAPHORE_VERIFY_KR(kr); } +#endif void _dispatch_thread_event_signal_slow(dispatch_thread_event_t dte) { +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK if (DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK) { kern_return_t kr = semaphore_signal(dte->dte_semaphore); DISPATCH_SEMAPHORE_VERIFY_KR(kr); return; } +#endif #if HAVE_UL_COMPARE_AND_WAIT _dispatch_ulock_wake(&dte->dte_value, 0); #elif HAVE_FUTEX - _dispatch_futex_wake(&dte->dte_value, 1, FUTEX_FLAG_PRIVATE); + _dispatch_futex_wake(&dte->dte_value, 1, FUTEX_PRIVATE_FLAG); #elif USE_POSIX_SEM int rc = sem_post(&dte->dte_sem); DISPATCH_SEMAPHORE_VERIFY_RET(ret); @@ -250,6 +253,7 @@ _dispatch_thread_event_signal_slow(dispatch_thread_event_t dte) void _dispatch_thread_event_wait_slow(dispatch_thread_event_t dte) { +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK if (DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK) { kern_return_t kr; do { @@ -258,6 +262,7 @@ _dispatch_thread_event_wait_slow(dispatch_thread_event_t dte) DISPATCH_SEMAPHORE_VERIFY_KR(kr); return; } +#endif #if HAVE_UL_COMPARE_AND_WAIT || HAVE_FUTEX for (;;) { uint32_t value = os_atomic_load(&dte->dte_value, acquire); @@ -269,8 +274,8 @@ _dispatch_thread_event_wait_slow(dispatch_thread_event_t dte) int rc = _dispatch_ulock_wait(&dte->dte_value, UINT32_MAX, 0, 0); dispatch_assert(rc == 0 || rc == EFAULT); #elif HAVE_FUTEX - _dispatch_futex_wait(&dgl->dte_value, UINT32_MAX, - NULL, FUTEX_FLAG_PRIVATE); + _dispatch_futex_wait(&dte->dte_value, UINT32_MAX, + NULL, FUTEX_PRIVATE_FLAG); #endif } #elif USE_POSIX_SEM @@ -318,9 +323,11 @@ _dispatch_unfair_lock_lock_slow(dispatch_unfair_lock_t dul, } #elif HAVE_FUTEX void -_dispatch_unfair_lock_lock_slow(dispatch_unfair_lock_t dul) +_dispatch_unfair_lock_lock_slow(dispatch_unfair_lock_t dul, + dispatch_lock_options_t flags) { - _dispatch_futex_lock_pi(&dul->dul_lock, 1, NULL, FUTEX_FLAG_PRIVATE); + (void)flags; + _dispatch_futex_lock_pi(&dul->dul_lock, NULL, 1, FUTEX_PRIVATE_FLAG); } #else void @@ -355,7 +362,7 @@ _dispatch_unfair_lock_unlock_slow(dispatch_unfair_lock_t dul, } #elif HAVE_FUTEX // futex_unlock_pi() handles both OWNER_DIED which we abuse & WAITERS - _dispatch_futex_unlock_pi(&dul->dul_lock, FUTEX_FLAG_PRIVATE); + _dispatch_futex_unlock_pi(&dul->dul_lock, FUTEX_PRIVATE_FLAG); #else (void)dul; #endif @@ -388,7 +395,7 @@ _dispatch_gate_wait_slow(dispatch_gate_t dgl, dispatch_lock value, #if HAVE_UL_UNFAIR_LOCK _dispatch_unfair_lock_wait(&dgl->dgl_lock, tid_new, 0, flags); #elif HAVE_FUTEX - _dispatch_futex_wait(&dgl->dgl_lock, tid_new, NULL, FUTEX_FLAG_PRIVATE); + _dispatch_futex_wait(&dgl->dgl_lock, tid_new, NULL, FUTEX_PRIVATE_FLAG); #else _dispatch_thread_switch(tid_new, flags, timeout++); #endif @@ -407,7 +414,7 @@ _dispatch_gate_broadcast_slow(dispatch_gate_t dgl, dispatch_lock tid_cur) #if HAVE_UL_UNFAIR_LOCK _dispatch_unfair_lock_wake(&dgl->dgl_lock, ULF_WAKE_ALL); #elif HAVE_FUTEX - _dispatch_futex_wake(&dgl->dgl_lock, INT_MAX, FUTEX_FLAG_PRIVATE); + _dispatch_futex_wake(&dgl->dgl_lock, INT_MAX, FUTEX_PRIVATE_FLAG); #else (void)dgl; #endif diff --git a/src/shims/lock.h b/src/shims/lock.h index 52a705cd5..0786d9947 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -87,6 +87,9 @@ _dispatch_lock_has_failed_trylock(dispatch_lock lock_value) } #elif defined(__linux__) +#include +#include +#include /* For SYS_xxx definitions */ typedef uint32_t dispatch_lock; typedef pid_t dispatch_lock_owner; @@ -95,7 +98,7 @@ typedef pid_t dispatch_lock_owner; #define DLOCK_OWNER_MASK ((dispatch_lock)FUTEX_TID_MASK) #define DLOCK_WAITERS_BIT ((dispatch_lock)FUTEX_WAITERS) #define DLOCK_FAILED_TRYLOCK_BIT ((dispatch_lock)FUTEX_OWNER_DIED) -#define _dispatch_tid_self() /* FIXME cached in TSD in the swift port */ +#define _dispatch_tid_self() syscall(SYS_gettid) /* FIXME: should be cached in TSD instead of doing syscall each time */ DISPATCH_ALWAYS_INLINE static inline bool @@ -157,7 +160,7 @@ _dispatch_lock_has_failed_trylock(dispatch_lock lock_value) #endif // HAVE_UL_UNFAIR_LOCK #ifndef DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK -#define DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK (!HAVE_UL_COMPARE_AND_WAIT) +#define DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK (!HAVE_UL_COMPARE_AND_WAIT && !HAVE_FUTEX) #endif #ifndef HAVE_FUTEX @@ -235,6 +238,7 @@ typedef struct dispatch_thread_event_s { #endif } dispatch_thread_event_s, *dispatch_thread_event_t; +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK semaphore_t _dispatch_thread_semaphore_create(void); void _dispatch_thread_semaphore_dispose(void *); @@ -262,6 +266,7 @@ _dispatch_put_thread_semaphore(semaphore_t sema) return _dispatch_thread_semaphore_dispose((void *)(uintptr_t)old_sema); } } +#endif DISPATCH_NOT_TAIL_CALLED void _dispatch_thread_event_wait_slow(dispatch_thread_event_t); @@ -271,10 +276,12 @@ DISPATCH_ALWAYS_INLINE static inline void _dispatch_thread_event_init(dispatch_thread_event_t dte) { +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK if (DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK) { dte->dte_semaphore = _dispatch_get_thread_semaphore(); return; } +#endif #if HAVE_UL_COMPARE_AND_WAIT || HAVE_FUTEX dte->dte_value = 0; #elif USE_POSIX_SEM @@ -287,10 +294,12 @@ DISPATCH_ALWAYS_INLINE static inline void _dispatch_thread_event_signal(dispatch_thread_event_t dte) { +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK if (DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK) { _dispatch_thread_event_signal_slow(dte); return; } +#endif #if HAVE_UL_COMPARE_AND_WAIT || HAVE_FUTEX if (os_atomic_inc_orig(&dte->dte_value, release) == 0) { // 0 -> 1 transition doesn't need a signal @@ -309,10 +318,12 @@ DISPATCH_ALWAYS_INLINE static inline void _dispatch_thread_event_wait(dispatch_thread_event_t dte) { +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK if (DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK) { _dispatch_thread_event_wait_slow(dte); return; } +#endif #if HAVE_UL_COMPARE_AND_WAIT || HAVE_FUTEX if (os_atomic_dec(&dte->dte_value, acquire) == 0) { // 1 -> 0 is always a valid transition, so we can return @@ -329,10 +340,12 @@ DISPATCH_ALWAYS_INLINE static inline void _dispatch_thread_event_destroy(dispatch_thread_event_t dte) { +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK if (DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK) { _dispatch_put_thread_semaphore(dte->dte_semaphore); return; } +#endif #if HAVE_UL_COMPARE_AND_WAIT || HAVE_FUTEX // nothing to do dispatch_assert(dte->dte_value == 0); @@ -428,7 +441,7 @@ _dispatch_unfair_lock_unlock_had_failed_trylock(dispatch_unfair_lock_t l) #if HAVE_FUTEX if (likely(os_atomic_cmpxchgv(&l->dul_lock, tid_self, DLOCK_OWNER_NULL, &tid_cur, release))) { - return; + return false; } #else tid_cur = os_atomic_xchg(&l->dul_lock, DLOCK_OWNER_NULL, release); diff --git a/src/source.c b/src/source.c index dd26814df..e5743e2f9 100644 --- a/src/source.c +++ b/src/source.c @@ -622,7 +622,7 @@ _dispatch_source_kevent_unregister(dispatch_source_t ds) } } else if (!ds->ds_is_direct_kevent) { ds->ds_dkev = NULL; - dispatch_assert(ds->ds_is_installed); + dispatch_assert((bool)ds->ds_is_installed); TAILQ_REMOVE(&dk->dk_sources, ds->ds_refs, dr_list); _dispatch_kevent_unregister(dk, flags, 0); } else { @@ -1031,8 +1031,10 @@ _dispatch_source_wakeup(dispatch_source_t ds, pthread_priority_t pp, if (tq) { return _dispatch_queue_class_wakeup(ds->_as_dq, pp, flags, tq); +#if HAVE_PTHREAD_WORKQUEUE_QOS } else if (pp) { return _dispatch_queue_class_override_drainer(ds->_as_dq, pp, flags); +#endif } else if (flags & DISPATCH_WAKEUP_CONSUME) { return _dispatch_release_tailcall(ds); } @@ -1204,10 +1206,12 @@ _dispatch_source_merge_kevent(dispatch_source_t ds, if (dqf & (DSF_CANCELED | DQF_RELEASED)) { goto done; // rdar://20204025 } +#if HAVE_MACH if (ke->filter == EVFILT_MACHPORT && dx_type(ds) == DISPATCH_MACH_CHANNEL_TYPE) { DISPATCH_INTERNAL_CRASH(ke->flags,"Unexpected kevent for mach channel"); } +#endif unsigned long data; if ((ke->flags & EV_UDATA_SPECIFIC) && (ke->flags & EV_ONESHOT) && @@ -1220,9 +1224,11 @@ _dispatch_source_merge_kevent(dispatch_source_t ds, // Since we never ask for both EV_ONESHOT and EV_VANISHED for sources, // if we get both bits it was a real EV_VANISHED delivery os_atomic_store2o(ds, ds_pending_data, 0, relaxed); +#if HAVE_MACH } else if (ke->filter == EVFILT_MACHPORT) { data = DISPATCH_MACH_RECV_MESSAGE; os_atomic_store2o(ds, ds_pending_data, data, relaxed); +#endif } else if (ds->ds_is_level) { // ke->data is signed and "negative available data" makes no sense // zero bytes happens when EV_EOF is set @@ -1571,12 +1577,14 @@ _dispatch_kevent_error(_dispatch_kevent_qos_s *ke) ke->flags |= kev->flags; } +#if HAVE_MACH if (ke->filter == EVFILT_MACHPORT && ke->data == ENOTSUP && (ke->flags & EV_ADD) && _dispatch_evfilt_machport_direct_enabled && kev && (kev->fflags & MACH_RCV_MSG)) { DISPATCH_INTERNAL_CRASH(ke->ident, "Missing EVFILT_MACHPORT support for ports"); } +#endif if (ke->data) { // log the unexpected error @@ -6078,8 +6086,10 @@ _dispatch_mach_wakeup(dispatch_mach_t dm, pthread_priority_t pp, done: if (tq) { return _dispatch_queue_class_wakeup(dm->_as_dq, pp, flags, tq); +#if HAVE_PTHREAD_WORKQUEUE_QOS } else if (pp) { return _dispatch_queue_class_override_drainer(dm->_as_dq, pp, flags); +#endif } else if (flags & DISPATCH_WAKEUP_CONSUME) { return _dispatch_release_tailcall(dm); } diff --git a/src/voucher_internal.h b/src/voucher_internal.h index 461cdfddd..3aa1a6579 100644 --- a/src/voucher_internal.h +++ b/src/voucher_internal.h @@ -692,9 +692,10 @@ _dispatch_continuation_voucher_set(dispatch_continuation_t dc, DISPATCH_ALWAYS_INLINE static inline void -_dispatch_continuation_voucher_adopt(dispatch_continuation_t dc, long dc_vtable) +_dispatch_continuation_voucher_adopt(dispatch_continuation_t dc, voucher_t ov, + uintptr_t dc_flags) { - (void)dc; (void)dc_vtable; + (void)dc; (void)ov; (void)dc_flags; } #endif // VOUCHER_USE_MACH_VOUCHER From 847f62b62366d11b6f038c0525f0b81851c6a4e6 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 15 Jun 2016 11:28:47 -0700 Subject: [PATCH 02/67] Merge pull request #81 from dgrove-oss/linux-porting Linux port of libdispatch-685 merge Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 0c7ff18d1..c5cf82b15 100644 --- a/PATCHES +++ b/PATCHES @@ -241,3 +241,4 @@ github commits starting with 29bdc2f from [4a6ec51] APPLIED rdar://25159995 [bc16cc9] APPLIED rdar://25159995 [954ace4] APPLIED rdar://25159995 +[5ea30b5] APPLIED rdar://26822213 From 7f2a683ab99f1c8721bcf8af4fe9e14c76aec6e8 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 23 Jun 2016 09:54:50 -0600 Subject: [PATCH 03/67] tweaks to preprocessor checks in libdispatch-685 Linux port validated by building on Darwin with -DHAVE_PTHREAD_WORKQUEUE_QOS=0 -DDISPATCH_USE_KEVENT_QOS=0 -DVOUCHER_USE_MACH_VOUCHER=0 -DOS_FIREHOSE_SPI=0 Signed-off-by: Daniel A. Steffen --- config/config.h | 4 +++ configure.ac | 2 +- dispatch/dispatch.h | 50 ++++++++++------------------------ src/firehose/firehose_buffer.c | 4 +++ src/init.c | 2 +- src/inline_internal.h | 2 +- src/internal.h | 10 ------- src/introspection.c | 2 ++ src/queue.c | 25 ++++++++--------- src/source.c | 10 +++---- 10 files changed, 43 insertions(+), 68 deletions(-) diff --git a/config/config.h b/config/config.h index 3d44641bb..ca3a1dbb8 100644 --- a/config/config.h +++ b/config/config.h @@ -13,6 +13,10 @@ don't. */ #define HAVE_DECL_FD_COPY 1 +/* Define to 1 if you have the declaration of `NOTE_LOWAT', and to 0 if you + don't. */ +#define HAVE_DECL_NOTE_LOWAT 1 + /* Define to 1 if you have the declaration of `NOTE_NONE', and to 0 if you don't. */ #define HAVE_DECL_NOTE_NONE 1 diff --git a/configure.ac b/configure.ac index d983d7f00..e3710f2ed 100644 --- a/configure.ac +++ b/configure.ac @@ -267,7 +267,7 @@ AC_CHECK_FUNCS([mach_port_construct]) # AC_CHECK_DECLS([CLOCK_UPTIME, CLOCK_MONOTONIC], [], [], [[#include ]]) -AC_CHECK_DECLS([NOTE_NONE, NOTE_REAP, NOTE_REVOKE, NOTE_SIGNAL], [], [], +AC_CHECK_DECLS([NOTE_NONE, NOTE_REAP, NOTE_REVOKE, NOTE_SIGNAL, NOTE_LOWAT], [], [], [[#include ]]) AC_CHECK_DECLS([FD_COPY], [], [], [[#include ]]) AC_CHECK_DECLS([SIGEMT], [], [], [[#include ]]) diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index 349dd5983..11034f290 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -24,53 +24,31 @@ #ifdef __APPLE__ #include #include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__linux__) && defined(__DISPATCH_BUILDING_SWIFT_MODULE__) -#include // for off_t -#endif - -#ifndef __OSX_AVAILABLE_STARTING +#else #define __OSX_AVAILABLE_STARTING(x, y) -#endif -#ifndef __OSX_AVAILABLE_BUT_DEPRECATED #define __OSX_AVAILABLE_BUT_DEPRECATED(...) -#endif -#ifndef __OSX_AVAILABLE_BUT_DEPRECATED_MSG #define __OSX_AVAILABLE_BUT_DEPRECATED_MSG(...) -#endif - -#ifndef __OSX_AVAILABLE #define __OSX_AVAILABLE(...) -#endif -#ifndef __IOS_AVAILABLE #define __IOS_AVAILABLE(...) -#endif -#ifndef __TVOS_AVAILABLE #define __TVOS_AVAILABLE(...) -#endif -#ifndef __WATCHOS_AVAILABLE #define __WATCHOS_AVAILABLE(...) -#endif -#ifndef __OSX_DEPRECATED #define __OSX_DEPRECATED(...) -#endif -#ifndef __IOS_DEPRECATED #define __IOS_DEPRECATED(...) -#endif -#ifndef __TVOS_DEPRECATED #define __TVOS_DEPRECATED(...) -#endif -#ifndef __WATCHOS_DEPRECATED #define __WATCHOS_DEPRECATED(...) +#endif // __APPLE__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) && defined(__DISPATCH_BUILDING_SWIFT_MODULE__) +#include // for off_t #endif #define DISPATCH_API_VERSION 20160612 diff --git a/src/firehose/firehose_buffer.c b/src/firehose/firehose_buffer.c index 5e9d225ef..5cdd9a71d 100644 --- a/src/firehose/firehose_buffer.c +++ b/src/firehose/firehose_buffer.c @@ -83,6 +83,8 @@ static void _dispatch_gate_wait(dispatch_gate_t l, uint32_t flags); #include "firehose_replyServer.h" // MiG #endif +#if OS_FIREHOSE_SPI + #if __has_feature(c_static_assert) _Static_assert(sizeof(((firehose_stream_state_u *)NULL)->fss_gate) == sizeof(((firehose_stream_state_u *)NULL)->fss_allocator), @@ -1141,3 +1143,5 @@ __firehose_merge_updates(firehose_push_reply_t update) } } #endif // KERNEL + +#endif // OS_FIREHOSE_SPI diff --git a/src/init.c b/src/init.c index e204e7d10..d4561384f 100644 --- a/src/init.c +++ b/src/init.c @@ -1196,8 +1196,8 @@ dispatch_source_type_readwrite_init(dispatch_source_t ds, dispatch_queue_t q DISPATCH_UNUSED) { ds->ds_is_level = true; +#ifdef HAVE_DECL_NOTE_LOWAT // bypass kernel check for device kqueue support rdar://19004921 -#ifdef NOTE_LOWAT ds->ds_dkev->dk_kevent.fflags = NOTE_LOWAT; #endif ds->ds_dkev->dk_kevent.data = 1; diff --git a/src/inline_internal.h b/src/inline_internal.h index f4e44a183..5d941a297 100644 --- a/src/inline_internal.h +++ b/src/inline_internal.h @@ -1963,7 +1963,7 @@ _dispatch_set_defaultpriority(pthread_priority_t pp, pthread_priority_t *new_pp) if (new_pp) *new_pp = pp; return old_pp; #else - (void)pp; + (void)pp; (void)new_pp; return 0; #endif } diff --git a/src/internal.h b/src/internal.h index bba72f658..21fda7e32 100644 --- a/src/internal.h +++ b/src/internal.h @@ -938,16 +938,6 @@ _dispatch_ktrace_impl(uint32_t code, uint64_t a, uint64_t b, #define VOUCHER_USE_BANK_AUTOREDEEM 1 #endif -#if OS_FIREHOSE_SPI -#include -#else -typedef uint64_t firehose_activity_id_t; -typedef uint64_t firehose_tracepoint_id_t; -typedef unsigned long firehose_activity_flags_t; -typedef uint8_t firehose_stream_t; -typedef void * voucher_activity_hooks_t; -#endif - #if !VOUCHER_USE_MACH_VOUCHER || \ !__has_include() || \ !DISPATCH_HOST_SUPPORTS_OSX(101200) diff --git a/src/introspection.c b/src/introspection.c index cdd631ccd..d847cb91a 100644 --- a/src/introspection.c +++ b/src/introspection.c @@ -189,6 +189,7 @@ _dispatch_introspection_continuation_get_info(dispatch_queue_t dq, if (_dispatch_object_has_vtable(dc)) { flags = 0; switch (dc_type(dc)) { +#if HAVE_PTHREAD_WORKQUEUE_QOS case DC_OVERRIDE_STEALING_TYPE: case DC_OVERRIDE_OWNING_TYPE: dc = dc->dc_data; @@ -200,6 +201,7 @@ _dispatch_introspection_continuation_get_info(dispatch_queue_t dq, return; } return _dispatch_introspection_continuation_get_info(dq, dc, diqi); +#endif case DC_ASYNC_REDIRECT_TYPE: DISPATCH_INTERNAL_CRASH(0, "Handled by the caller"); case DC_MACH_SEND_BARRRIER_DRAIN_TYPE: diff --git a/src/queue.c b/src/queue.c index 1670783d3..7a74d0f96 100644 --- a/src/queue.c +++ b/src/queue.c @@ -2658,7 +2658,6 @@ _dispatch_block_create_with_voucher_and_priority(dispatch_block_flags_t flags, voucher_t voucher, pthread_priority_t pri, dispatch_block_t block) { flags = _dispatch_block_normalize_flags(flags); -#if HAVE_PTHREAD_WORKQUEUE_QOS bool assign = (flags & DISPATCH_BLOCK_ASSIGN_CURRENT); if (assign && !(flags & DISPATCH_BLOCK_HAS_VOUCHER)) { @@ -2672,7 +2671,6 @@ _dispatch_block_create_with_voucher_and_priority(dispatch_block_flags_t flags, pri = _dispatch_priority_propagate(); flags |= DISPATCH_BLOCK_HAS_PRIORITY; } -#endif dispatch_block_t db = _dispatch_block_create(flags, voucher, pri, block); #if DISPATCH_DEBUG dispatch_assert(_dispatch_block_get_data(db)); @@ -3995,20 +3993,18 @@ _dispatch_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, } if (target) { return _dispatch_queue_class_wakeup(dq, pp, flags, target); -#if HAVE_PTHREAD_WORKQUEUE_QOS } else if (pp) { return _dispatch_queue_class_override_drainer(dq, pp, flags); -#endif } else if (flags & DISPATCH_WAKEUP_CONSUME) { return _dispatch_release_tailcall(dq); } } -#if DISPATCH_COCOA_COMPAT void _dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, dispatch_wakeup_flags_t flags) { +#if DISPATCH_COCOA_COMPAT if (slowpath(_dispatch_queue_atomic_flags(dq) & DQF_RELEASED)) { // return _dispatch_queue_wakeup(dq, pp, flags); @@ -4027,19 +4023,15 @@ _dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, _dispatch_thread_override_end(owner, dq); return; } - if (flags & DISPATCH_WAKEUP_CONSUME) { return _dispatch_release_tailcall(dq); } -} -#else -void -_dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, - dispatch_wakeup_flags_t flags) -{ +#elif defined(__linux__) LINUX_PORT_ERROR(); -} +#else + return _dispatch_queue_wakeup(dq, pp, flags); #endif +} void _dispatch_main_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, @@ -4930,12 +4922,14 @@ _dispatch_queue_class_wakeup_with_override(dispatch_queue_t dq, return _dispatch_release_tailcall(dq); } } +#endif // HAVE_PTHREAD_WORKQUEUE_QOS DISPATCH_NOINLINE void _dispatch_queue_class_override_drainer(dispatch_queue_t dq, pthread_priority_t pp, dispatch_wakeup_flags_t flags) { +#if HAVE_PTHREAD_WORKQUEUE_QOS uint64_t dq_state, value; // @@ -4957,10 +4951,14 @@ _dispatch_queue_class_override_drainer(dispatch_queue_t dq, return _dispatch_queue_class_wakeup_with_override(dq, pp, flags, dq_state); } +#else + (void)pp; +#endif // HAVE_PTHREAD_WORKQUEUE_QOS if (flags & DISPATCH_WAKEUP_CONSUME) { return _dispatch_release_tailcall(dq); } } + #if DISPATCH_USE_KEVENT_WORKQUEUE DISPATCH_NOINLINE static void @@ -4997,7 +4995,6 @@ _dispatch_trystash_to_deferred_items(dispatch_queue_t dq, dispatch_object_t dou, _dispatch_queue_push_inline(dq, dou, 0, 0); } #endif -#endif // HAVE_PTHREAD_WORKQUEUE_QOS DISPATCH_NOINLINE void diff --git a/src/source.c b/src/source.c index e5743e2f9..b01e9b2aa 100644 --- a/src/source.c +++ b/src/source.c @@ -1031,10 +1031,8 @@ _dispatch_source_wakeup(dispatch_source_t ds, pthread_priority_t pp, if (tq) { return _dispatch_queue_class_wakeup(ds->_as_dq, pp, flags, tq); -#if HAVE_PTHREAD_WORKQUEUE_QOS } else if (pp) { return _dispatch_queue_class_override_drainer(ds->_as_dq, pp, flags); -#endif } else if (flags & DISPATCH_WAKEUP_CONSUME) { return _dispatch_release_tailcall(ds); } @@ -3192,19 +3190,23 @@ _dispatch_memorypressure_handler(void *context DISPATCH_UNUSED) if (memorypressure & DISPATCH_MEMORYPRESSURE_NORMAL) { _dispatch_memory_warn = false; _dispatch_continuation_cache_limit = DISPATCH_CONTINUATION_CACHE_LIMIT; +#if VOUCHER_USE_MACH_VOUCHER if (_firehose_task_buffer) { firehose_buffer_clear_bank_flags(_firehose_task_buffer, FIREHOSE_BUFFER_BANK_FLAG_LOW_MEMORY); } +#endif } if (memorypressure & DISPATCH_MEMORYPRESSURE_WARN) { _dispatch_memory_warn = true; _dispatch_continuation_cache_limit = DISPATCH_CONTINUATION_CACHE_LIMIT_MEMORYPRESSURE_PRESSURE_WARN; +#if VOUCHER_USE_MACH_VOUCHER if (_firehose_task_buffer) { firehose_buffer_set_bank_flags(_firehose_task_buffer, FIREHOSE_BUFFER_BANK_FLAG_LOW_MEMORY); } +#endif } if (memorypressure & DISPATCH_MEMORYPRESSURE_MALLOC_MASK) { malloc_memory_event_handler(memorypressure & DISPATCH_MEMORYPRESSURE_MALLOC_MASK); @@ -6086,10 +6088,8 @@ _dispatch_mach_wakeup(dispatch_mach_t dm, pthread_priority_t pp, done: if (tq) { return _dispatch_queue_class_wakeup(dm->_as_dq, pp, flags, tq); -#if HAVE_PTHREAD_WORKQUEUE_QOS } else if (pp) { return _dispatch_queue_class_override_drainer(dm->_as_dq, pp, flags); -#endif } else if (flags & DISPATCH_WAKEUP_CONSUME) { return _dispatch_release_tailcall(dm); } @@ -6585,7 +6585,7 @@ dispatch_kevent_debug(const char *verb, const _dispatch_kevent_qos_s *kev, #else 0ull, 0ull, #endif - str, function, line); + function, line); #endif } From 10c999186df4fcaf194d72ef05cb4330d03b5b9d Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 17 Jun 2016 11:39:48 -0400 Subject: [PATCH 04/67] Avoid overwriting config.h with generated header Change name of generated header file to config_ac.h and use __has_include to prefer the generated file if it is present. Avoids stomping on the config.h used by XCode when building using autotools. Signed-off-by: Daniel A. Steffen --- configure.ac | 2 +- src/internal.h | 4 ++++ src/shims/linux_stubs.c | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index e3710f2ed..678625d0e 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ AC_PREREQ(2.69) AC_INIT([libdispatch], [1.3], [libdispatch@macosforge.org], [libdispatch], [http://libdispatch.macosforge.org]) AC_REVISION([$$]) AC_CONFIG_AUX_DIR(config) -AC_CONFIG_HEADER([config/config.h]) +AC_CONFIG_HEADER([config/config_ac.h]) AC_CONFIG_MACRO_DIR([m4]) ac_clean_files=a.out.dSYM AM_MAINTAINER_MODE diff --git a/src/internal.h b/src/internal.h index 21fda7e32..a6261e11f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -27,7 +27,11 @@ #ifndef __DISPATCH_INTERNAL__ #define __DISPATCH_INTERNAL__ +#if __has_include() +#include +#else #include +#endif #define __DISPATCH_BUILDING_DISPATCH__ #define __DISPATCH_INDIRECT__ diff --git a/src/shims/linux_stubs.c b/src/shims/linux_stubs.c index b209e6f10..dad96eb17 100644 --- a/src/shims/linux_stubs.c +++ b/src/shims/linux_stubs.c @@ -18,7 +18,12 @@ #include #include + +#if __has_include() +#include +#else #include +#endif #include "pthread.h" #include "os/linux_base.h" From 75185458fcd25f97256fa25dfbc96e3ba5816a23 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Fri, 17 Jun 2016 20:20:28 -0700 Subject: [PATCH 05/67] Merge pull request #84 from dgrove-oss/gitignore_config.h Avoid overwriting config.h with generated header Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index c5cf82b15..52ad0c57c 100644 --- a/PATCHES +++ b/PATCHES @@ -242,3 +242,4 @@ github commits starting with 29bdc2f from [bc16cc9] APPLIED rdar://25159995 [954ace4] APPLIED rdar://25159995 [5ea30b5] APPLIED rdar://26822213 +[9f1e778] APPLIED rdar://26822213 From 31f1d2b8622867f69aa4824f37fceba2de627580 Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 16 Jun 2016 17:43:24 -0400 Subject: [PATCH 06/67] Eliminate dummy mach-specific functions from linux_stubs Get rid of mach_error_string, mach_vm_deallocate, and mach_test_self by adding missing #if HAVE_MACH in the last couple places it was missing. Avoid needing pthread_mach_thread_np by replacing uses of the _dispatch_thread_port() macro with _dispatch_tid_self() Signed-off-by: Daniel A. Steffen --- src/data.c | 2 ++ src/init.c | 2 ++ src/queue.c | 26 +++++++++++++------------- src/shims/linux_stubs.c | 11 ----------- src/shims/linux_stubs.h | 2 -- 5 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/data.c b/src/data.c index 050eeb47d..b950bae03 100644 --- a/src/data.c +++ b/src/data.c @@ -155,10 +155,12 @@ _dispatch_data_destroy_buffer(const void* buffer, size_t size, free((void*)buffer); } else if (destructor == DISPATCH_DATA_DESTRUCTOR_NONE) { // do nothing +#if HAVE_MACH } else if (destructor == DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE) { mach_vm_size_t vm_size = size; mach_vm_address_t vm_addr = (uintptr_t)buffer; mach_vm_deallocate(mach_task_self(), vm_addr, vm_size); +#endif } else { if (!queue) { queue = dispatch_get_global_queue( diff --git a/src/init.c b/src/init.c index d4561384f..b62fc85c8 100644 --- a/src/init.c +++ b/src/init.c @@ -580,12 +580,14 @@ _dispatch_bug_client(const char* msg) _dispatch_bug_log("BUG in libdispatch client: %s", msg); } +#if HAVE_MACH void _dispatch_bug_mach_client(const char* msg, mach_msg_return_t kr) { _dispatch_bug_log("BUG in libdispatch client: %s %s - 0x%x", msg, mach_error_string(kr), kr); } +#endif void _dispatch_bug_kevent_client(const char* msg, const char* filter, diff --git a/src/queue.c b/src/queue.c index 7a74d0f96..320b395f3 100644 --- a/src/queue.c +++ b/src/queue.c @@ -553,7 +553,7 @@ dispatch_assert_queue(dispatch_queue_t dq) if (unlikely(_dq_state_drain_pended(dq_state))) { goto fail; } - if (likely(_dq_state_drain_owner(dq_state) == _dispatch_thread_port())) { + if (likely(_dq_state_drain_owner(dq_state) == _dispatch_tid_self())) { return; } if (likely(dq->dq_width > 1)) { @@ -580,7 +580,7 @@ dispatch_assert_queue_not(dispatch_queue_t dq) if (_dq_state_drain_pended(dq_state)) { return; } - if (likely(_dq_state_drain_owner(dq_state) != _dispatch_thread_port())) { + if (likely(_dq_state_drain_owner(dq_state) != _dispatch_tid_self())) { if (likely(dq->dq_width == 1)) { // we can look at the width: if it is changing while we read it, // it means that a barrier is running on `dq` concurrently, which @@ -1602,7 +1602,7 @@ _dispatch_queue_resume(dispatch_queue_t dq, bool activate) DISPATCH_QUEUE_WIDTH_FULL_BIT) { value = full_width; value &= ~DISPATCH_QUEUE_DIRTY; - value |= _dispatch_thread_port(); + value |= _dispatch_tid_self(); } } } @@ -2334,7 +2334,7 @@ _dispatch_queue_is_exclusively_owned_by_current_thread_4IOHID( DISPATCH_CLIENT_CRASH(dq->dq_width, "Invalid queue type"); } uint64_t dq_state = os_atomic_load2o(dq, dq_state, relaxed); - return _dq_state_drain_locked_by(dq_state, _dispatch_thread_port()); + return _dq_state_drain_locked_by(dq_state, _dispatch_tid_self()); } #endif @@ -2471,7 +2471,7 @@ _dispatch_set_priority_and_mach_voucher_slow(pthread_priority_t pp, pflags |= _PTHREAD_SET_SELF_QOS_FLAG; } if (unlikely(DISPATCH_QUEUE_DRAIN_OWNER(&_dispatch_mgr_q) == - _dispatch_thread_port())) { + _dispatch_tid_self())) { DISPATCH_INTERNAL_CRASH(pp, "Changing the QoS while on the manager queue"); } @@ -2773,7 +2773,7 @@ _dispatch_block_invoke_direct(const struct dispatch_block_private_data_s *dbcpd) v = dbpd->dbpd_voucher; } ov = _dispatch_adopt_priority_and_set_voucher(p, v, adopt_flags); - dbpd->dbpd_thread = _dispatch_thread_port(); + dbpd->dbpd_thread = _dispatch_tid_self(); _dispatch_client_callout(dbpd->dbpd_block, _dispatch_Block_invoke(dbpd->dbpd_block)); _dispatch_reset_priority_and_voucher(op, ov); @@ -3123,7 +3123,7 @@ _dispatch_async_redirect_invoke(dispatch_continuation_t dc, old_dp = _dispatch_set_defaultpriority(dq->dq_priority, &dp); op = dq->dq_override; if (op > (dp & _PTHREAD_PRIORITY_QOS_CLASS_MASK)) { - _dispatch_wqthread_override_start(_dispatch_thread_port(), op); + _dispatch_wqthread_override_start(_dispatch_tid_self(), op); // Ensure that the root queue sees that this thread was overridden. _dispatch_set_defaultpriority_override(); } @@ -3543,7 +3543,7 @@ _dispatch_barrier_sync_f_slow(dispatch_queue_t dq, void *ctxt, _dispatch_introspection_barrier_sync_begin(dq, func); } #endif - uint32_t th_self = _dispatch_thread_port(); + uint32_t th_self = _dispatch_tid_self(); struct dispatch_continuation_s dbss = { .dc_flags = DISPATCH_OBJ_BARRIER_BIT | DISPATCH_OBJ_SYNC_SLOW_BIT, .dc_func = _dispatch_barrier_sync_f_slow_invoke, @@ -3709,7 +3709,7 @@ _dispatch_non_barrier_complete(dispatch_queue_t dq) DISPATCH_QUEUE_WIDTH_FULL_BIT) { new_state = full_width; new_state &= ~DISPATCH_QUEUE_DIRTY; - new_state |= _dispatch_thread_port(); + new_state |= _dispatch_tid_self(); } } } @@ -3736,7 +3736,7 @@ _dispatch_sync_f_slow(dispatch_queue_t dq, void *ctxt, dispatch_function_t func, } dispatch_thread_event_s event; _dispatch_thread_event_init(&event); - uint32_t th_self = _dispatch_thread_port(); + uint32_t th_self = _dispatch_tid_self(); struct dispatch_continuation_s dc = { .dc_flags = DISPATCH_OBJ_SYNC_SLOW_BIT, #if DISPATCH_INTROSPECTION @@ -4430,7 +4430,7 @@ _dispatch_main_queue_drain(void) " after dispatch_main()"); } mach_port_t owner = DISPATCH_QUEUE_DRAIN_OWNER(dq); - if (slowpath(owner != _dispatch_thread_port())) { + if (slowpath(owner != _dispatch_tid_self())) { DISPATCH_CLIENT_CRASH(owner, "_dispatch_main_queue_callback_4CF called" " from the wrong thread"); } @@ -4655,7 +4655,7 @@ _dispatch_queue_drain_deferred_invoke(dispatch_queue_t dq, } if (dq) { - uint32_t self = _dispatch_thread_port(); + uint32_t self = _dispatch_tid_self(); os_atomic_rmw_loop2o(dq, dq_state, old_state, new_state, release,{ new_state = old_state; if (!_dq_state_drain_pended(old_state) || @@ -5091,7 +5091,7 @@ _dispatch_queue_class_wakeup(dispatch_queue_t dq, pthread_priority_t pp, uint64_t pending_barrier_width = (dq->dq_width - 1) * DISPATCH_QUEUE_WIDTH_INTERVAL; uint64_t xor_owner_and_set_full_width_and_in_barrier = - _dispatch_thread_port() | DISPATCH_QUEUE_WIDTH_FULL_BIT | + _dispatch_tid_self() | DISPATCH_QUEUE_WIDTH_FULL_BIT | DISPATCH_QUEUE_IN_BARRIER; #ifdef DLOCK_NOWAITERS_BIT diff --git a/src/shims/linux_stubs.c b/src/shims/linux_stubs.c index dad96eb17..d5618d572 100644 --- a/src/shims/linux_stubs.c +++ b/src/shims/linux_stubs.c @@ -39,17 +39,6 @@ unsigned long _dispatch_runloop_queue_probe(dispatch_queue_t dq) { void _dispatch_runloop_queue_xref_dispose() { LINUX_PORT_ERROR(); } void _dispatch_runloop_queue_dispose() { LINUX_PORT_ERROR(); } -char* mach_error_string(mach_msg_return_t x) { - LINUX_PORT_ERROR(); -} -void mach_vm_deallocate() { LINUX_PORT_ERROR(); } - -mach_port_t pthread_mach_thread_np(void) { - return (pid_t)syscall(SYS_gettid); -} -mach_port_t mach_task_self(void) { - return (mach_port_t)pthread_self(); -} /* * Stubbed out static data diff --git a/src/shims/linux_stubs.h b/src/shims/linux_stubs.h index 7726e9073..6a70c0b11 100644 --- a/src/shims/linux_stubs.h +++ b/src/shims/linux_stubs.h @@ -62,8 +62,6 @@ typedef void (*dispatch_mach_handler_function_t)(void*, dispatch_mach_reason_t, typedef void (*dispatch_mach_msg_destructor_t)(void*); -mach_port_t mach_task_self(); - // Print a warning when an unported code path executes. #define LINUX_PORT_ERROR() do { printf("LINUX_PORT_ERROR_CALLED %s:%d: %s\n",__FILE__,__LINE__,__FUNCTION__); } while (0) From b11112dd9bcb9db3756883a5cf877892e7316a94 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Fri, 17 Jun 2016 20:44:22 -0700 Subject: [PATCH 07/67] Merge pull request #86 from dgrove-oss/kill_mach_task_self_on_linux eliminate mach_task_self from linux_stubs Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 52ad0c57c..4461a297c 100644 --- a/PATCHES +++ b/PATCHES @@ -243,3 +243,4 @@ github commits starting with 29bdc2f from [954ace4] APPLIED rdar://25159995 [5ea30b5] APPLIED rdar://26822213 [9f1e778] APPLIED rdar://26822213 +[3339b81] APPLIED rdar://26822213 From b8cce96d9d123eaabcc30d7d15c709a68f095297 Mon Sep 17 00:00:00 2001 From: Hubertus Franke Date: Thu, 16 Jun 2016 11:32:45 -0400 Subject: [PATCH 08/67] TLS thread local storage refresh Signed-off-by: Daniel A. Steffen --- configure.ac | 21 ++++++++++++ src/init.c | 11 +++--- src/queue.c | 57 +++++++++++++++++++++++++++++++ src/shims/linux_stubs.c | 1 + src/shims/lock.h | 3 +- src/shims/tsd.h | 75 +++++++++++++++++++++++++++++++++++++++-- 6 files changed, 159 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index 678625d0e..b3dc10658 100644 --- a/configure.ac +++ b/configure.ac @@ -108,6 +108,27 @@ AC_ARG_WITH([swift-toolchain], AM_CONDITIONAL(HAVE_SWIFT, $have_swift) AC_SUBST([SWIFTC]) +# +# Enable __thread based TSD on platforms where it is efficient +# Allow override based on command line argument to configure +# +AC_CANONICAL_TARGET +AC_ARG_ENABLE([thread-local-storage], + [AS_HELP_STRING([--enable-thread-local-storage], + [Enable usage of thread local storage via __thread])],, + [case $target_os in + linux*) + enable_thread_local_storage=yes + ;; + *) + enable_thread_local_storage=no + esac] +) +AS_IF([test "x$enable_thread_local_storage" = "xyes"], + [AC_DEFINE(DISPATCH_USE_THREAD_LOCAL_STORAGE, 1, + [Enable usage of thread local storage via __thread])] +) + AC_USE_SYSTEM_EXTENSIONS AM_INIT_AUTOMAKE([foreign no-dependencies subdir-objects]) LT_INIT([disable-static]) diff --git a/src/init.c b/src/init.c index b62fc85c8..8ffd1bf7a 100644 --- a/src/init.c +++ b/src/init.c @@ -67,7 +67,10 @@ void *(*_dispatch_begin_NSAutoReleasePool)(void); void (*_dispatch_end_NSAutoReleasePool)(void *); #endif -#if !DISPATCH_USE_DIRECT_TSD +#if DISPATCH_USE_THREAD_LOCAL_STORAGE +__thread struct dispatch_tsd __dispatch_tsd; +pthread_key_t __dispatch_tsd_key; +#elif !DISPATCH_USE_DIRECT_TSD pthread_key_t dispatch_queue_key; pthread_key_t dispatch_frame_key; pthread_key_t dispatch_cache_key; @@ -82,7 +85,7 @@ pthread_key_t dispatch_bcounter_key; pthread_key_t dispatch_sema4_key; pthread_key_t dispatch_voucher_key; pthread_key_t dispatch_deferred_items_key; -#endif // !DISPATCH_USE_DIRECT_TSD +#endif // !DISPATCH_USE_DIRECT_TSD && !DISPATCH_USE_THREAD_LOCAL_STORAGE #if VOUCHER_USE_MACH_VOUCHER dispatch_once_t _voucher_task_mach_voucher_pred; @@ -184,10 +187,6 @@ const struct dispatch_tsd_indexes_s dispatch_tsd_indexes = { .dti_voucher_index = dispatch_voucher_key, .dti_qos_class_index = dispatch_priority_key, }; -#else // DISPATCH_USE_DIRECT_TSD -#ifndef __LINUX_PORT_HDD__ -#error Not implemented on this platform -#endif #endif // DISPATCH_USE_DIRECT_TSD // 6618342 Contact the team that owns the Instrument DTrace probe before diff --git a/src/queue.c b/src/queue.c index 320b395f3..ef6a2c639 100644 --- a/src/queue.c +++ b/src/queue.c @@ -894,6 +894,9 @@ libdispatch_init(void) #endif #endif +#if DISPATCH_USE_THREAD_LOCAL_STORAGE + _dispatch_thread_key_create(&__dispatch_tsd_key, _libdispatch_tsd_cleanup); +#else _dispatch_thread_key_create(&dispatch_queue_key, _dispatch_queue_cleanup); _dispatch_thread_key_create(&dispatch_deferred_items_key, _dispatch_deferred_items_cleanup); @@ -913,6 +916,7 @@ libdispatch_init(void) _dispatch_thread_semaphore_dispose); } #endif +#endif #if DISPATCH_USE_RESOLVERS // rdar://problem/8541707 _dispatch_main_q.do_targetq = &_dispatch_root_queues[ @@ -967,6 +971,59 @@ _dispatch_get_mach_host_port(void) } #endif +#if DISPATCH_USE_THREAD_LOCAL_STORAGE +#include +#include + +#ifdef SYS_gettid +DISPATCH_ALWAYS_INLINE +static inline pid_t +gettid(void) +{ + return (pid_t) syscall(SYS_gettid); +} +#else +#error "SYS_gettid unavailable on this system" +#endif + +#define _tsd_call_cleanup(k, f) do { \ + if ((f) && tsd->k) ((void(*)(void*))(f))(tsd->k); \ + } while (0) + +void +_libdispatch_tsd_cleanup(void *ctx) +{ + struct dispatch_tsd *tsd = (struct dispatch_tsd*) ctx; + + _tsd_call_cleanup(dispatch_queue_key, _dispatch_queue_cleanup); + _tsd_call_cleanup(dispatch_frame_key, _dispatch_frame_cleanup); + _tsd_call_cleanup(dispatch_cache_key, _dispatch_cache_cleanup); + _tsd_call_cleanup(dispatch_context_key, _dispatch_context_cleanup); + _tsd_call_cleanup(dispatch_pthread_root_queue_observer_hooks_key, + NULL); + _tsd_call_cleanup(dispatch_defaultpriority_key, NULL); +#if DISPATCH_PERF_MON && !DISPATCH_INTROSPECTION + _tsd_call_cleanup(dispatch_bcounter_key, NULL); +#endif +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK + _tsd_call_cleanup(dispatch_sema4_key, _dispatch_thread_semaphore_dispose); +#endif + _tsd_call_cleanup(dispatch_priority_key, NULL); + _tsd_call_cleanup(dispatch_voucher_key, _voucher_thread_cleanup); + _tsd_call_cleanup(dispatch_deferred_items_key, + _dispatch_deferred_items_cleanup); + tsd->tid = 0; +} + +DISPATCH_NOINLINE +void +libdispatch_tsd_init(void) +{ + pthread_setspecific(__dispatch_tsd_key, &__dispatch_tsd); + __dispatch_tsd.tid = gettid(); +} +#endif + DISPATCH_EXPORT DISPATCH_NOTHROW void dispatch_atfork_child(void) diff --git a/src/shims/linux_stubs.c b/src/shims/linux_stubs.c index d5618d572..33a4578ac 100644 --- a/src/shims/linux_stubs.c +++ b/src/shims/linux_stubs.c @@ -57,3 +57,4 @@ unsigned short dispatch_callout__return_semaphore; unsigned short dispatch_queue__push_semaphore; void (*_dispatch_block_special_invoke)(void*); struct dispatch_queue_attr_s _dispatch_queue_attr_concurrent; + diff --git a/src/shims/lock.h b/src/shims/lock.h index 0786d9947..5c2dfc502 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -98,7 +98,8 @@ typedef pid_t dispatch_lock_owner; #define DLOCK_OWNER_MASK ((dispatch_lock)FUTEX_TID_MASK) #define DLOCK_WAITERS_BIT ((dispatch_lock)FUTEX_WAITERS) #define DLOCK_FAILED_TRYLOCK_BIT ((dispatch_lock)FUTEX_OWNER_DIED) -#define _dispatch_tid_self() syscall(SYS_gettid) /* FIXME: should be cached in TSD instead of doing syscall each time */ +#define _dispatch_tid_self() \ + ((dispatch_lock_owner)(_dispatch_get_tsd_base()->tid)) DISPATCH_ALWAYS_INLINE static inline bool diff --git a/src/shims/tsd.h b/src/shims/tsd.h index ef67a90d3..2edba3959 100644 --- a/src/shims/tsd.h +++ b/src/shims/tsd.h @@ -92,10 +92,76 @@ _dispatch_thread_key_create(const unsigned long *k, void (*d)(void *)) if (!*k || !d) return; dispatch_assert_zero(pthread_key_init_np((int)*k, d)); } +#elif DISPATCH_USE_THREAD_LOCAL_STORAGE + +DISPATCH_TSD_INLINE +static inline void +_dispatch_thread_key_create(pthread_key_t *k, void (*d)(void *)) +{ + dispatch_assert_zero(pthread_key_create(k, d)); +} + +struct dispatch_tsd { + pid_t tid; + void *dispatch_queue_key; + void *dispatch_frame_key; + void *dispatch_cache_key; + void *dispatch_context_key; + void *dispatch_pthread_root_queue_observer_hooks_key; + void *dispatch_defaultpriority_key; +#if DISPATCH_INTROSPECTION + void *dispatch_introspection_key; +#elif DISPATCH_PERF_MON + void *dispatch_bcounter_key; +#endif +#if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK + void *dispatch_sema4_key; +#endif + void *dispatch_priority_key; + void *dispatch_voucher_key; + void *dispatch_deferred_items_key; +}; + +extern __thread struct dispatch_tsd __dispatch_tsd; +extern pthread_key_t __dispatch_tsd_key; +extern void libdispatch_tsd_init(void); +extern void _libdispatch_tsd_cleanup(void *ctx); + +DISPATCH_ALWAYS_INLINE +static inline struct dispatch_tsd * +_dispatch_get_tsd_base(void) +{ + if (unlikely(__dispatch_tsd.tid == 0)) { + libdispatch_tsd_init(); + } + OS_COMPILER_CAN_ASSUME(__dispatch_tsd.tid != 0); + return &__dispatch_tsd; +} + +#define _dispatch_thread_getspecific(key) \ + (_dispatch_get_tsd_base()->key) +#define _dispatch_thread_setspecific(key, value) \ + (void)(_dispatch_get_tsd_base()->key = (value)) + +#define _dispatch_thread_getspecific_pair(k1, p1, k2, p2) \ + ( *(p1) = _dispatch_thread_getspecific(k1), \ + *(p2) = _dispatch_thread_getspecific(k2) ) + +#define _dispatch_thread_getspecific_packed_pair(k1, k2, p) \ + ( (p)[0] = _dispatch_thread_getspecific(k1), \ + (p)[1] = _dispatch_thread_getspecific(k2) ) + +#define _dispatch_thread_setspecific_pair(k1, p1, k2, p2) \ + ( _dispatch_thread_setspecific(k1,p1), \ + _dispatch_thread_setspecific(k2,p2) ) + +#define _dispatch_thread_setspecific_packed_pair(k1, k2, p) \ + ( _dispatch_thread_setspecific(k1,(p)[0]), \ + _dispatch_thread_setspecific(k2,(p)[1]) ) + #else extern pthread_key_t dispatch_queue_key; extern pthread_key_t dispatch_frame_key; -extern pthread_key_t dispatch_sema4_key; extern pthread_key_t dispatch_cache_key; extern pthread_key_t dispatch_context_key; extern pthread_key_t dispatch_pthread_root_queue_observer_hooks_key; @@ -105,7 +171,8 @@ extern pthread_key_t dispatch_introspection_key; #elif DISPATCH_PERF_MON extern pthread_key_t dispatch_bcounter_key; #endif -extern pthread_key_t dispatch_cache_key; +extern pthread_key_t dispatch_sema4_key; +extern pthread_key_t dispatch_priority_key; extern pthread_key_t dispatch_voucher_key; extern pthread_key_t dispatch_deferred_items_key; @@ -117,6 +184,7 @@ _dispatch_thread_key_create(pthread_key_t *k, void (*d)(void *)) } #endif +#ifndef DISPATCH_USE_THREAD_LOCAL_STORAGE DISPATCH_TSD_INLINE static inline void _dispatch_thread_setspecific(pthread_key_t k, void *v) @@ -210,6 +278,7 @@ _dispatch_thread_setspecific_packed_pair(pthread_key_t k1, pthread_key_t k2, _dispatch_thread_setspecific(k1, p[0]); _dispatch_thread_setspecific(k2, p[1]); } +#endif #if TARGET_OS_WIN32 #define _dispatch_thread_self() ((uintptr_t)GetCurrentThreadId()) @@ -228,6 +297,8 @@ _dispatch_thread_setspecific_packed_pair(pthread_key_t k1, pthread_key_t k2, #if DISPATCH_USE_DIRECT_TSD #define _dispatch_thread_port() ((mach_port_t)(uintptr_t)\ _dispatch_thread_getspecific(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF)) +#elif DISPATCH_USE_THREAD_LOCAL_STORAGE +#define _dispatch_thread_port() ((mach_port_t)(_dispatch_get_tsd_base()->tid)) #else #define _dispatch_thread_port() pthread_mach_thread_np(_dispatch_thread_self()) #endif From c4f4e68163aa959fc2603dd1bb60ed8b638d209f Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Mon, 20 Jun 2016 18:10:26 -0700 Subject: [PATCH 09/67] Merge pull request #82 from frankeh/TLS TLS: Thread Local Storage Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 4461a297c..f6d8638d4 100644 --- a/PATCHES +++ b/PATCHES @@ -244,3 +244,4 @@ github commits starting with 29bdc2f from [5ea30b5] APPLIED rdar://26822213 [9f1e778] APPLIED rdar://26822213 [3339b81] APPLIED rdar://26822213 +[4fa8d8d] APPLIED rdar://26822213 From 3e6e4b743c95a3d08e290c777c9f0e38034fadd0 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 23 Jun 2016 13:12:20 -0600 Subject: [PATCH 10/67] remove mach-specific thread_port macro that should not be used on linux whitespace Signed-off-by: Daniel A. Steffen --- src/shims/linux_stubs.c | 1 - src/shims/tsd.h | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/shims/linux_stubs.c b/src/shims/linux_stubs.c index 33a4578ac..d5618d572 100644 --- a/src/shims/linux_stubs.c +++ b/src/shims/linux_stubs.c @@ -57,4 +57,3 @@ unsigned short dispatch_callout__return_semaphore; unsigned short dispatch_queue__push_semaphore; void (*_dispatch_block_special_invoke)(void*); struct dispatch_queue_attr_s _dispatch_queue_attr_concurrent; - diff --git a/src/shims/tsd.h b/src/shims/tsd.h index 2edba3959..2e3ece8b0 100644 --- a/src/shims/tsd.h +++ b/src/shims/tsd.h @@ -278,7 +278,7 @@ _dispatch_thread_setspecific_packed_pair(pthread_key_t k1, pthread_key_t k2, _dispatch_thread_setspecific(k1, p[0]); _dispatch_thread_setspecific(k2, p[1]); } -#endif +#endif #if TARGET_OS_WIN32 #define _dispatch_thread_self() ((uintptr_t)GetCurrentThreadId()) @@ -293,12 +293,10 @@ _dispatch_thread_setspecific_packed_pair(pthread_key_t k1, pthread_key_t k2, #if TARGET_OS_WIN32 #define _dispatch_thread_port() ((mach_port_t)0) -#else +#elif !DISPATCH_USE_THREAD_LOCAL_STORAGE #if DISPATCH_USE_DIRECT_TSD #define _dispatch_thread_port() ((mach_port_t)(uintptr_t)\ _dispatch_thread_getspecific(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF)) -#elif DISPATCH_USE_THREAD_LOCAL_STORAGE -#define _dispatch_thread_port() ((mach_port_t)(_dispatch_get_tsd_base()->tid)) #else #define _dispatch_thread_port() pthread_mach_thread_np(_dispatch_thread_self()) #endif From c1f5e466e69a5fb1b2fa08a53b1b64e9da448a9e Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 22 Jun 2016 09:05:27 -0600 Subject: [PATCH 11/67] import Dispatch overlay and apinotes from swift-3.0-preview-2-branch of github swift repo Signed-off-by: Daniel A. Steffen --- src/swift/Block.swift | 131 ++++++++++ src/swift/Data.swift | 302 +++++++++++++++++++++++ src/swift/Dispatch.apinotes | 328 +++++++++++++++++++++++++ src/swift/Dispatch.mm | 179 ++++++++++++++ src/swift/Dispatch.swift | 308 +++++++++++++---------- src/swift/IO.swift | 127 ++++++++++ src/swift/Private.swift | 472 ++++++++++++++++++++++++++++++++++++ src/swift/Queue.swift | 429 ++++++++++++++++++++++++++++++++ src/swift/Source.swift | 389 +++++++++++++++++++++++++++++ src/swift/Time.swift | 108 +++++++++ src/swift/swift_wrappers.c | 47 ---- 11 files changed, 2639 insertions(+), 181 deletions(-) create mode 100644 src/swift/Block.swift create mode 100644 src/swift/Data.swift create mode 100644 src/swift/Dispatch.apinotes create mode 100644 src/swift/Dispatch.mm create mode 100644 src/swift/IO.swift create mode 100644 src/swift/Private.swift create mode 100644 src/swift/Queue.swift create mode 100644 src/swift/Source.swift create mode 100644 src/swift/Time.swift delete mode 100644 src/swift/swift_wrappers.c diff --git a/src/swift/Block.swift b/src/swift/Block.swift new file mode 100644 index 000000000..e32478ea0 --- /dev/null +++ b/src/swift/Block.swift @@ -0,0 +1,131 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +public struct DispatchWorkItemFlags : OptionSet, RawRepresentable { + public let rawValue: UInt + public init(rawValue: UInt) { self.rawValue = rawValue } + + public static let barrier = DispatchWorkItemFlags(rawValue: 0x1) + + @available(OSX 10.10, iOS 8.0, *) + public static let detached = DispatchWorkItemFlags(rawValue: 0x2) + + @available(OSX 10.10, iOS 8.0, *) + public static let assignCurrentContext = DispatchWorkItemFlags(rawValue: 0x4) + + @available(OSX 10.10, iOS 8.0, *) + public static let noQoS = DispatchWorkItemFlags(rawValue: 0x8) + + @available(OSX 10.10, iOS 8.0, *) + public static let inheritQoS = DispatchWorkItemFlags(rawValue: 0x10) + + @available(OSX 10.10, iOS 8.0, *) + public static let enforceQoS = DispatchWorkItemFlags(rawValue: 0x20) +} + +@available(OSX 10.10, iOS 8.0, *) +public class DispatchWorkItem { + internal var _block: _DispatchBlock + internal var _group: DispatchGroup? + + public init(group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], block: @convention(block) () -> ()) { + _block = _swift_dispatch_block_create_with_qos_class(__dispatch_block_flags_t(flags.rawValue), + qos.qosClass.rawValue, Int32(qos.relativePriority), block) + } + + // Used by DispatchQueue.synchronously to provide a @noescape path through + // dispatch_block_t, as we know the lifetime of the block in question. + internal init(flags: DispatchWorkItemFlags = [], noescapeBlock: @noescape () -> ()) { + _block = _swift_dispatch_block_create_noescape(__dispatch_block_flags_t(flags.rawValue), noescapeBlock) + } + + public func perform() { + if let g = _group { + g.enter() + defer { g.leave() } + } + _block() + } + + public func wait() { + _ = _swift_dispatch_block_wait(_block, DispatchTime.distantFuture.rawValue) + } + + public func wait(timeout: DispatchTime) -> DispatchTimeoutResult { + return _swift_dispatch_block_wait(_block, timeout.rawValue) == 0 ? .Success : .TimedOut + } + + public func wait(wallTimeout: DispatchWallTime) -> DispatchTimeoutResult { + return _swift_dispatch_block_wait(_block, wallTimeout.rawValue) == 0 ? .Success : .TimedOut + } + + public func notify(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], queue: DispatchQueue, execute: @convention(block) () -> Void) { + if qos != .unspecified || !flags.isEmpty { + let item = DispatchWorkItem(qos: qos, flags: flags, block: execute) + _swift_dispatch_block_notify(_block, queue, item._block) + } else { + _swift_dispatch_block_notify(_block, queue, execute) + } + } + + public func notify(queue: DispatchQueue, execute: DispatchWorkItem) { + _swift_dispatch_block_notify(_block, queue, execute._block) + } + + public func cancel() { + _swift_dispatch_block_cancel(_block) + } + + public var isCancelled: Bool { + return _swift_dispatch_block_testcancel(_block) != 0 + } +} + +@available(OSX 10.10, iOS 8.0, *) +public extension DispatchWorkItem { + @available(*, deprecated, renamed: "DispatchWorkItem.wait(self:wallTimeout:)") + public func wait(timeout: DispatchWallTime) -> Int { + switch wait(wallTimeout: timeout) { + case .Success: return 0 + case .TimedOut: return Int(KERN_OPERATION_TIMED_OUT) + } + } +} + +/// The dispatch_block_t typealias is different from usual closures in that it +/// uses @convention(block). This is to avoid unnecessary bridging between +/// C blocks and Swift closures, which interferes with dispatch APIs that depend +/// on the referential identity of a block. Particularly, dispatch_block_create. +internal typealias _DispatchBlock = @convention(block) () -> Void + +/// APINotes also removes the old dispatch_block_t typedef from the Dispatch module +/// completely. In doing so it causes the dispatch_block_* API to lose their +/// @convention(block) attributes. As such, all of the entry points are shimmed +//// through Dispatch.mm with _DispatchBlock types. +@_silgen_name("_swift_dispatch_block_create_with_qos_class") +internal func _swift_dispatch_block_create_with_qos_class(_ flags: __dispatch_block_flags_t, _ qos: qos_class_t, _ relativePriority: Int32, _ block: _DispatchBlock) -> _DispatchBlock + +@_silgen_name("_swift_dispatch_block_create_noescape") +internal func _swift_dispatch_block_create_noescape(_ flags: __dispatch_block_flags_t, _ block: @noescape () -> ()) -> _DispatchBlock + +@_silgen_name("_swift_dispatch_block_wait") +internal func _swift_dispatch_block_wait(_ block: _DispatchBlock, _ timeout: UInt64) -> Int + +@_silgen_name("_swift_dispatch_block_notify") +internal func _swift_dispatch_block_notify(_ block: _DispatchBlock, _ queue: DispatchQueue, _ notifier: _DispatchBlock) + +@_silgen_name("_swift_dispatch_block_cancel") +internal func _swift_dispatch_block_cancel(_ block: _DispatchBlock) + +@_silgen_name("_swift_dispatch_block_testcancel") +internal func _swift_dispatch_block_testcancel(_ block: _DispatchBlock) -> Int + diff --git a/src/swift/Data.swift b/src/swift/Data.swift new file mode 100644 index 000000000..a78bf5bca --- /dev/null +++ b/src/swift/Data.swift @@ -0,0 +1,302 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { + public typealias Iterator = DispatchDataIterator + public typealias Index = Int + public typealias Indices = DefaultRandomAccessIndices + + public static let empty: DispatchData = DispatchData(data: _swift_dispatch_data_empty()) + + public enum Deallocator { + /// Use `free` + case free + + /// Use `munmap` + case unmap + + /// A custom deallocator + case custom(DispatchQueue?, @convention(block) () -> Void) + + private var _deallocator: (DispatchQueue?, @convention(block) () -> Void) { + switch self { + case .free: return (nil, _dispatch_data_destructor_free()) + case .unmap: return (nil, _dispatch_data_destructor_munmap()) + case .custom(let q, let b): return (q, b) + } + } + } + + private var __wrapped: __DispatchData + + /// Initialize a `Data` with copied memory content. + /// + /// - parameter bytes: A pointer to the memory. It will be copied. + /// - parameter count: The number of bytes to copy. + public init(bytes buffer: UnsafeBufferPointer) { + __wrapped = __dispatch_data_create( + buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default()) + } + + /// Initialize a `Data` without copying the bytes. + /// + /// - parameter bytes: A pointer to the bytes. + /// - parameter count: The size of the bytes. + /// - parameter deallocator: Specifies the mechanism to free the indicated buffer. + public init(bytesNoCopy bytes: UnsafeBufferPointer, deallocator: Deallocator = .free) { + let (q, b) = deallocator._deallocator + + __wrapped = __dispatch_data_create( + bytes.baseAddress!, bytes.count, q, b) + } + + internal init(data: __DispatchData) { + __wrapped = data + } + + public var count: Int { + return __dispatch_data_get_size(__wrapped) + } + + public func withUnsafeBytes( + body: @noescape (UnsafePointer) throws -> Result) rethrows -> Result + { + var ptr: UnsafePointer? = nil + var size = 0; + let data = __dispatch_data_create_map(__wrapped, &ptr, &size) + defer { _fixLifetime(data) } + return try body(UnsafePointer(ptr!)) + } + + public func enumerateBytes( + block: @noescape (buffer: UnsafeBufferPointer, byteIndex: Int, stop: inout Bool) -> Void) + { + _swift_dispatch_data_apply(__wrapped) { (data: __DispatchData, offset: Int, ptr: UnsafePointer, size: Int) in + let bp = UnsafeBufferPointer(start: UnsafePointer(ptr), count: size) + var stop = false + block(buffer: bp, byteIndex: offset, stop: &stop) + return !stop + } + } + + /// Append bytes to the data. + /// + /// - parameter bytes: A pointer to the bytes to copy in to the data. + /// - parameter count: The number of bytes to copy. + public mutating func append(_ bytes: UnsafePointer, count: Int) { + let data = __dispatch_data_create(bytes, count, nil, _dispatch_data_destructor_default()) + self.append(DispatchData(data: data)) + } + + /// Append data to the data. + /// + /// - parameter data: The data to append to this data. + public mutating func append(_ other: DispatchData) { + let data = __dispatch_data_create_concat(__wrapped, other as __DispatchData) + __wrapped = data + } + + /// Append a buffer of bytes to the data. + /// + /// - parameter buffer: The buffer of bytes to append. The size is calculated from `SourceType` and `buffer.count`. + public mutating func append(_ buffer : UnsafeBufferPointer) { + self.append(UnsafePointer(buffer.baseAddress!), count: buffer.count * sizeof(SourceType)) + } + + private func _copyBytesHelper(to pointer: UnsafeMutablePointer, from range: CountableRange) { + var copiedCount = 0 + __dispatch_data_apply(__wrapped) { (data: __DispatchData, offset: Int, ptr: UnsafePointer, size: Int) in + let limit = Swift.min((range.endIndex - range.startIndex) - copiedCount, size) + memcpy(pointer + copiedCount, ptr, limit) + copiedCount += limit + return copiedCount < (range.endIndex - range.startIndex) + } + } + + /// Copy the contents of the data to a pointer. + /// + /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. + /// - parameter count: The number of bytes to copy. + /// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes. + public func copyBytes(to pointer: UnsafeMutablePointer, count: Int) { + _copyBytesHelper(to: pointer, from: 0.., from range: CountableRange) { + _copyBytesHelper(to: pointer, from: range) + } + + /// Copy the contents of the data into a buffer. + /// + /// This function copies the bytes in `range` from the data into the buffer. If the count of the `range` is greater than `sizeof(DestinationType) * buffer.count` then the first N bytes will be copied into the buffer. + /// - precondition: The range must be within the bounds of the data. Otherwise `fatalError` is called. + /// - parameter buffer: A buffer to copy the data into. + /// - parameter range: A range in the data to copy into the buffer. If the range is empty, this function will return 0 without copying anything. If the range is nil, as much data as will fit into `buffer` is copied. + /// - returns: Number of bytes copied into the destination buffer. + public func copyBytes(to buffer: UnsafeMutableBufferPointer, from range: CountableRange? = nil) -> Int { + let cnt = count + guard cnt > 0 else { return 0 } + + let copyRange : CountableRange + if let r = range { + guard !r.isEmpty else { return 0 } + precondition(r.startIndex >= 0) + precondition(r.startIndex < cnt, "The range is outside the bounds of the data") + + precondition(r.endIndex >= 0) + precondition(r.endIndex <= cnt, "The range is outside the bounds of the data") + + copyRange = r.startIndex..<(r.startIndex + Swift.min(buffer.count * sizeof(DestinationType), r.count)) + } else { + copyRange = 0.. = UnsafeMutablePointer(buffer.baseAddress!) + _copyBytesHelper(to: pointer, from: copyRange) + return copyRange.count + } + + /// Sets or returns the byte at the specified index. + public subscript(index: Index) -> UInt8 { + var offset = 0 + let subdata = __dispatch_data_copy_region(__wrapped, index, &offset) + + var ptr: UnsafePointer? = nil + var size = 0 + let map = __dispatch_data_create_map(subdata, &ptr, &size) + defer { _fixLifetime(map) } + + let pptr = UnsafePointer(ptr!) + return pptr[index - offset] + } + + public subscript(bounds: Range) -> RandomAccessSlice { + return RandomAccessSlice(base: self, bounds: bounds) + } + + /// Return a new copy of the data in a specified range. + /// + /// - parameter range: The range to copy. + public func subdata(in range: CountableRange) -> DispatchData { + let subrange = __dispatch_data_create_subrange( + __wrapped, range.startIndex, range.endIndex - range.startIndex) + return DispatchData(data: subrange) + } + + public func region(location: Int) -> (data: DispatchData, offset: Int) { + var offset: Int = 0 + let data = __dispatch_data_copy_region(__wrapped, location, &offset) + return (DispatchData(data: data), offset) + } + + public var startIndex: Index { + return 0 + } + + public var endIndex: Index { + return count + } + + public func index(before i: Index) -> Index { + return i - 1 + } + + public func index(after i: Index) -> Index { + return i + 1 + } + + /// An iterator over the contents of the data. + /// + /// The iterator will increment byte-by-byte. + public func makeIterator() -> DispatchData.Iterator { + return DispatchDataIterator(_data: self) + } +} + +public struct DispatchDataIterator : IteratorProtocol, Sequence { + + /// Create an iterator over the given DisaptchData + public init(_data: DispatchData) { + var ptr: UnsafePointer? + self._count = 0 + self._data = __dispatch_data_create_map( + _data as __DispatchData, &ptr, &self._count) + self._ptr = UnsafePointer(ptr!) + self._position = _data.startIndex + } + + /// Advance to the next element and return it, or `nil` if no next + /// element exists. + /// + /// - Precondition: No preceding call to `self.next()` has returned `nil`. + public mutating func next() -> DispatchData._Element? { + if _position == _count { return nil } + let element = _ptr[_position]; + _position = _position + 1 + return element + } + + internal let _data: __DispatchData + internal var _ptr: UnsafePointer + internal var _count: Int + internal var _position: DispatchData.Index +} + +extension DispatchData { + public static func _isBridgedToObjectiveC() -> Bool { + return true + } + + @_semantics("convertToObjectiveC") + public func _bridgeToObjectiveC() -> __DispatchData { + return unsafeBitCast(__wrapped, to: __DispatchData.self) + } + + public static func _forceBridgeFromObjectiveC(_ input: __DispatchData, result: inout DispatchData?) { + result = DispatchData(data: input) + } + + public static func _conditionallyBridgeFromObjectiveC(_ input: __DispatchData, result: inout DispatchData?) -> Bool { + result = DispatchData(data: input) + return true + } + + public static func _unconditionallyBridgeFromObjectiveC(_ source: __DispatchData?) -> DispatchData { + var result: DispatchData? = nil + _forceBridgeFromObjectiveC(source!, result: &result) + return result! + } +} + +typealias _swift_data_applier = @convention(block) @noescape (__DispatchData, Int, UnsafePointer, Int) -> Bool + +@_silgen_name("_swift_dispatch_data_apply") +internal func _swift_dispatch_data_apply(_ data: __DispatchData, _ block: _swift_data_applier) + +@_silgen_name("_swift_dispatch_data_empty") +internal func _swift_dispatch_data_empty() -> __DispatchData + +@_silgen_name("_swift_dispatch_data_destructor_free") +internal func _dispatch_data_destructor_free() -> _DispatchBlock + +@_silgen_name("_swift_dispatch_data_destructor_munmap") +internal func _dispatch_data_destructor_munmap() -> _DispatchBlock + +@_silgen_name("_swift_dispatch_data_destructor_default") +internal func _dispatch_data_destructor_default() -> _DispatchBlock diff --git a/src/swift/Dispatch.apinotes b/src/swift/Dispatch.apinotes new file mode 100644 index 000000000..6e804515a --- /dev/null +++ b/src/swift/Dispatch.apinotes @@ -0,0 +1,328 @@ +--- +Name: Dispatch +Typedefs: +- Name: dispatch_object_t + Availability: nonswift +- Name: dispatch_block_t + Availability: nonswift +- Name: dispatch_queue_t + Availability: nonswift +- Name: dispatch_semaphore_t + Availability: nonswift +- Name: dispatch_io_t + Availability: nonswift +- Name: dispatch_data_t + Availability: nonswift +- Name: dispatch_group_t + Availability: nonswift +- Name: dispatch_qos_class_t + Availability: nonswift +- Name: dispatch_data_applier_t + Availability: nonswift +- Name: dispatch_fd_t + Availability: nonswift +- Name: dispatch_io_handler_t + Availability: nonswift +- Name: dispatch_source_t + Availability: nonswift +- Name: dispatch_function_t + Availability: nonswift +- Name: dispatch_io_close_flags_t + Availability: nonswift +- Name: dispatch_io_interval_flags_t + Availability: nonswift +- Name: dispatch_io_type_t + Availability: nonswift +- Name: dispatch_source_timer_flags_t + Availability: nonswift +- Name: dispatch_autorelease_frequency_t + SwiftPrivate: true +- Name: dispatch_queue_attr_t + Availability: nonswift +- Name: dispatch_queue_priority_t + Availability: nonswift +- Name: dispatch_block_flags_t + SwiftPrivate: true +- Name: dispatch_source_type_t + SwiftPrivate: true +- Name: dispatch_source_mach_send_flags_t + Availability: nonswift +- Name: dispatch_source_memorypressure_flags_t + Availability: nonswift +- Name: dispatch_source_proc_flags_t + Availability: nonswift +- Name: dispatch_source_vnode_flags_t + Availability: nonswift +Classes: +- Name: OS_dispatch_object + SwiftName: DispatchObject +- Name: OS_dispatch_queue + SwiftName: DispatchQueue +- Name: OS_dispatch_io + SwiftName: DispatchIO +- Name: OS_dispatch_semaphore + SwiftName: DispatchSemaphore +- Name: OS_dispatch_group + SwiftName: DispatchGroup +- Name: OS_dispatch_source + SwiftName: DispatchSource +- Name: OS_dispatch_queue_attr + SwiftPrivate: true +- Name: OS_dispatch_data + SwiftName: __DispatchData +Protocols: +- Name: OS_dispatch_source + SwiftName: DispatchSourceType +- Name: OS_dispatch_source_mach_send + SwiftName: DispatchSourceMachSend +- Name: OS_dispatch_source_mach_recv + SwiftName: DispatchSourceMachReceive +- Name: OS_dispatch_source_memorypressure + SwiftName: DispatchSourceMemoryPressure +- Name: OS_dispatch_source_proc + SwiftName: DispatchSourceProcess +- Name: OS_dispatch_source_read + SwiftName: DispatchSourceRead +- Name: OS_dispatch_source_signal + SwiftName: DispatchSourceSignal +- Name: OS_dispatch_source_timer + SwiftName: DispatchSourceTimer +- Name: OS_dispatch_source_data_or + SwiftName: DispatchSourceUserDataOr +- Name: OS_dispatch_source_data_add + SwiftName: DispatchSourceUserDataAdd +- Name: OS_dispatch_source_vnode + SwiftName: DispatchSourceFileSystemObject +- Name: OS_dispatch_source_write + SwiftName: DispatchSourceWrite +Functions: +- Name: dispatch_release + Availability: nonswift +- Name: dispatch_retain + Availability: nonswift +# dispatch_queue_t +- Name: dispatch_queue_create + SwiftName: 'DispatchQueue.init(__label:attr:)' + SwiftPrivate: true +- Name: dispatch_get_global_queue + SwiftPrivate: true +- Name: dispatch_queue_create_with_target + SwiftName: 'DispatchQueue.init(__label:attr:queue:)' + SwiftPrivate: true +- Name: dispatch_assert_queue + SwiftPrivate: true +- Name: dispatch_assert_queue_barrier + SwiftPrivate: true +- Name: dispatch_assert_queue_not + SwiftPrivate: true +- Name: dispatch_async + SwiftPrivate: true +- Name: dispatch_async_f + Availability: nonswift +- Name: dispatch_barrier_async + SwiftPrivate: true +- Name: dispatch_barrier_async_f + Availability: nonswift +- Name: dispatch_apply + SwiftPrivate: true +- Name: dispatch_apply_f + Availability: nonswift +- Name: dispatch_sync + SwiftName: 'DispatchQueue.sync(self:execute:)' +- Name: dispatch_sync_f + Availability: nonswift +- Name: dispatch_barrier_sync + SwiftPrivate: true +- Name: dispatch_barrier_sync_f + Availability: nonswift +- Name: dispatch_queue_get_label + SwiftPrivate: true +- Name: dispatch_queue_get_qos_class + SwiftPrivate: true +- Name: dispatch_after + SwiftPrivate: true +- Name: dispatch_after_f + Availability: nonswift +- Name: dispatch_queue_get_specific + SwiftPrivate: true +- Name: dispatch_queue_set_specific + SwiftPrivate: true +- Name: dispatch_get_specific + SwiftPrivate: true +- Name: dispatch_get_main_queue + Availability: nonswift +- Name: dispatch_queue_attr_make_initially_inactive + SwiftPrivate: true +- Name: dispatch_queue_attr_make_with_autorelease_frequency + SwiftPrivate: true +- Name: dispatch_queue_attr_make_with_qos_class + SwiftPrivate: true +# dispatch_object_t +- Name: dispatch_set_target_queue + SwiftName: 'DispatchObject.setTarget(self:queue:)' +- Name: dispatch_activate + SwiftName: 'DispatchObject.activate(self:)' +- Name: dispatch_suspend + SwiftName: 'DispatchObject.suspend(self:)' +- Name: dispatch_resume + SwiftName: 'DispatchObject.resume(self:)' +- Name: dispatch_set_finalizer_f + Availability: nonswift +- Name: dispatch_get_context + Availability: nonswift +- Name: dispatch_set_context + Availability: nonswift +- Name: _dispatch_object_validate + Availability: nonswift +# dispatch_block +- Name: dispatch_block_create + Availability: nonswift + AvailabilityMsg: 'Use DispatchWorkItem()' +- Name: dispatch_block_create_with_qos_class + Availability: nonswift + AvailabilityMsg: 'Use DispatchWorkItem()' +- Name: dispatch_block_perform + Availability: nonswift + AvailabilityMsg: 'Use DispatchWorkItem.perform()' +- Name: dispatch_block_wait + Availability: nonswift + AvailabilityMsg: 'Use DispatchWorkItem.wait(timeout:)' +- Name: dispatch_block_notify + Availability: nonswift + AvailabilityMsg: 'Use DispatchWorkItem.notify(queue:execute:)' +- Name: dispatch_block_cancel + Availability: nonswift + AvailabilityMsg: 'Use DispatchWorkItem.cancel()' +- Name: dispatch_block_testcancel + Availability: nonswift + AvailabilityMsg: 'Use DispatchWorkItem.isCancelled' +# dispatch_data +- Name: dispatch_data_create + SwiftPrivate: true +- Name: dispatch_data_get_size + SwiftPrivate: true +- Name: dispatch_data_apply + SwiftPrivate: true +- Name: dispatch_data_create_concat + SwiftPrivate: true +- Name: dispatch_data_create_subrange + SwiftPrivate: true +- Name: dispatch_data_copy_region + SwiftPrivate: true +- Name: dispatch_data_create_map + SwiftPrivate: true +# dispatch_group_t +- Name: dispatch_group_create + SwiftName: 'DispatchGroup.init()' + Availability: available +- Name: dispatch_group_async + SwiftPrivate: true +- Name: dispatch_group_async_f + Availability: nonswift +- Name: dispatch_group_wait + SwiftPrivate: true +- Name: dispatch_group_notify + SwiftPrivate: true +- Name: dispatch_group_notify_f + Availability: nonswift +- Name: dispatch_group_enter + SwiftName: 'DispatchGroup.enter(self:)' +- Name: dispatch_group_leave + SwiftName: 'DispatchGroup.leave(self:)' +# dispatch_io +- Name: dispatch_io_create + SwiftPrivate: true + SwiftName: 'DispatchIO.init(__type:fd:queue:handler:)' +- Name: dispatch_io_create_with_path + SwiftPrivate: true + SwiftName: 'DispatchIO.init(__type:path:oflag:mode:queue:handler:)' +- Name: dispatch_io_create_with_io + SwiftPrivate: true + SwiftName: 'DispatchIO.init(__type:io:queue:handler:)' +- Name: dispatch_io_read + SwiftPrivate: true +- Name: dispatch_io_write + SwiftPrivate: true +- Name: dispatch_io_close + SwiftPrivate: true +- Name: dispatch_io_barrier + SwiftName: 'DispatchIO.barrier(self:execute:)' +- Name: dispatch_io_get_descriptor + SwiftName: 'getter:DispatchIO.fileDescriptor(self:)' +- Name: dispatch_io_set_high_water + SwiftName: 'DispatchIO.setLimit(self:highWater:)' +- Name: dispatch_io_set_low_water + SwiftName: 'DispatchIO.setLimit(self:lowWater:)' +- Name: dispatch_io_set_interval + SwiftPrivate: true +- Name: dispatch_read + SwiftPrivate: true +- Name: dispatch_write + SwiftPrivate: true +# dispatch_semaphore +- Name: dispatch_semaphore_create + SwiftName: 'DispatchSemaphore.init(value:)' +- Name: dispatch_semaphore_wait + SwiftPrivate: true +- Name: dispatch_semaphore_signal + SwiftPrivate: true +# dispatch_source +- Name: dispatch_source_create + SwiftPrivate: true +- Name: dispatch_source_get_handle + SwiftPrivate: true +- Name: dispatch_source_get_mask + SwiftPrivate: true +- Name: dispatch_source_get_data + SwiftPrivate: true +- Name: dispatch_source_merge_data + SwiftPrivate: true +- Name: dispatch_source_set_event_handler + SwiftPrivate: true +- Name: dispatch_source_set_event_handler_f + Availability: nonswift +- Name: dispatch_source_set_cancel_handler + SwiftPrivate: true +- Name: dispatch_source_set_cancel_handler_f + Availability: nonswift +- Name: dispatch_source_set_registration_handler + SwiftPrivate: true +- Name: dispatch_source_set_registration_handler_f + Availability: nonswift +- Name: dispatch_source_cancel + SwiftPrivate: true +- Name: dispatch_source_testcancel + SwiftPrivate: true +- Name: dispatch_source_set_timer + SwiftPrivate: true +# dispatch_time +- Name: dispatch_time + SwiftPrivate: true +- Name: dispatch_walltime + SwiftPrivate: true +- Name: dispatch_main + SwiftName: 'dispatchMain()' +Globals: +- Name: _dispatch_data_destructor_free + Availability: nonswift +- Name: _dispatch_data_destructor_munmap + Availability: nonswift +Enumerators: +- Name: DISPATCH_BLOCK_BARRIER + Availability: nonswift +- Name: DISPATCH_BLOCK_DETACHED + Availability: nonswift +- Name: DISPATCH_BLOCK_ASSIGN_CURRENT + Availability: nonswift +- Name: DISPATCH_BLOCK_NO_QOS_CLASS + Availability: nonswift +- Name: DISPATCH_BLOCK_INHERIT_QOS_CLASS + Availability: nonswift +- Name: DISPATCH_BLOCK_ENFORCE_QOS_CLASS + Availability: nonswift +- Name: DISPATCH_AUTORELEASE_FREQUENCY_INHERIT + Availability: nonswift +- Name: DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM + Availability: nonswift +- Name: DISPATCH_AUTORELEASE_FREQUENCY_NEVER + Availability: nonswift diff --git a/src/swift/Dispatch.mm b/src/swift/Dispatch.mm new file mode 100644 index 000000000..b66a34e8b --- /dev/null +++ b/src/swift/Dispatch.mm @@ -0,0 +1,179 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +#define DISPATCH_RUNTIME_STDLIB_INTERFACE __attribute__((__visibility__("default"))) + +@protocol OS_dispatch_source; +@protocol OS_dispatch_source_mach_send; +@protocol OS_dispatch_source_mach_recv; +@protocol OS_dispatch_source_memorypressure; +@protocol OS_dispatch_source_proc; +@protocol OS_dispatch_source_read; +@protocol OS_dispatch_source_signal; +@protocol OS_dispatch_source_timer; +@protocol OS_dispatch_source_data_add; +@protocol OS_dispatch_source_data_or; +@protocol OS_dispatch_source_vnode; +@protocol OS_dispatch_source_write; + +// #include +__attribute__((constructor)) +static void _dispatch_overlay_constructor() { + Class source = objc_lookUpClass("OS_dispatch_source"); + if (source) { + class_addProtocol(source, @protocol(OS_dispatch_source)); + class_addProtocol(source, @protocol(OS_dispatch_source_mach_send)); + class_addProtocol(source, @protocol(OS_dispatch_source_mach_recv)); + class_addProtocol(source, @protocol(OS_dispatch_source_memorypressure)); + class_addProtocol(source, @protocol(OS_dispatch_source_proc)); + class_addProtocol(source, @protocol(OS_dispatch_source_read)); + class_addProtocol(source, @protocol(OS_dispatch_source_signal)); + class_addProtocol(source, @protocol(OS_dispatch_source_timer)); + class_addProtocol(source, @protocol(OS_dispatch_source_data_add)); + class_addProtocol(source, @protocol(OS_dispatch_source_data_or)); + class_addProtocol(source, @protocol(OS_dispatch_source_vnode)); + class_addProtocol(source, @protocol(OS_dispatch_source_write)); + } +} + +#include "swift/Runtime/Config.h" + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" dispatch_queue_attr_t +_swift_dispatch_queue_concurrent(void) { + return DISPATCH_QUEUE_CONCURRENT; +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" void +_swift_dispatch_apply_current(size_t iterations, __attribute__((__noescape__)) void (^block)(size_t)) { + dispatch_apply(iterations, (dispatch_queue_t _Nonnull)0, block); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" dispatch_queue_t +_swift_dispatch_get_main_queue(void) { + return dispatch_get_main_queue(); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" dispatch_data_t +_swift_dispatch_data_empty(void) { + return dispatch_data_empty; +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" dispatch_block_t +_swift_dispatch_data_destructor_default(void) { + return DISPATCH_DATA_DESTRUCTOR_DEFAULT; +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" dispatch_block_t +_swift_dispatch_data_destructor_free(void) { + return _dispatch_data_destructor_free; +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" dispatch_block_t +_swift_dispatch_data_destructor_munmap(void) { + return _dispatch_data_destructor_munmap; +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" dispatch_block_t +_swift_dispatch_block_create_with_qos_class(dispatch_block_flags_t flags, qos_class_t qos, int relative_priority, dispatch_block_t block) { + return dispatch_block_create_with_qos_class(flags, qos, relative_priority, block); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" dispatch_block_t +_swift_dispatch_block_create_noescape(dispatch_block_flags_t flags, dispatch_block_t block) { + return dispatch_block_create(flags, block); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" void +_swift_dispatch_block_cancel(dispatch_block_t block) { + dispatch_block_cancel(block); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" long +_swift_dispatch_block_wait(dispatch_block_t block, dispatch_time_t timeout) { + return dispatch_block_wait(block, timeout); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" void +_swift_dispatch_block_notify(dispatch_block_t block, dispatch_queue_t queue, dispatch_block_t notification_block) { + dispatch_block_notify(block, queue, notification_block); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" long +_swift_dispatch_block_testcancel(dispatch_block_t block) { + return dispatch_block_testcancel(block); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" bool +_swift_dispatch_data_apply(dispatch_data_t data, bool (^applier)(dispatch_data_t, size_t, const void *, size_t)) { + return dispatch_data_apply(data, applier); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" void +_swift_dispatch_async(dispatch_queue_t queue, dispatch_block_t block) { + dispatch_async(queue, block); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" void +_swift_dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block) { + dispatch_group_async(group, queue, block); +} + +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" void +_swift_dispatch_sync(dispatch_queue_t queue, dispatch_block_t block) { + dispatch_sync(queue, block); +} + +// DISPATCH_RUNTIME_STDLIB_INTERFACE +// extern "C" dispatch_queue_t +// _swift_apply_current_root_queue() { +// return DISPATCH_APPLY_CURRENT_ROOT_QUEUE; +// } + +#define SOURCE(t) \ + SWIFT_CC(swift) \ + DISPATCH_RUNTIME_STDLIB_INTERFACE extern "C" dispatch_source_type_t \ + _swift_dispatch_source_type_##t(void) { \ + return DISPATCH_SOURCE_TYPE_##t; \ + } + +SOURCE(DATA_ADD) +SOURCE(DATA_OR) +SOURCE(MACH_SEND) +SOURCE(MACH_RECV) +SOURCE(MEMORYPRESSURE) +SOURCE(PROC) +SOURCE(READ) +SOURCE(SIGNAL) +SOURCE(TIMER) +SOURCE(VNODE) +SOURCE(WRITE) diff --git a/src/swift/Dispatch.swift b/src/swift/Dispatch.swift index a5f88c1ff..4ed2ad9cd 100644 --- a/src/swift/Dispatch.swift +++ b/src/swift/Dispatch.swift @@ -12,157 +12,197 @@ @_exported import Dispatch -/// The type of blocks submitted to dispatch queues, which take no arguments -/// and have no return value. -/// -/// The dispatch_block_t typealias is different from usual closures in that it -/// uses @convention(block). This is to avoid unnecessary bridging between -/// C blocks and Swift closures, which interferes with Grand Central Dispatch -/// APIs that depend on the referential identity of a block. -public typealias dispatch_block_t = @convention(block) () -> Void - -//===----------------------------------------------------------------------===// -// Macros -// FIXME: rdar://16851050 update API so these import better -//===----------------------------------------------------------------------===// - -// dispatch/io.h -public var DISPATCH_IO_STREAM: dispatch_io_type_t { - return 0 -} -public var DISPATCH_IO_RANDOM: dispatch_io_type_t { - return 1 +/// dispatch_assert + +@available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) +public enum DispatchPredicate { + case onQueue(DispatchQueue) + case onQueueAsBarrier(DispatchQueue) + case notOnQueue(DispatchQueue) +} + +@available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) +public func _dispatchPreconditionTest(_ condition: DispatchPredicate) -> Bool { + switch condition { + case .onQueue(let q): + __dispatch_assert_queue(q) + case .onQueueAsBarrier(let q): + __dispatch_assert_queue_barrier(q) + case .notOnQueue(let q): + __dispatch_assert_queue_not(q) + } + return true } -public var DISPATCH_IO_STOP: dispatch_io_close_flags_t { - return 1 -} -public var DISPATCH_IO_STRICT_INTERVAL: dispatch_io_interval_flags_t { - return 1 +@_transparent +@available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) +public func dispatchPrecondition(condition: @autoclosure () -> DispatchPredicate) { + // precondition is able to determine release-vs-debug asserts where the overlay + // cannot, so formulating this into a call that we can call with precondition() + precondition(_dispatchPreconditionTest(condition()), "dispatchPrecondition failure") } -public var DISPATCH_QUEUE_SERIAL: dispatch_queue_attr_t! { - return nil -} -public var DISPATCH_CURRENT_QUEUE_LABEL: dispatch_queue_t! { - return nil -} -public var DISPATCH_TARGET_QUEUE_DEFAULT: dispatch_queue_t! { - return nil -} -public var DISPATCH_QUEUE_PRIORITY_HIGH: dispatch_queue_priority_t { - return 2 -} -public var DISPATCH_QUEUE_PRIORITY_DEFAULT: dispatch_queue_priority_t { - return 0 -} -public var DISPATCH_QUEUE_PRIORITY_LOW: dispatch_queue_priority_t { - return -2 -} -public var DISPATCH_QUEUE_PRIORITY_BACKGROUND: dispatch_queue_priority_t { - return -32768 -} +/// qos_class_t -/* -FIXME: LINUX_PORT: qos_class_t not being imported -@warn_unused_result -public func dispatch_get_global_queue(identifier: qos_class_t, - _ flags: UInt) -> dispatch_queue_t { - return dispatch_get_global_queue(Int(identifier.rawValue), flags) -} -*/ +public struct DispatchQoS : Equatable { + public let qosClass: QoSClass + public let relativePriority: Int -public var DISPATCH_QUEUE_CONCURRENT: dispatch_queue_attr_t { - return _swift_dispatch_queue_concurrent() -} + @available(OSX 10.10, iOS 8.0, *) + public static let background = DispatchQoS(qosClass: .background, relativePriority: 0) -@warn_unused_result -@_silgen_name("_swift_dispatch_queue_concurrent") -internal func _swift_dispatch_queue_concurrent() -> dispatch_queue_attr_t + @available(OSX 10.10, iOS 8.0, *) + public static let utility = DispatchQoS(qosClass: .utility, relativePriority: 0) -// dispatch/data.h -public var dispatch_data_empty: dispatch_data_t { - return _swift_dispatch_data_empty() -} + @available(OSX 10.10, iOS 8.0, *) + public static let `default` = DispatchQoS(qosClass: .default, relativePriority: 0) -@warn_unused_result -@_silgen_name("_swift_dispatch_data_empty") -internal func _swift_dispatch_data_empty() -> dispatch_data_t + @available(OSX, introduced: 10.10, deprecated: 10.10, renamed: "DispatchQoS.default") + @available(iOS, introduced: 8.0, deprecated: 8.0, renamed: "DispatchQoS.default") + @available(*, deprecated, renamed: "DispatchQoS.default") + public static let defaultQoS = DispatchQoS.default -// dispatch/source.h -// FIXME: DISPATCH_SOURCE_TYPE_* -public var DISPATCH_PROC_EXIT: dispatch_source_proc_flags_t { - return 0x80000000 -} -public var DISPATCH_PROC_FORK: dispatch_source_proc_flags_t { return 0x40000000 } -public var DISPATCH_PROC_EXEC: dispatch_source_proc_flags_t { return 0x20000000 } -public var DISPATCH_PROC_SIGNAL: dispatch_source_proc_flags_t { return 0x08000000 } -public var DISPATCH_VNODE_DELETE: dispatch_source_vnode_flags_t { return 0x1 } -public var DISPATCH_VNODE_WRITE: dispatch_source_vnode_flags_t { return 0x2 } -public var DISPATCH_VNODE_EXTEND: dispatch_source_vnode_flags_t { return 0x4 } -public var DISPATCH_VNODE_ATTRIB: dispatch_source_vnode_flags_t { return 0x8 } -public var DISPATCH_VNODE_LINK: dispatch_source_vnode_flags_t { return 0x10 } -public var DISPATCH_VNODE_RENAME: dispatch_source_vnode_flags_t { return 0x20 } -public var DISPATCH_VNODE_REVOKE: dispatch_source_vnode_flags_t { return 0x40 } -public var DISPATCH_TIMER_STRICT: dispatch_source_timer_flags_t { return 1 } - -public var DISPATCH_SOURCE_TYPE_DATA_ADD: dispatch_source_type_t { - return _swift_dispatch_source_type_data_add() -} -public var DISPATCH_SOURCE_TYPE_DATA_OR: dispatch_source_type_t { - return _swift_dispatch_source_type_data_or() -} -public var DISPATCH_SOURCE_TYPE_READ: dispatch_source_type_t { - return _swift_dispatch_source_type_read() -} -public var DISPATCH_SOURCE_TYPE_PROC: dispatch_source_type_t { - return _swift_dispatch_source_type_proc() -} -public var DISPATCH_SOURCE_TYPE_SIGNAL: dispatch_source_type_t { - return _swift_dispatch_source_type_signal() -} -public var DISPATCH_SOURCE_TYPE_TIMER: dispatch_source_type_t { - return _swift_dispatch_source_type_timer() -} -public var DISPATCH_SOURCE_TYPE_VNODE: dispatch_source_type_t { - return _swift_dispatch_source_type_vnode() -} -public var DISPATCH_SOURCE_TYPE_WRITE: dispatch_source_type_t { - return _swift_dispatch_source_type_write() + @available(OSX 10.10, iOS 8.0, *) + public static let userInitiated = DispatchQoS(qosClass: .userInitiated, relativePriority: 0) + + @available(OSX 10.10, iOS 8.0, *) + public static let userInteractive = DispatchQoS(qosClass: .userInteractive, relativePriority: 0) + + public static let unspecified = DispatchQoS(qosClass: .unspecified, relativePriority: 0) + + public enum QoSClass { + @available(OSX 10.10, iOS 8.0, *) + case background + + @available(OSX 10.10, iOS 8.0, *) + case utility + + @available(OSX 10.10, iOS 8.0, *) + case `default` + + @available(OSX, introduced: 10.10, deprecated: 10.10, renamed: "QoSClass.default") + @available(iOS, introduced: 8.0, deprecated: 8.0, renamed: "QoSClass.default") + @available(*, deprecated, renamed: "QoSClass.default") + static let defaultQoS = QoSClass.default + + @available(OSX 10.10, iOS 8.0, *) + case userInitiated + + @available(OSX 10.10, iOS 8.0, *) + case userInteractive + + case unspecified + + @available(OSX 10.10, iOS 8.0, *) + internal init?(qosClass: qos_class_t) { + switch qosClass { + case QOS_CLASS_BACKGROUND: self = .background + case QOS_CLASS_UTILITY: self = .utility + case QOS_CLASS_DEFAULT: self = .default + case QOS_CLASS_USER_INITIATED: self = .userInitiated + case QOS_CLASS_USER_INTERACTIVE: self = .userInteractive + case QOS_CLASS_UNSPECIFIED: self = .unspecified + default: return nil + } + } + + @available(OSX 10.10, iOS 8.0, *) + internal var rawValue: qos_class_t { + switch self { + case .background: return QOS_CLASS_BACKGROUND + case .utility: return QOS_CLASS_UTILITY + case .default: return QOS_CLASS_DEFAULT + case .userInitiated: return QOS_CLASS_USER_INITIATED + case .userInteractive: return QOS_CLASS_USER_INTERACTIVE + case .unspecified: return QOS_CLASS_UNSPECIFIED + } + } + } + + public init(qosClass: QoSClass, relativePriority: Int) { + self.qosClass = qosClass + self.relativePriority = relativePriority + } } -@warn_unused_result -@_silgen_name("_swift_dispatch_source_type_DATA_ADD") -internal func _swift_dispatch_source_type_data_add() -> dispatch_source_type_t +public func ==(a: DispatchQoS, b: DispatchQoS) -> Bool { + return a.qosClass == b.qosClass && a.relativePriority == b.relativePriority +} -@warn_unused_result -@_silgen_name("_swift_dispatch_source_type_DATA_OR") -internal func _swift_dispatch_source_type_data_or() -> dispatch_source_type_t +/// -@warn_unused_result -@_silgen_name("_swift_dispatch_source_type_PROC") -internal func _swift_dispatch_source_type_proc() -> dispatch_source_type_t +public enum DispatchTimeoutResult { + case Success + case TimedOut +} -@warn_unused_result -@_silgen_name("_swift_dispatch_source_type_READ") -internal func _swift_dispatch_source_type_read() -> dispatch_source_type_t +/// dispatch_group -@warn_unused_result -@_silgen_name("_swift_dispatch_source_type_SIGNAL") -internal func _swift_dispatch_source_type_signal() -> dispatch_source_type_t +public extension DispatchGroup { + public func notify(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], queue: DispatchQueue, execute work: @convention(block) () -> ()) { + if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { + let item = DispatchWorkItem(qos: qos, flags: flags, block: work) + __dispatch_group_notify(self, queue, item._block) + } else { + __dispatch_group_notify(self, queue, work) + } + } -@warn_unused_result -@_silgen_name("_swift_dispatch_source_type_TIMER") -internal func _swift_dispatch_source_type_timer() -> dispatch_source_type_t + @available(OSX 10.10, iOS 8.0, *) + public func notify(queue: DispatchQueue, work: DispatchWorkItem) { + __dispatch_group_notify(self, queue, work._block) + } -@warn_unused_result -@_silgen_name("_swift_dispatch_source_type_VNODE") -internal func _swift_dispatch_source_type_vnode() -> dispatch_source_type_t + public func wait() { + _ = __dispatch_group_wait(self, DispatchTime.distantFuture.rawValue) + } -@warn_unused_result -@_silgen_name("_swift_dispatch_source_type_WRITE") -internal func _swift_dispatch_source_type_write() -> dispatch_source_type_t + public func wait(timeout: DispatchTime) -> DispatchTimeoutResult { + return __dispatch_group_wait(self, timeout.rawValue) == 0 ? .Success : .TimedOut + } -// dispatch/time.h -// DISPATCH_TIME_NOW: ok -// DISPATCH_TIME_FOREVER: ok + public func wait(wallTimeout timeout: DispatchWallTime) -> DispatchTimeoutResult { + return __dispatch_group_wait(self, timeout.rawValue) == 0 ? .Success : .TimedOut + } +} + +public extension DispatchGroup { + @available(*, deprecated, renamed: "DispatchGroup.wait(self:wallTimeout:)") + public func wait(walltime timeout: DispatchWallTime) -> Int { + switch wait(wallTimeout: timeout) { + case .Success: return 0 + case .TimedOut: return Int(KERN_OPERATION_TIMED_OUT) + } + } +} + +/// dispatch_semaphore + +public extension DispatchSemaphore { + @discardableResult + public func signal() -> Int { + return __dispatch_semaphore_signal(self) + } + + public func wait() { + _ = __dispatch_semaphore_wait(self, DispatchTime.distantFuture.rawValue) + } + + public func wait(timeout: DispatchTime) -> DispatchTimeoutResult { + return __dispatch_semaphore_wait(self, timeout.rawValue) == 0 ? .Success : .TimedOut + } + + public func wait(wallTimeout: DispatchWallTime) -> DispatchTimeoutResult { + return __dispatch_semaphore_wait(self, wallTimeout.rawValue) == 0 ? .Success : .TimedOut + } +} + +public extension DispatchSemaphore { + @available(*, deprecated, renamed: "DispatchSemaphore.wait(self:wallTimeout:)") + public func wait(walltime timeout: DispatchWalltime) -> Int { + switch wait(wallTimeout: timeout) { + case .Success: return 0 + case .TimedOut: return Int(KERN_OPERATION_TIMED_OUT) + } + } +} diff --git a/src/swift/IO.swift b/src/swift/IO.swift new file mode 100644 index 000000000..049f54f3c --- /dev/null +++ b/src/swift/IO.swift @@ -0,0 +1,127 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +public extension DispatchIO { + + public enum StreamType : UInt { + case stream = 0 + case random = 1 + } + + public struct CloseFlags : OptionSet, RawRepresentable { + public let rawValue: UInt + public init(rawValue: UInt) { self.rawValue = rawValue } + + public static let stop = CloseFlags(rawValue: 1) + } + + public struct IntervalFlags : OptionSet, RawRepresentable { + public let rawValue: UInt + public init(rawValue: UInt) { self.rawValue = rawValue } + public init(nilLiteral: ()) { self.rawValue = 0 } + + public static let strictInterval = IntervalFlags(rawValue: 1) + } + + public class func read(fromFileDescriptor: Int32, maxLength: Int, runningHandlerOn queue: DispatchQueue, handler: (data: DispatchData, error: Int32) -> Void) { + __dispatch_read(fromFileDescriptor, maxLength, queue) { (data: __DispatchData, error: Int32) in + handler(data: DispatchData(data: data), error: error) + } + } + + public class func write(fromFileDescriptor: Int32, data: DispatchData, runningHandlerOn queue: DispatchQueue, handler: (data: DispatchData?, error: Int32) -> Void) { + __dispatch_write(fromFileDescriptor, data as __DispatchData, queue) { (data: __DispatchData?, error: Int32) in + handler(data: data.flatMap { DispatchData(data: $0) }, error: error) + } + } + + public convenience init( + type: StreamType, + fileDescriptor: Int32, + queue: DispatchQueue, + cleanupHandler: (error: Int32) -> Void) + { + self.init(__type: type.rawValue, fd: fileDescriptor, queue: queue, handler: cleanupHandler) + } + + public convenience init( + type: StreamType, + path: UnsafePointer, + oflag: Int32, + mode: mode_t, + queue: DispatchQueue, + cleanupHandler: (error: Int32) -> Void) + { + self.init(__type: type.rawValue, path: path, oflag: oflag, mode: mode, queue: queue, handler: cleanupHandler) + } + + public convenience init( + type: StreamType, + io: DispatchIO, + queue: DispatchQueue, + cleanupHandler: (error: Int32) -> Void) + { + self.init(__type: type.rawValue, io: io, queue: queue, handler: cleanupHandler) + } + + public func read(offset: off_t, length: Int, queue: DispatchQueue, ioHandler: (done: Bool, data: DispatchData?, error: Int32) -> Void) { + __dispatch_io_read(self, offset, length, queue) { (done: Bool, data: __DispatchData?, error: Int32) in + ioHandler(done: done, data: data.flatMap { DispatchData(data: $0) }, error: error) + } + } + + public func write(offset: off_t, data: DispatchData, queue: DispatchQueue, ioHandler: (done: Bool, data: DispatchData?, error: Int32) -> Void) { + __dispatch_io_write(self, offset, data as __DispatchData, queue) { (done: Bool, data: __DispatchData?, error: Int32) in + ioHandler(done: done, data: data.flatMap { DispatchData(data: $0) }, error: error) + } + } + + public func setInterval(interval: DispatchTimeInterval, flags: IntervalFlags = []) { + __dispatch_io_set_interval(self, interval.rawValue, flags.rawValue) + } + + public func close(flags: CloseFlags = []) { + __dispatch_io_close(self, flags.rawValue) + } +} + +extension DispatchIO { + @available(*, deprecated, renamed: "DispatchIO.read(fromFileDescriptor:maxLength:runningHandlerOn:handler:)") + public class func read(fd: Int32, length: Int, queue: DispatchQueue, handler: (DispatchData, Int32) -> Void) { + DispatchIO.read(fromFileDescriptor: fd, maxLength: length, runningHandlerOn: queue, handler: handler) + } + + @available(*, deprecated, renamed: "DispatchIO.write(fromFileDescriptor:data:runningHandlerOn:handler:)") + public class func write(fd: Int32, data: DispatchData, queue: DispatchQueue, handler: (DispatchData?, Int32) -> Void) { + DispatchIO.write(fromFileDescriptor: fd, data: data, runningHandlerOn: queue, handler: handler) + } + + @available(*, deprecated, renamed: "DispatchIO.barrier(self:execute:)") + public func withBarrier(barrier work: () -> ()) { + barrier(execute: work) + } + + @available(*, deprecated, renamed: "DispatchIO.setLimit(self:highWater:)") + public func setHighWater(highWater: Int) { + setLimit(highWater: highWater) + } + + @available(*, deprecated, renamed: "DispatchIO.setLimit(self:lowWater:)") + public func setLowWater(lowWater: Int) { + setLimit(lowWater: lowWater) + } + + @available(*, deprecated, renamed: "DispatchIO.setInterval(self:interval:flags:)") + public func setInterval(interval: UInt64, flags: IntervalFlags) { + setInterval(interval: .nanoseconds(Int(interval)), flags: flags) + } +} diff --git a/src/swift/Private.swift b/src/swift/Private.swift new file mode 100644 index 000000000..3a0cdb630 --- /dev/null +++ b/src/swift/Private.swift @@ -0,0 +1,472 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// Redeclarations of all SwiftPrivate functions with appropriate markup. + +@available(*, unavailable, renamed:"DispatchQueue.init(label:attributes:target:)") +public func dispatch_queue_create(_ label: UnsafePointer?, _ attr: __OS_dispatch_queue_attr?) -> DispatchQueue +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.init(label:attributes:target:)") +public func dispatch_queue_create_with_target(_ label: UnsafePointer?, _ attr: __OS_dispatch_queue_attr?, _ queue: DispatchQueue?) -> DispatchQueue +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchIO.init(type:fileDescriptor:queue:cleanupHandler:)") +public func dispatch_io_create(_ type: UInt, _ fd: Int32, _ queue: DispatchQueue, _ cleanup_handler: (Int32) -> Void) -> DispatchIO +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchIO.init(type:path:oflag:mode:queue:cleanupHandler:)") +public func dispatch_io_create_with_path(_ type: UInt, _ path: UnsafePointer, _ oflag: Int32, _ mode: mode_t, _ queue: DispatchQueue, _ cleanup_handler: (Int32) -> Void) -> DispatchIO +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchIO.init(type:io:queue:cleanupHandler:)") +public func dispatch_io_create_with_io(_ type: UInt, _ io: DispatchIO, _ queue: DispatchQueue, _ cleanup_handler: (Int32) -> Void) -> DispatchIO +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchIO.read(fileDescriptor:length:queue:handler:)") +public func dispatch_read(_ fd: Int32, _ length: Int, _ queue: DispatchQueue, _ handler: (__DispatchData, Int32) -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchIO.read(self:offset:length:queue:ioHandler:)") +func dispatch_io_read(_ channel: DispatchIO, _ offset: off_t, _ length: Int, _ queue: DispatchQueue, _ io_handler: (Bool, __DispatchData?, Int32) -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchIO.write(self:offset:data:queue:ioHandler:)") +func dispatch_io_write(_ channel: DispatchIO, _ offset: off_t, _ data: __DispatchData, _ queue: DispatchQueue, _ io_handler: (Bool, __DispatchData?, Int32) -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchIO.write(fileDescriptor:data:queue:handler:)") +func dispatch_write(_ fd: Int32, _ data: __DispatchData, _ queue: DispatchQueue, _ handler: (__DispatchData?, Int32) -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchData.init(bytes:)") +public func dispatch_data_create(_ buffer: UnsafePointer, _ size: Int, _ queue: DispatchQueue?, _ destructor: (() -> Void)?) -> __DispatchData +{ + fatalError() +} + +@available(*, unavailable, renamed:"getter:DispatchData.count(self:)") +public func dispatch_data_get_size(_ data: __DispatchData) -> Int +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchData.withUnsafeBytes(self:body:)") +public func dispatch_data_create_map(_ data: __DispatchData, _ buffer_ptr: UnsafeMutablePointer?>?, _ size_ptr: UnsafeMutablePointer?) -> __DispatchData +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchData.append(self:_:)") +public func dispatch_data_create_concat(_ data1: __DispatchData, _ data2: __DispatchData) -> __DispatchData +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchData.subdata(self:in:)") +public func dispatch_data_create_subrange(_ data: __DispatchData, _ offset: Int, _ length: Int) -> __DispatchData +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchData.enumerateBytes(self:block:)") +public func dispatch_data_apply(_ data: __DispatchData, _ applier: (__DispatchData, Int, UnsafePointer, Int) -> Bool) -> Bool +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchData.region(self:location:)") +public func dispatch_data_copy_region(_ data: __DispatchData, _ location: Int, _ offset_ptr: UnsafeMutablePointer) -> __DispatchData +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.asynchronously(self:group:qos:flags:execute:)") +public func dispatch_group_async(_ group: DispatchGroup, _ queue: DispatchQueue, _ block: () -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed: "DispatchGroup.notify(self:qos:flags:queue:execute:)") +public func dispatch_group_notify(_ group: DispatchGroup, _ queue: DispatchQueue, _ block: () -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchGroup.wait(self:timeout:)") +public func dispatch_group_wait(_ group: DispatchGroup, _ timeout: dispatch_time_t) -> Int +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchIO.close(self:flags:)") +public func dispatch_io_close(_ channel: DispatchIO, _ flags: UInt) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchIO.setInterval(self:interval:flags:)") +public func dispatch_io_set_interval(_ channel: DispatchIO, _ interval: UInt64, _ flags: UInt) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.apply(attributes:iterations:execute:)") +public func dispatch_apply(_ iterations: Int, _ queue: DispatchQueue, _ block: @noescape (Int) -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.asynchronously(self:execute:)") +public func dispatch_async(_ queue: DispatchQueue, _ block: () -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.global(attributes:)") +public func dispatch_get_global_queue(_ identifier: Int, _ flags: UInt) -> DispatchQueue +{ + fatalError() +} + +@available(*, unavailable, renamed: "DispatchQueue.main") +public func dispatch_get_main_queue() -> DispatchQueue +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueueAttributes.initiallyInactive") +public func dispatch_queue_attr_make_initially_inactive(_ attr: __OS_dispatch_queue_attr?) -> __OS_dispatch_queue_attr +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueueAttributes.autoreleaseWorkItem") +public func dispatch_queue_attr_make_with_autorelease_frequency(_ attr: __OS_dispatch_queue_attr?, _ frequency: __dispatch_autorelease_frequency_t) -> __OS_dispatch_queue_attr +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueueAttributes.qosUserInitiated") +public func dispatch_queue_attr_make_with_qos_class(_ attr: __OS_dispatch_queue_attr?, _ qos_class: qos_class_t, _ relative_priority: Int32) -> __OS_dispatch_queue_attr +{ + fatalError() +} + +@available(*, unavailable, renamed:"getter:DispatchQueue.label(self:)") +public func dispatch_queue_get_label(_ queue: DispatchQueue?) -> UnsafePointer +{ + fatalError() +} + +@available(*, unavailable, renamed:"getter:DispatchQueue.qos(self:)") +public func dispatch_queue_get_qos_class(_ queue: DispatchQueue, _ relative_priority_ptr: UnsafeMutablePointer?) -> qos_class_t +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.after(self:when:execute:)") +public func dispatch_after(_ when: dispatch_time_t, _ queue: DispatchQueue, _ block: () -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.asynchronously(self:group:qos:flags:execute:)") +public func dispatch_barrier_async(_ queue: DispatchQueue, _ block: () -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.synchronously(self:flags:execute:)") +public func dispatch_barrier_sync(_ queue: DispatchQueue, _ block: @noescape () -> Void) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.setSpecific(self:key:value:)") +public func dispatch_queue_set_specific(_ queue: DispatchQueue, _ key: UnsafePointer, _ context: UnsafeMutablePointer?, _ destructor: (@convention(c) (UnsafeMutablePointer?) -> Void)?) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.getSpecific(self:key:)") +public func dispatch_queue_get_specific(_ queue: DispatchQueue, _ key: UnsafePointer) -> UnsafeMutablePointer? +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchQueue.getSpecific(key:)") +public func dispatch_get_specific(_ key: UnsafePointer) -> UnsafeMutablePointer? +{ + fatalError() +} + +@available(*, unavailable, renamed:"dispatchPrecondition(_:)") +public func dispatch_assert_queue(_ queue: DispatchQueue) +{ + fatalError() +} + +@available(*, unavailable, renamed:"dispatchPrecondition(_:)") +public func dispatch_assert_queue_barrier(_ queue: DispatchQueue) +{ + fatalError() +} + +@available(*, unavailable, renamed:"dispatchPrecondition(_:)") +public func dispatch_assert_queue_not(_ queue: DispatchQueue) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchSemaphore.wait(self:timeout:)") +public func dispatch_semaphore_wait(_ dsema: DispatchSemaphore, _ timeout: dispatch_time_t) -> Int +{ + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSemaphore.signal(self:)") +public func dispatch_semaphore_signal(_ dsema: DispatchSemaphore) -> Int +{ + fatalError() +} + +@available(*, unavailable, message:"Use DispatchSource class methods") +public func dispatch_source_create(_ type: __dispatch_source_type_t, _ handle: UInt, _ mask: UInt, _ queue: DispatchQueue?) -> DispatchSource +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchSource.setEventHandler(self:handler:)") +public func dispatch_source_set_event_handler(_ source: DispatchSource, _ handler: (() -> Void)?) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchSource.setCancelHandler(self:handler:)") +public func dispatch_source_set_cancel_handler(_ source: DispatchSource, _ handler: (() -> Void)?) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchSource.cancel(self:)") +public func dispatch_source_cancel(_ source: DispatchSource) +{ + fatalError() +} + +@available(*, unavailable, renamed:"getter:DispatchSource.isCancelled(self:)") +public func dispatch_source_testcancel(_ source: DispatchSource) -> Int +{ + fatalError() +} + +@available(*, unavailable, renamed:"getter:DispatchSource.handle(self:)") +public func dispatch_source_get_handle(_ source: DispatchSource) -> UInt +{ + fatalError() +} + +@available(*, unavailable, renamed:"getter:DispatchSource.mask(self:)") +public func dispatch_source_get_mask(_ source: DispatchSource) -> UInt +{ + fatalError() +} + +@available(*, unavailable, renamed:"getter:DispatchSource.data(self:)") +public func dispatch_source_get_data(_ source: DispatchSource) -> UInt +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchUserDataAdd.mergeData(self:value:)") +public func dispatch_source_merge_data(_ source: DispatchSource, _ value: UInt) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchTimerSource.setTimer(self:start:interval:leeway:)") +public func dispatch_source_set_timer(_ source: DispatchSource, _ start: dispatch_time_t, _ interval: UInt64, _ leeway: UInt64) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchSource.setRegistrationHandler(self:handler:)") +public func dispatch_source_set_registration_handler(_ source: DispatchSource, _ handler: (() -> Void)?) +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchTime.now()") +public func dispatch_time(_ when: dispatch_time_t, _ delta: Int64) -> dispatch_time_t +{ + fatalError() +} + +@available(*, unavailable, renamed:"DispatchWalltime.init(time:)") +public func dispatch_walltime(_ when: UnsafePointer?, _ delta: Int64) -> dispatch_time_t +{ + fatalError() +} + +@available(*, unavailable, renamed: "DispatchQueue.GlobalAttributes.qosUserInitiated") +public var DISPATCH_QUEUE_PRIORITY_HIGH: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchQueue.GlobalAttributes.qosDefault") +public var DISPATCH_QUEUE_PRIORITY_DEFAULT: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchQueue.GlobalAttributes.qosUtility") +public var DISPATCH_QUEUE_PRIORITY_LOW: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchQueue.GlobalAttributes.qosBackground") +public var DISPATCH_QUEUE_PRIORITY_BACKGROUND: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchIO.StreamType.stream") +public var DISPATCH_IO_STREAM: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchIO.StreamType.random") +public var DISPATCH_IO_RANDOM: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchIO.CloseFlags.stop") +public var DISPATCH_IO_STOP: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchIO.IntervalFlags.strictInterval") +public var DISPATCH_IO_STRICT_INTERVAL: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.MachSendEvent.dead") +public var DISPATCH_MACH_SEND_DEAD: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.MemoryPressureEvent.normal") +public var DISPATCH_MEMORYPRESSURE_NORMAL: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.MemoryPressureEvent.warning") +public var DISPATCH_MEMORYPRESSURE_WARN: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.MemoryPressureEvent.critical") +public var DISPATCH_MEMORYPRESSURE_CRITICAL: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.ProcessEvent.exit") +public var DISPATCH_PROC_EXIT: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.ProcessEvent.fork") +public var DISPATCH_PROC_FORK: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.ProcessEvent.exec") +public var DISPATCH_PROC_EXEC: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.ProcessEvent.signal") +public var DISPATCH_PROC_SIGNAL: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.TimerFlags.strict") +public var DISPATCH_TIMER_STRICT: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.FileSystemEvent.delete") +public var DISPATCH_VNODE_DELETE: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.FileSystemEvent.write") +public var DISPATCH_VNODE_WRITE: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.FileSystemEvent.extend") +public var DISPATCH_VNODE_EXTEND: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.FileSystemEvent.attrib") +public var DISPATCH_VNODE_ATTRIB: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.FileSystemEvent.link") +public var DISPATCH_VNODE_LINK: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.FileSystemEvent.rename") +public var DISPATCH_VNODE_RENAME: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.FileSystemEvent.revoke") +public var DISPATCH_VNODE_REVOKE: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchSource.FileSystemEvent.funlock") +public var DISPATCH_VNODE_FUNLOCK: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchTime.now()") +public var DISPATCH_TIME_NOW: Int { + fatalError() +} + +@available(*, unavailable, renamed: "DispatchTime.distantFuture") +public var DISPATCH_TIME_FOREVER: Int { + fatalError() +} diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift new file mode 100644 index 000000000..6f7b541e9 --- /dev/null +++ b/src/swift/Queue.swift @@ -0,0 +1,429 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// dispatch/queue.h + +public struct DispatchQueueAttributes : OptionSet { + public let rawValue: UInt64 + public init(rawValue: UInt64) { self.rawValue = rawValue } + + public static let serial = DispatchQueueAttributes(rawValue: 0<<0) + public static let concurrent = DispatchQueueAttributes(rawValue: 1<<1) + + @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) + public static let initiallyInactive = DispatchQueueAttributes(rawValue: 1<<2) + + @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) + public static let autoreleaseInherit = DispatchQueueAttributes(rawValue: 1<<3) + + @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) + public static let autoreleaseWorkItem = DispatchQueueAttributes(rawValue: 1<<4) + + @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) + public static let autoreleaseNever = DispatchQueueAttributes(rawValue: 1<<5) + + @available(OSX 10.10, iOS 8.0, *) + public static let qosUserInteractive = DispatchQueueAttributes(rawValue: 1<<6) + + @available(OSX 10.10, iOS 8.0, *) + public static let qosUserInitiated = DispatchQueueAttributes(rawValue: 1<<7) + + @available(OSX 10.10, iOS 8.0, *) + public static let qosDefault = DispatchQueueAttributes(rawValue: 1<<8) + + @available(OSX 10.10, iOS 8.0, *) + public static let qosUtility = DispatchQueueAttributes(rawValue: 1<<9) + + @available(OSX 10.10, iOS 8.0, *) + public static let qosBackground = DispatchQueueAttributes(rawValue: 1<<10) + + @available(*, deprecated, message: ".noQoS has no effect, it should not be used") + public static let noQoS = DispatchQueueAttributes(rawValue: 1<<11) + + private var attr: __OS_dispatch_queue_attr? { + var attr: __OS_dispatch_queue_attr? + + if self.contains(.concurrent) { + attr = _swift_dispatch_queue_concurrent() + } + if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) { + if self.contains(.initiallyInactive) { + attr = __dispatch_queue_attr_make_initially_inactive(attr) + } + if self.contains(.autoreleaseWorkItem) { + // DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM + attr = __dispatch_queue_attr_make_with_autorelease_frequency(attr, __dispatch_autorelease_frequency_t(1)) + } else if self.contains(.autoreleaseInherit) { + // DISPATCH_AUTORELEASE_FREQUENCY_INHERIT + attr = __dispatch_queue_attr_make_with_autorelease_frequency(attr, __dispatch_autorelease_frequency_t(0)) + } else if self.contains(.autoreleaseNever) { + // DISPATCH_AUTORELEASE_FREQUENCY_NEVER + attr = __dispatch_queue_attr_make_with_autorelease_frequency(attr, __dispatch_autorelease_frequency_t(2)) + } + } + if #available(OSX 10.10, iOS 8.0, *) { + if self.contains(.qosUserInteractive) { + attr = __dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_USER_INTERACTIVE, 0) + } else if self.contains(.qosUserInitiated) { + attr = __dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_USER_INITIATED, 0) + } else if self.contains(.qosDefault) { + attr = __dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_DEFAULT, 0) + } else if self.contains(.qosUtility) { + attr = __dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_UTILITY, 0) + } else if self.contains(.qosBackground) { + attr = __dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_BACKGROUND, 0) + } + } + return attr + } +} + + +public final class DispatchSpecificKey { + public init() {} +} + +internal class _DispatchSpecificValue { + internal let value: T + internal init(value: T) { self.value = value } +} + +public extension DispatchQueue { + + public struct GlobalAttributes : OptionSet { + public let rawValue: UInt64 + public init(rawValue: UInt64) { self.rawValue = rawValue } + + @available(OSX 10.10, iOS 8.0, *) + public static let qosUserInteractive = GlobalAttributes(rawValue: 1<<0) + + @available(OSX 10.10, iOS 8.0, *) + public static let qosUserInitiated = GlobalAttributes(rawValue: 1<<1) + + @available(OSX 10.10, iOS 8.0, *) + public static let qosDefault = GlobalAttributes(rawValue: 1<<2) + + @available(OSX 10.10, iOS 8.0, *) + public static let qosUtility = GlobalAttributes(rawValue: 1<<3) + + @available(OSX 10.10, iOS 8.0, *) + public static let qosBackground = GlobalAttributes(rawValue: 1<<4) + + // Avoid using our own deprecated constants here by declaring + // non-deprecated constants and then basing the public ones on those. + internal static let _priorityHigh = GlobalAttributes(rawValue: 1<<5) + internal static let _priorityDefault = GlobalAttributes(rawValue: 1<<6) + internal static let _priorityLow = GlobalAttributes(rawValue: 1<<7) + internal static let _priorityBackground = GlobalAttributes(rawValue: 1<<8) + + @available(OSX, deprecated: 10.10, message: "Use qos attributes instead") + @available(*, deprecated: 8.0, message: "Use qos attributes instead") + public static let priorityHigh = _priorityHigh + + @available(OSX, deprecated: 10.10, message: "Use qos attributes instead") + @available(*, deprecated: 8.0, message: "Use qos attributes instead") + public static let priorityDefault = _priorityDefault + + @available(OSX, deprecated: 10.10, message: "Use qos attributes instead") + @available(*, deprecated: 8.0, message: "Use qos attributes instead") + public static let priorityLow = _priorityLow + + @available(OSX, deprecated: 10.10, message: "Use qos attributes instead") + @available(*, deprecated: 8.0, message: "Use qos attributes instead") + public static let priorityBackground = _priorityBackground + + internal var _translatedValue: Int { + if #available(OSX 10.10, iOS 8.0, *) { + if self.contains(.qosUserInteractive) { return Int(QOS_CLASS_USER_INTERACTIVE.rawValue) } + else if self.contains(.qosUserInitiated) { return Int(QOS_CLASS_USER_INITIATED.rawValue) } + else if self.contains(.qosDefault) { return Int(QOS_CLASS_DEFAULT.rawValue) } + else if self.contains(.qosUtility) { return Int(QOS_CLASS_UTILITY.rawValue) } + else { return Int(QOS_CLASS_BACKGROUND.rawValue) } + } + if self.contains(._priorityHigh) { return 2 } // DISPATCH_QUEUE_PRIORITY_HIGH + else if self.contains(._priorityDefault) { return 0 } // DISPATCH_QUEUE_PRIORITY_DEFAULT + else if self.contains(._priorityLow) { return -2 } // // DISPATCH_QUEUE_PRIORITY_LOW + else if self.contains(._priorityBackground) { return Int(Int16.min) } // // DISPATCH_QUEUE_PRIORITY_BACKGROUND + return 0 + } + } + + public class func concurrentPerform(iterations: Int, execute work: @noescape (Int) -> Void) { + _swift_dispatch_apply_current(iterations, work) + } + + public class var main: DispatchQueue { + return _swift_dispatch_get_main_queue() + } + + public class func global(attributes: GlobalAttributes = []) -> DispatchQueue { + return __dispatch_get_global_queue(attributes._translatedValue, 0) + } + + public class func getSpecific(key: DispatchSpecificKey) -> T? { + let k = Unmanaged.passUnretained(key).toOpaque() + if let p = __dispatch_get_specific(k) { + let v = Unmanaged<_DispatchSpecificValue> + .fromOpaque(p) + .takeUnretainedValue() + return v.value + } + return nil + } + + public convenience init( + label: String, + attributes: DispatchQueueAttributes = .serial, + target: DispatchQueue? = nil) + { + if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) { + self.init(__label: label, attr: attributes.attr, queue: target) + } else { + self.init(__label: label, attr: attributes.attr) + if let tq = target { self.setTarget(queue: tq) } + } + } + + public var label: String { + return String(validatingUTF8: __dispatch_queue_get_label(self))! + } + + @available(OSX 10.10, iOS 8.0, *) + public func sync(execute workItem: DispatchWorkItem) { + // _swift_dispatch_sync preserves the @convention(block) for + // work item blocks. + _swift_dispatch_sync(self, workItem._block) + } + + @available(OSX 10.10, iOS 8.0, *) + public func async(execute workItem: DispatchWorkItem) { + // _swift_dispatch_{group,}_async preserves the @convention(block) + // for work item blocks. + if let g = workItem._group { + _swift_dispatch_group_async(g, self, workItem._block) + } else { + _swift_dispatch_async(self, workItem._block) + } + } + + public func async(group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { + if group == nil && qos == .unspecified && flags.isEmpty { + // Fast-path route for the most common API usage + __dispatch_async(self, work) + return + } + + if #available(OSX 10.10, iOS 8.0, *), (qos != .unspecified || !flags.isEmpty) { + let workItem = DispatchWorkItem(qos: qos, flags: flags, block: work) + if let g = group { + _swift_dispatch_group_async(g, self, workItem._block) + } else { + _swift_dispatch_async(self, workItem._block) + } + } else { + if let g = group { + __dispatch_group_async(g, self, work) + } else { + __dispatch_async(self, work) + } + } + } + + private func _syncBarrier(block: @noescape () -> ()) { + __dispatch_barrier_sync(self, block) + } + + private func _syncHelper( + fn: (@noescape () -> ()) -> (), + execute work: @noescape () throws -> T, + rescue: ((ErrorProtocol) throws -> (T))) rethrows -> T + { + var result: T? + var error: ErrorProtocol? + fn { + do { + result = try work() + } catch let e { + error = e + } + } + if let e = error { + return try rescue(e) + } else { + return result! + } + } + + @available(OSX 10.10, iOS 8.0, *) + private func _syncHelper( + fn: (DispatchWorkItem) -> (), + flags: DispatchWorkItemFlags, + execute work: @noescape () throws -> T, + rescue: ((ErrorProtocol) throws -> (T))) rethrows -> T + { + var result: T? + var error: ErrorProtocol? + let workItem = DispatchWorkItem(flags: flags, noescapeBlock: { + do { + result = try work() + } catch let e { + error = e + } + }) + fn(workItem) + if let e = error { + return try rescue(e) + } else { + return result! + } + } + + public func sync(execute work: @noescape () throws -> T) rethrows -> T { + return try self._syncHelper(fn: sync, execute: work, rescue: { throw $0 }) + } + + public func sync(flags: DispatchWorkItemFlags, execute work: @noescape () throws -> T) rethrows -> T { + if flags == .barrier { + return try self._syncHelper(fn: _syncBarrier, execute: work, rescue: { throw $0 }) + } else if #available(OSX 10.10, iOS 8.0, *), !flags.isEmpty { + return try self._syncHelper(fn: sync, flags: flags, execute: work, rescue: { throw $0 }) + } else { + return try self._syncHelper(fn: sync, execute: work, rescue: { throw $0 }) + } + } + + public func after(when: DispatchTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { + if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { + let item = DispatchWorkItem(qos: qos, flags: flags, block: work) + __dispatch_after(when.rawValue, self, item._block) + } else { + __dispatch_after(when.rawValue, self, work) + } + } + + @available(OSX 10.10, iOS 8.0, *) + public func after(when: DispatchTime, execute: DispatchWorkItem) { + __dispatch_after(when.rawValue, self, execute._block) + } + + public func after(walltime when: DispatchWallTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { + if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { + let item = DispatchWorkItem(qos: qos, flags: flags, block: work) + __dispatch_after(when.rawValue, self, item._block) + } else { + __dispatch_after(when.rawValue, self, work) + } + } + + @available(OSX 10.10, iOS 8.0, *) + public func after(walltime when: DispatchWallTime, execute: DispatchWorkItem) { + __dispatch_after(when.rawValue, self, execute._block) + } + + @available(OSX 10.10, iOS 8.0, *) + public var qos: DispatchQoS { + var relPri: Int32 = 0 + let cls = DispatchQoS.QoSClass(qosClass: __dispatch_queue_get_qos_class(self, &relPri))! + return DispatchQoS(qosClass: cls, relativePriority: Int(relPri)) + } + + public func getSpecific(key: DispatchSpecificKey) -> T? { + let k = Unmanaged.passUnretained(key).toOpaque() + if let p = __dispatch_queue_get_specific(self, k) { + let v = Unmanaged<_DispatchSpecificValue> + .fromOpaque(p) + .takeUnretainedValue() + return v.value + } + return nil + } + + public func setSpecific(key: DispatchSpecificKey, value: T) { + let v = _DispatchSpecificValue(value: value) + let k = Unmanaged.passUnretained(key).toOpaque() + let p = Unmanaged.passRetained(v).toOpaque() + __dispatch_queue_set_specific(self, k, p, _destructDispatchSpecificValue) + } +} + +extension DispatchQueue { + @available(*, deprecated, renamed: "DispatchQueue.sync(self:execute:)") + public func synchronously(execute work: @noescape () -> ()) { + sync(execute: work) + } + + @available(OSX, introduced: 10.10, deprecated: 10.12, renamed: "DispatchQueue.sync(self:execute:)") + @available(iOS, introduced: 8.0, deprecated: 10.0, renamed: "DispatchQueue.sync(self:execute:)") + @available(*, deprecated, renamed: "DispatchQueue.sync(self:execute:)") + public func synchronously(execute workItem: DispatchWorkItem) { + sync(execute: workItem) + } + + @available(OSX, introduced: 10.10, deprecated: 10.12, renamed: "DispatchQueue.async(self:execute:)") + @available(iOS, introduced: 8.0, deprecated: 10.0, renamed: "DispatchQueue.async(self:execute:)") + @available(*, deprecated, renamed: "DispatchQueue.async(self:execute:)") + public func asynchronously(execute workItem: DispatchWorkItem) { + async(execute: workItem) + } + + @available(*, deprecated, renamed: "DispatchQueue.async(self:group:qos:flags:execute:)") + public func asynchronously(group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { + async(group: group, qos: qos, flags: flags, execute: work) + } + + @available(*, deprecated, renamed: "DispatchQueue.sync(self:execute:)") + public func synchronously(execute work: @noescape () throws -> T) rethrows -> T { + return try sync(execute: work) + } + + @available(*, deprecated, renamed: "DispatchQueue.sync(self:flags:execute:)") + public func synchronously(flags: DispatchWorkItemFlags, execute work: @noescape () throws -> T) rethrows -> T { + return try sync(flags: flags, execute: work) + } + + @available(*, deprecated, renamed: "DispatchQueue.concurrentPerform(iterations:execute:)") + public func apply(applier iterations: Int, execute block: @noescape (Int) -> Void) { + DispatchQueue.concurrentPerform(iterations: iterations, execute: block) + } + + @available(*, deprecated, renamed: "DispatchQueue.setTarget(self:queue:)") + public func setTargetQueue(queue: DispatchQueue) { + self.setTarget(queue: queue) + } +} + +private func _destructDispatchSpecificValue(ptr: UnsafeMutablePointer?) { + if let p = ptr { + Unmanaged.fromOpaque(p).release() + } +} + +@_silgen_name("_swift_dispatch_queue_concurrent") +internal func _swift_dispatch_queue_concurrent() -> __OS_dispatch_queue_attr + +@_silgen_name("_swift_dispatch_get_main_queue") +internal func _swift_dispatch_get_main_queue() -> DispatchQueue + +@_silgen_name("_swift_dispatch_apply_current_root_queue") +internal func _swift_dispatch_apply_current_root_queue() -> DispatchQueue + +@_silgen_name("_swift_dispatch_async") +internal func _swift_dispatch_async(_ queue: DispatchQueue, _ block: _DispatchBlock) + +@_silgen_name("_swift_dispatch_group_async") +internal func _swift_dispatch_group_async(_ group: DispatchGroup, _ queue: DispatchQueue, _ block: _DispatchBlock) + +@_silgen_name("_swift_dispatch_sync") +internal func _swift_dispatch_sync(_ queue: DispatchQueue, _ block: _DispatchBlock) + +@_silgen_name("_swift_dispatch_apply_current") +internal func _swift_dispatch_apply_current(_ iterations: Int, _ block: @convention(block) @noescape (Int) -> Void) diff --git a/src/swift/Source.swift b/src/swift/Source.swift new file mode 100644 index 000000000..6ea3960f0 --- /dev/null +++ b/src/swift/Source.swift @@ -0,0 +1,389 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// import Foundation + +public extension DispatchSourceType { + typealias DispatchSourceHandler = @convention(block) () -> Void + + public func setEventHandler(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], handler: DispatchSourceHandler?) { + if #available(OSX 10.10, iOS 8.0, *), let h = handler where qos != .unspecified || !flags.isEmpty { + let item = DispatchWorkItem(qos: qos, flags: flags, block: h) + __dispatch_source_set_event_handler(self as! DispatchSource, item._block) + } else { + __dispatch_source_set_event_handler(self as! DispatchSource, handler) + } + } + + @available(OSX 10.10, iOS 8.0, *) + public func setEventHandler(handler: DispatchWorkItem) { + __dispatch_source_set_event_handler(self as! DispatchSource, handler._block) + } + + public func setCancelHandler(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], handler: DispatchSourceHandler?) { + if #available(OSX 10.10, iOS 8.0, *), let h = handler where qos != .unspecified || !flags.isEmpty { + let item = DispatchWorkItem(qos: qos, flags: flags, block: h) + __dispatch_source_set_cancel_handler(self as! DispatchSource, item._block) + } else { + __dispatch_source_set_cancel_handler(self as! DispatchSource, handler) + } + } + + @available(OSX 10.10, iOS 8.0, *) + public func setCancelHandler(handler: DispatchWorkItem) { + __dispatch_source_set_cancel_handler(self as! DispatchSource, handler._block) + } + + public func setRegistrationHandler(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], handler: DispatchSourceHandler?) { + if #available(OSX 10.10, iOS 8.0, *), let h = handler where qos != .unspecified || !flags.isEmpty { + let item = DispatchWorkItem(qos: qos, flags: flags, block: h) + __dispatch_source_set_registration_handler(self as! DispatchSource, item._block) + } else { + __dispatch_source_set_registration_handler(self as! DispatchSource, handler) + } + } + + @available(OSX 10.10, iOS 8.0, *) + public func setRegistrationHandler(handler: DispatchWorkItem) { + __dispatch_source_set_registration_handler(self as! DispatchSource, handler._block) + } + + @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) + public func activate() { + (self as! DispatchSource).activate() + } + + public func cancel() { + __dispatch_source_cancel(self as! DispatchSource) + } + + public func resume() { + (self as! DispatchSource).resume() + } + + public func suspend() { + (self as! DispatchSource).suspend() + } + + public var handle: UInt { + return __dispatch_source_get_handle(self as! DispatchSource) + } + + public var mask: UInt { + return __dispatch_source_get_mask(self as! DispatchSource) + } + + public var data: UInt { + return __dispatch_source_get_data(self as! DispatchSource) + } + + public var isCancelled: Bool { + return __dispatch_source_testcancel(self as! DispatchSource) != 0 + } +} + +public extension DispatchSource { + public struct MachSendEvent : OptionSet, RawRepresentable { + public let rawValue: UInt + public init(rawValue: UInt) { self.rawValue = rawValue } + + public static let dead = MachSendEvent(rawValue: 0x1) + } + + public struct MemoryPressureEvent : OptionSet, RawRepresentable { + public let rawValue: UInt + public init(rawValue: UInt) { self.rawValue = rawValue } + + public static let normal = MemoryPressureEvent(rawValue: 0x1) + public static let warning = MemoryPressureEvent(rawValue: 0x2) + public static let critical = MemoryPressureEvent(rawValue: 0x4) + public static let all: MemoryPressureEvent = [.normal, .warning, .critical] + } + + public struct ProcessEvent : OptionSet, RawRepresentable { + public let rawValue: UInt + public init(rawValue: UInt) { self.rawValue = rawValue } + + public static let exit = ProcessEvent(rawValue: 0x80000000) + public static let fork = ProcessEvent(rawValue: 0x40000000) + public static let exec = ProcessEvent(rawValue: 0x20000000) + public static let signal = ProcessEvent(rawValue: 0x08000000) + public static let all: ProcessEvent = [.exit, .fork, .exec, .signal] + } + + public struct TimerFlags : OptionSet, RawRepresentable { + public let rawValue: UInt + public init(rawValue: UInt) { self.rawValue = rawValue } + + public static let strict = TimerFlags(rawValue: 1) + } + + public struct FileSystemEvent : OptionSet, RawRepresentable { + public let rawValue: UInt + public init(rawValue: UInt) { self.rawValue = rawValue } + + public static let delete = FileSystemEvent(rawValue: 0x1) + public static let write = FileSystemEvent(rawValue: 0x2) + public static let extend = FileSystemEvent(rawValue: 0x4) + public static let attrib = FileSystemEvent(rawValue: 0x8) + public static let link = FileSystemEvent(rawValue: 0x10) + public static let rename = FileSystemEvent(rawValue: 0x20) + public static let revoke = FileSystemEvent(rawValue: 0x40) + public static let funlock = FileSystemEvent(rawValue: 0x100) + + public static let all: FileSystemEvent = [ + .delete, .write, .extend, .attrib, .link, .rename, .revoke] + } + + public class func machSend(port: mach_port_t, eventMask: MachSendEvent, queue: DispatchQueue? = nil) -> DispatchSourceMachSend { + return __dispatch_source_create( + _swift_dispatch_source_type_mach_send(), UInt(port), eventMask.rawValue, queue) as DispatchSourceMachSend + } + + public class func machReceive(port: mach_port_t, queue: DispatchQueue? = nil) -> DispatchSourceMachReceive { + return __dispatch_source_create( + _swift_dispatch_source_type_mach_recv(), UInt(port), 0, queue) as DispatchSourceMachReceive + } + + public class func memoryPressure(eventMask: MemoryPressureEvent, queue: DispatchQueue? = nil) -> DispatchSourceMemoryPressure { + return __dispatch_source_create( + _swift_dispatch_source_type_memorypressure(), 0, eventMask.rawValue, queue) as DispatchSourceMemoryPressure + } + + public class func process(identifier: pid_t, eventMask: ProcessEvent, queue: DispatchQueue? = nil) -> DispatchSourceProcess { + return __dispatch_source_create( + _swift_dispatch_source_type_proc(), UInt(identifier), eventMask.rawValue, queue) as DispatchSourceProcess + } + + public class func read(fileDescriptor: Int32, queue: DispatchQueue? = nil) -> DispatchSourceRead { + return __dispatch_source_create( + _swift_dispatch_source_type_read(), UInt(fileDescriptor), 0, queue) as DispatchSourceRead + } + + public class func signal(signal: Int32, queue: DispatchQueue? = nil) -> DispatchSourceSignal { + return __dispatch_source_create( + _swift_dispatch_source_type_read(), UInt(signal), 0, queue) as DispatchSourceSignal + } + + public class func timer(flags: TimerFlags = [], queue: DispatchQueue? = nil) -> DispatchSourceTimer { + return __dispatch_source_create(_swift_dispatch_source_type_timer(), 0, flags.rawValue, queue) as DispatchSourceTimer + } + + public class func userDataAdd(queue: DispatchQueue? = nil) -> DispatchSourceUserDataAdd { + return __dispatch_source_create(_swift_dispatch_source_type_data_add(), 0, 0, queue) as DispatchSourceUserDataAdd + } + + public class func userDataOr(queue: DispatchQueue? = nil) -> DispatchSourceUserDataOr { + return __dispatch_source_create(_swift_dispatch_source_type_data_or(), 0, 0, queue) as DispatchSourceUserDataOr + } + + public class func fileSystemObject(fileDescriptor: Int32, eventMask: FileSystemEvent, queue: DispatchQueue? = nil) -> DispatchSourceFileSystemObject { + return __dispatch_source_create( + _swift_dispatch_source_type_vnode(), UInt(fileDescriptor), eventMask.rawValue, queue) as DispatchSourceFileSystemObject + } + + public class func write(fileDescriptor: Int32, queue: DispatchQueue? = nil) -> DispatchSourceWrite { + return __dispatch_source_create( + _swift_dispatch_source_type_write(), UInt(fileDescriptor), 0, queue) as DispatchSourceWrite + } +} + +public extension DispatchSourceMachSend { + public var handle: mach_port_t { + return mach_port_t(__dispatch_source_get_handle(self as! DispatchSource)) + } + + public var data: DispatchSource.MachSendEvent { + let data = __dispatch_source_get_data(self as! DispatchSource) + return DispatchSource.MachSendEvent(rawValue: data) + } + + public var mask: DispatchSource.MachSendEvent { + let mask = __dispatch_source_get_mask(self as! DispatchSource) + return DispatchSource.MachSendEvent(rawValue: mask) + } +} + +public extension DispatchSourceMachReceive { + public var handle: mach_port_t { + return mach_port_t(__dispatch_source_get_handle(self as! DispatchSource)) + } +} + +public extension DispatchSourceMemoryPressure { + public var data: DispatchSource.MemoryPressureEvent { + let data = __dispatch_source_get_data(self as! DispatchSource) + return DispatchSource.MemoryPressureEvent(rawValue: data) + } + + public var mask: DispatchSource.MemoryPressureEvent { + let mask = __dispatch_source_get_mask(self as! DispatchSource) + return DispatchSource.MemoryPressureEvent(rawValue: mask) + } +} + +public extension DispatchSourceProcess { + public var handle: pid_t { + return pid_t(__dispatch_source_get_handle(self as! DispatchSource)) + } + + public var data: DispatchSource.ProcessEvent { + let data = __dispatch_source_get_data(self as! DispatchSource) + return DispatchSource.ProcessEvent(rawValue: data) + } + + public var mask: DispatchSource.ProcessEvent { + let mask = __dispatch_source_get_mask(self as! DispatchSource) + return DispatchSource.ProcessEvent(rawValue: mask) + } +} + +public extension DispatchSourceTimer { + public func scheduleOneshot(deadline: DispatchTime, leeway: DispatchTimeInterval = .nanoseconds(0)) { + __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, ~0, UInt64(leeway.rawValue)) + } + + public func scheduleOneshot(wallDeadline: DispatchWallTime, leeway: DispatchTimeInterval = .nanoseconds(0)) { + __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, ~0, UInt64(leeway.rawValue)) + } + + public func scheduleRepeating(deadline: DispatchTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .nanoseconds(0)) { + __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, interval.rawValue, UInt64(leeway.rawValue)) + } + + public func scheduleRepeating(deadline: DispatchTime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { + __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) + } + + public func scheduleRepeating(wallDeadline: DispatchWallTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .nanoseconds(0)) { + __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, interval.rawValue, UInt64(leeway.rawValue)) + } + + public func scheduleRepeating(wallDeadline: DispatchWallTime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { + __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) + } +} + +public extension DispatchSourceTimer { + @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleOneshot(self:deadline:leeway:)") + public func setTimer(start: DispatchTime, leeway: DispatchTimeInterval = .nanoseconds(0)) { + scheduleOneshot(deadline: start, leeway: leeway) + } + + @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleOneshot(self:wallDeadline:leeway:)") + public func setTimer(walltime start: DispatchWallTime, leeway: DispatchTimeInterval = .nanoseconds(0)) { + scheduleOneshot(wallDeadline: start, leeway: leeway) + } + + @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleRepeating(self:deadline:interval:leeway:)") + public func setTimer(start: DispatchTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .nanoseconds(0)) { + scheduleRepeating(deadline: start, interval: interval, leeway: leeway) + } + + @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleRepeating(self:deadline:interval:leeway:)") + public func setTimer(start: DispatchTime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { + scheduleRepeating(deadline: start, interval: interval, leeway: leeway) + } + + @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleRepeating(self:wallDeadline:interval:leeway:)") + public func setTimer(walltime start: DispatchWallTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .nanoseconds(0)) { + scheduleRepeating(wallDeadline: start, interval: interval, leeway: leeway) + } + + @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleRepeating(self:wallDeadline:interval:leeway:)") + public func setTimer(walltime start: DispatchWalltime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { + scheduleRepeating(wallDeadline: start, interval: interval, leeway: leeway) + } +} + +public extension DispatchSourceFileSystemObject { + public var handle: Int32 { + return Int32(__dispatch_source_get_handle(self as! DispatchSource)) + } + + public var data: DispatchSource.FileSystemEvent { + let data = __dispatch_source_get_data(self as! DispatchSource) + return DispatchSource.FileSystemEvent(rawValue: data) + } + + public var mask: DispatchSource.FileSystemEvent { + let data = __dispatch_source_get_mask(self as! DispatchSource) + return DispatchSource.FileSystemEvent(rawValue: data) + } +} + +public extension DispatchSourceUserDataAdd { + /// @function mergeData + /// + /// @abstract + /// Merges data into a dispatch source of type DISPATCH_SOURCE_TYPE_DATA_ADD or + /// DISPATCH_SOURCE_TYPE_DATA_OR and submits its event handler block to its + /// target queue. + /// + /// @param value + /// The value to coalesce with the pending data using a logical OR or an ADD + /// as specified by the dispatch source type. A value of zero has no effect + /// and will not result in the submission of the event handler block. + public func mergeData(value: UInt) { + __dispatch_source_merge_data(self as! DispatchSource, value) + } +} + +public extension DispatchSourceUserDataOr { + /// @function mergeData + /// + /// @abstract + /// Merges data into a dispatch source of type DISPATCH_SOURCE_TYPE_DATA_ADD or + /// DISPATCH_SOURCE_TYPE_DATA_OR and submits its event handler block to its + /// target queue. + /// + /// @param value + /// The value to coalesce with the pending data using a logical OR or an ADD + /// as specified by the dispatch source type. A value of zero has no effect + /// and will not result in the submission of the event handler block. + public func mergeData(value: UInt) { + __dispatch_source_merge_data(self as! DispatchSource, value) + } +} + +@_silgen_name("_swift_dispatch_source_type_DATA_ADD") +internal func _swift_dispatch_source_type_data_add() -> __dispatch_source_type_t + +@_silgen_name("_swift_dispatch_source_type_DATA_OR") +internal func _swift_dispatch_source_type_data_or() -> __dispatch_source_type_t + +@_silgen_name("_swift_dispatch_source_type_MACH_SEND") +internal func _swift_dispatch_source_type_mach_send() -> __dispatch_source_type_t + +@_silgen_name("_swift_dispatch_source_type_MACH_RECV") +internal func _swift_dispatch_source_type_mach_recv() -> __dispatch_source_type_t + +@_silgen_name("_swift_dispatch_source_type_MEMORYPRESSURE") +internal func _swift_dispatch_source_type_memorypressure() -> __dispatch_source_type_t + +@_silgen_name("_swift_dispatch_source_type_PROC") +internal func _swift_dispatch_source_type_proc() -> __dispatch_source_type_t + +@_silgen_name("_swift_dispatch_source_type_READ") +internal func _swift_dispatch_source_type_read() -> __dispatch_source_type_t + +@_silgen_name("_swift_dispatch_source_type_SIGNAL") +internal func _swift_dispatch_source_type_signal() -> __dispatch_source_type_t + +@_silgen_name("_swift_dispatch_source_type_TIMER") +internal func _swift_dispatch_source_type_timer() -> __dispatch_source_type_t + +@_silgen_name("_swift_dispatch_source_type_VNODE") +internal func _swift_dispatch_source_type_vnode() -> __dispatch_source_type_t + +@_silgen_name("_swift_dispatch_source_type_WRITE") +internal func _swift_dispatch_source_type_write() -> __dispatch_source_type_t diff --git a/src/swift/Time.swift b/src/swift/Time.swift new file mode 100644 index 000000000..e0b63b814 --- /dev/null +++ b/src/swift/Time.swift @@ -0,0 +1,108 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// dispatch/time.h +// DISPATCH_TIME_NOW: ok +// DISPATCH_TIME_FOREVER: ok + +public struct DispatchTime { + public let rawValue: dispatch_time_t + + public static func now() -> DispatchTime { + let t = __dispatch_time(0, 0) + return DispatchTime(rawValue: t) + } + + public static let distantFuture = DispatchTime(rawValue: ~0) + + private init(rawValue: dispatch_time_t) { + self.rawValue = rawValue + } +} + +public struct DispatchWallTime { + public let rawValue: dispatch_time_t + + public static func now() -> DispatchWallTime { + return DispatchWallTime(rawValue: __dispatch_walltime(nil, 0)) + } + + public static let distantFuture = DispatchWallTime(rawValue: ~0) + + private init(rawValue: dispatch_time_t) { + self.rawValue = rawValue + } + + public init(time: timespec) { + var t = time + self.rawValue = __dispatch_walltime(&t, 0) + } +} + +@available(*, deprecated, renamed: "DispatchWallTime") +public typealias DispatchWalltime = DispatchWallTime + +public enum DispatchTimeInterval { + case seconds(Int) + case milliseconds(Int) + case microseconds(Int) + case nanoseconds(Int) + + internal var rawValue: UInt64 { + switch self { + case .seconds(let s): return UInt64(s) * NSEC_PER_SEC + case .milliseconds(let ms): return UInt64(ms) * NSEC_PER_MSEC + case .microseconds(let us): return UInt64(us) * NSEC_PER_USEC + case .nanoseconds(let ns): return UInt64(ns) + } + } +} + +public func +(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime { + let t = __dispatch_time(time.rawValue, Int64(interval.rawValue)) + return DispatchTime(rawValue: t) +} + +public func -(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime { + let t = __dispatch_time(time.rawValue, -Int64(interval.rawValue)) + return DispatchTime(rawValue: t) +} + +public func +(time: DispatchTime, seconds: Double) -> DispatchTime { + let t = __dispatch_time(time.rawValue, Int64(seconds * Double(NSEC_PER_SEC))) + return DispatchTime(rawValue: t) +} + +public func -(time: DispatchTime, seconds: Double) -> DispatchTime { + let t = __dispatch_time(time.rawValue, Int64(-seconds * Double(NSEC_PER_SEC))) + return DispatchTime(rawValue: t) +} + +public func +(time: DispatchWallTime, interval: DispatchTimeInterval) -> DispatchWallTime { + let t = __dispatch_time(time.rawValue, Int64(interval.rawValue)) + return DispatchWallTime(rawValue: t) +} + +public func -(time: DispatchWallTime, interval: DispatchTimeInterval) -> DispatchWallTime { + let t = __dispatch_time(time.rawValue, -Int64(interval.rawValue)) + return DispatchWallTime(rawValue: t) +} + +public func +(time: DispatchWallTime, seconds: Double) -> DispatchWallTime { + let t = __dispatch_time(time.rawValue, Int64(seconds * Double(NSEC_PER_SEC))) + return DispatchWallTime(rawValue: t) +} + +public func -(time: DispatchWallTime, seconds: Double) -> DispatchWallTime { + let t = __dispatch_time(time.rawValue, Int64(-seconds * Double(NSEC_PER_SEC))) + return DispatchWallTime(rawValue: t) +} diff --git a/src/swift/swift_wrappers.c b/src/swift/swift_wrappers.c deleted file mode 100644 index 0b982b91c..000000000 --- a/src/swift/swift_wrappers.c +++ /dev/null @@ -1,47 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#include - -DISPATCH_EXPORT -dispatch_queue_attr_t -_swift_dispatch_queue_serial(void) { - return DISPATCH_QUEUE_SERIAL; -} - -DISPATCH_EXPORT -dispatch_queue_attr_t -_swift_dispatch_queue_concurrent(void) { - return DISPATCH_QUEUE_CONCURRENT; -} - -DISPATCH_EXPORT -dispatch_data_t -_swift_dispatch_data_empty(void) { - return dispatch_data_empty; -} - -#define SOURCE(t) \ - DISPATCH_EXPORT \ - dispatch_source_type_t \ - _swift_dispatch_source_type_##t(void) { \ - return DISPATCH_SOURCE_TYPE_##t; \ - } - -SOURCE(DATA_ADD) -SOURCE(DATA_OR) -SOURCE(PROC) -SOURCE(READ) -SOURCE(SIGNAL) -SOURCE(TIMER) -SOURCE(VNODE) -SOURCE(WRITE) From aee1fe5d467beedbeef38f3a4a518f366dbeb0f0 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 22 Jun 2016 09:11:27 -0600 Subject: [PATCH 12/67] add new overlay sourcefiles to Makefile.am (does not build) Signed-off-by: Daniel A. Steffen --- src/Makefile.am | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ea4a32e2b..e51d15a33 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -114,8 +114,18 @@ DTRACE_SOURCES=provider.h endif if HAVE_SWIFT -libdispatch_la_SOURCES+=swift/swift_wrappers.c -EXTRA_libdispatch_la_SOURCES+=swift/Dispatch.swift +libdispatch_la_SOURCES+=swift/Dispatch.mm +EXTRA_libdispatch_la_SOURCES+= \ + swift/Dispatch.swift \ + swift/Block.swift \ + swift/Data.swift \ + swift/Dispatch.swift \ + swift/IO.swift \ + swift/Private.swift \ + swift/Queue.swift \ + swift/Source.swift \ + swift/Time.swift + EXTRA_libdispatch_la_DEPENDENCIES+=$(abs_builddir)/Dispatch.o $(abs_builddir)/Dispatch.swiftmodule libdispatch_la_LIBADD+=$(abs_builddir)/Dispatch.o From 4af7cad3180d1608a51ac4d8def2c3be5a2554c9 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 22 Jun 2016 08:16:35 -0700 Subject: [PATCH 13/67] Merge pull request #89 from apple/das-swift3-overlay Import Swift 3 overlay from swift repo Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index f6d8638d4..f803c2ef6 100644 --- a/PATCHES +++ b/PATCHES @@ -245,3 +245,4 @@ github commits starting with 29bdc2f from [9f1e778] APPLIED rdar://26822213 [3339b81] APPLIED rdar://26822213 [4fa8d8d] APPLIED rdar://26822213 +[e922531] APPLIED rdar://26822213 From 0de9c3c15cc40dd9e700f09312a393d5e1dcb78c Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 30 Jun 2016 16:32:53 -0400 Subject: [PATCH 14/67] Mark dispatch_source APIs that are not available on Linux as unavailable Define DISPATCH_UNAVAILABLE and DISPATCH_LINUX_UNAVAILABLE macros and use them to mark dispatch_source API functions that are not available on Linux. Signed-off-by: Daniel A. Steffen --- dispatch/dispatch.h | 17 ++++++++++++++++- dispatch/source.h | 10 +++++----- os/voucher_activity_private.h | 2 +- os/voucher_private.h | 6 +++--- private/data_private.h | 2 +- private/source_private.h | 12 +++++++----- src/data.c | 4 ++++ src/init.c | 16 +++++++++------- 8 files changed, 46 insertions(+), 23 deletions(-) diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index 11034f290..62647651a 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -47,9 +47,24 @@ #include #include -#if defined(__linux__) && defined(__DISPATCH_BUILDING_SWIFT_MODULE__) +#ifdef __has_attribute +#if __has_attribute(unavailable) +#define __DISPATCH_UNAVAILABLE(msg) __attribute__((__unavailable__(msg))) +#endif +#endif +#ifndef __DISPATCH_UNAVAILABLE +#define __DISPATCH_UNAVAILABLE(msg) +#endif + +#ifdef __linux__ +#ifdef __DISPATCH_BUILDING_SWIFT_MODULE__ #include // for off_t #endif +#define DISPATCH_LINUX_UNAVAILABLE() \ + __DISPATCH_UNAVAILABLE("This interface is unavailable on linux systems") +#else +#define DISPATCH_LINUX_UNAVAILABLE() +#endif #define DISPATCH_API_VERSION 20160612 diff --git a/dispatch/source.h b/dispatch/source.h index 3c005b822..63b3ff365 100644 --- a/dispatch/source.h +++ b/dispatch/source.h @@ -101,7 +101,7 @@ DISPATCH_SOURCE_TYPE_DECL(data_or); * The mask is a mask of desired events from dispatch_source_mach_send_flags_t. */ #define DISPATCH_SOURCE_TYPE_MACH_SEND (&_dispatch_source_type_mach_send) -__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) +__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) DISPATCH_LINUX_UNAVAILABLE() DISPATCH_SOURCE_TYPE_DECL(mach_send); /*! @@ -111,7 +111,7 @@ DISPATCH_SOURCE_TYPE_DECL(mach_send); * The mask is unused (pass zero for now). */ #define DISPATCH_SOURCE_TYPE_MACH_RECV (&_dispatch_source_type_mach_recv) -__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) +__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) DISPATCH_LINUX_UNAVAILABLE() DISPATCH_SOURCE_TYPE_DECL(mach_recv); /*! @@ -124,7 +124,7 @@ DISPATCH_SOURCE_TYPE_DECL(mach_recv); */ #define DISPATCH_SOURCE_TYPE_MEMORYPRESSURE \ (&_dispatch_source_type_memorypressure) -__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_8_0) +__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_8_0) DISPATCH_LINUX_UNAVAILABLE() DISPATCH_SOURCE_TYPE_DECL(memorypressure); /*! @@ -135,7 +135,7 @@ DISPATCH_SOURCE_TYPE_DECL(memorypressure); * The mask is a mask of desired events from dispatch_source_proc_flags_t. */ #define DISPATCH_SOURCE_TYPE_PROC (&_dispatch_source_type_proc) -__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) +__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) DISPATCH_LINUX_UNAVAILABLE() DISPATCH_SOURCE_TYPE_DECL(proc); /*! @@ -178,7 +178,7 @@ DISPATCH_SOURCE_TYPE_DECL(timer); * The mask is a mask of desired events from dispatch_source_vnode_flags_t. */ #define DISPATCH_SOURCE_TYPE_VNODE (&_dispatch_source_type_vnode) -__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) +__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) DISPATCH_LINUX_UNAVAILABLE() DISPATCH_SOURCE_TYPE_DECL(vnode); /*! diff --git a/os/voucher_activity_private.h b/os/voucher_activity_private.h index 5da410a2a..8f233b33c 100644 --- a/os/voucher_activity_private.h +++ b/os/voucher_activity_private.h @@ -22,7 +22,7 @@ #define __OS_VOUCHER_ACTIVITY_PRIVATE__ #if OS_VOUCHER_ACTIVITY_SPI -#ifdef __APPLE__ +#if __has_include() #include #include #endif diff --git a/os/voucher_private.h b/os/voucher_private.h index 9d97b885e..562a70415 100644 --- a/os/voucher_private.h +++ b/os/voucher_private.h @@ -24,7 +24,7 @@ #ifndef __linux__ #include #endif -#ifdef __APPLE__ +#if __has_include() #include #include #endif @@ -416,7 +416,7 @@ dispatch_queue_create_with_accounting_override_voucher( dispatch_queue_attr_t _Nullable attr, voucher_t _Nullable voucher); -#ifdef __APPLE__ +#if __has_include() /*! * @group Voucher Mach SPI * SPI intended for clients that need to interact with mach messages or mach @@ -528,7 +528,7 @@ int voucher_get_current_persona_proximate_info( struct proc_persona_info *persona_info); -#endif // __APPLE__ +#endif // __has_include() __END_DECLS diff --git a/private/data_private.h b/private/data_private.h index fa3a80a79..7485525a5 100644 --- a/private/data_private.h +++ b/private/data_private.h @@ -53,7 +53,7 @@ DISPATCH_DATA_DESTRUCTOR_TYPE_DECL(none); */ #define DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE \ (_dispatch_data_destructor_vm_deallocate) -__OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0) +__OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0) DISPATCH_LINUX_UNAVAILABLE() DISPATCH_DATA_DESTRUCTOR_TYPE_DECL(vm_deallocate); /*! diff --git a/private/source_private.h b/private/source_private.h index 6b64175f8..bb1370238 100644 --- a/private/source_private.h +++ b/private/source_private.h @@ -79,7 +79,7 @@ DISPATCH_SOURCE_TYPE_DECL(interval); * The handle is a process identifier (pid_t). */ #define DISPATCH_SOURCE_TYPE_VFS (&_dispatch_source_type_vfs) -__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) +__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) DISPATCH_LINUX_UNAVAILABLE() DISPATCH_EXPORT const struct dispatch_source_type_s _dispatch_source_type_vfs; /*! @@ -91,6 +91,7 @@ DISPATCH_EXPORT const struct dispatch_source_type_s _dispatch_source_type_vfs; #define DISPATCH_SOURCE_TYPE_VM (&_dispatch_source_type_vm) __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_7, __MAC_10_10, __IPHONE_4_3, __IPHONE_8_0, "Use DISPATCH_SOURCE_TYPE_MEMORYPRESSURE instead") +DISPATCH_LINUX_UNAVAILABLE() DISPATCH_EXPORT const struct dispatch_source_type_s _dispatch_source_type_vm; /*! @@ -104,6 +105,7 @@ __OSX_DEPRECATED(10.9, 10.12, "Use DISPATCH_SOURCE_TYPE_MEMORYPRESSURE instead") __IOS_DEPRECATED(6.0, 10.0, "Use DISPATCH_SOURCE_TYPE_MEMORYPRESSURE instead") __TVOS_DEPRECATED(6.0, 10.0, "Use DISPATCH_SOURCE_TYPE_MEMORYPRESSURE instead") __WATCHOS_DEPRECATED(1.0, 3.0, "Use DISPATCH_SOURCE_TYPE_MEMORYPRESSURE instead") +DISPATCH_LINUX_UNAVAILABLE() DISPATCH_EXPORT const struct dispatch_source_type_s _dispatch_source_type_memorystatus; @@ -112,7 +114,7 @@ DISPATCH_EXPORT const struct dispatch_source_type_s * @discussion A dispatch source that monitors events on socket state changes. */ #define DISPATCH_SOURCE_TYPE_SOCK (&_dispatch_source_type_sock) -__OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0) +__OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0) DISPATCH_LINUX_UNAVAILABLE() DISPATCH_EXPORT const struct dispatch_source_type_s _dispatch_source_type_sock; __END_DECLS @@ -456,7 +458,7 @@ uint64_t dispatch_timer_aggregate_get_delay(dispatch_timer_aggregate_t aggregate, uint64_t *_Nullable leeway_ptr); -#if TARGET_OS_MAC +#if __has_include() /*! * @typedef dispatch_mig_callback_t * @@ -466,7 +468,7 @@ dispatch_timer_aggregate_get_delay(dispatch_timer_aggregate_t aggregate, typedef boolean_t (*dispatch_mig_callback_t)(mach_msg_header_t *message, mach_msg_header_t *reply); -__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) +__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) DISPATCH_LINUX_UNAVAILABLE() DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW mach_msg_return_t dispatch_mig_server(dispatch_source_t ds, size_t maxmsgsz, @@ -478,7 +480,7 @@ dispatch_mig_server(dispatch_source_t ds, size_t maxmsgsz, * @abstract * Extract the context pointer from a mach message trailer. */ -__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) +__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) DISPATCH_LINUX_UNAVAILABLE() DISPATCH_EXPORT DISPATCH_PURE DISPATCH_WARN_RESULT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW void *_Nullable diff --git a/src/data.c b/src/data.c index b950bae03..33906d35d 100644 --- a/src/data.c +++ b/src/data.c @@ -108,9 +108,11 @@ const dispatch_block_t _dispatch_data_destructor_none = ^{ DISPATCH_INTERNAL_CRASH(0, "none destructor called"); }; +#ifndef __linux__ const dispatch_block_t _dispatch_data_destructor_vm_deallocate = ^{ DISPATCH_INTERNAL_CRASH(0, "vmdeallocate destructor called"); }; +#endif const dispatch_block_t _dispatch_data_destructor_inline = ^{ DISPATCH_INTERNAL_CRASH(0, "inline destructor called"); @@ -247,7 +249,9 @@ dispatch_data_create_f(const void *buffer, size_t size, dispatch_queue_t queue, if (destructor != DISPATCH_DATA_DESTRUCTOR_DEFAULT && destructor != DISPATCH_DATA_DESTRUCTOR_FREE && destructor != DISPATCH_DATA_DESTRUCTOR_NONE && +#ifndef __linux__ destructor != DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE && +#endif destructor != DISPATCH_DATA_DESTRUCTOR_INLINE) { destructor = ^{ destructor_function((void*)buffer); }; } diff --git a/src/init.c b/src/init.c index 8ffd1bf7a..45cbff3bf 100644 --- a/src/init.c +++ b/src/init.c @@ -1313,6 +1313,14 @@ const struct dispatch_source_type_s _dispatch_source_type_vm = { #endif // DISPATCH_USE_VM_PRESSURE +const struct dispatch_source_type_s _dispatch_source_type_signal = { + .ke = { + .filter = EVFILT_SIGNAL, + .flags = EV_UDATA_SPECIFIC, + }, +}; + +#if !defined(__linux__) static void dispatch_source_type_proc_init(dispatch_source_t ds, dispatch_source_type_t type DISPATCH_UNUSED, @@ -1339,13 +1347,6 @@ const struct dispatch_source_type_s _dispatch_source_type_proc = { .init = dispatch_source_type_proc_init, }; -const struct dispatch_source_type_s _dispatch_source_type_signal = { - .ke = { - .filter = EVFILT_SIGNAL, - .flags = EV_UDATA_SPECIFIC, - }, -}; - const struct dispatch_source_type_s _dispatch_source_type_vnode = { .ke = { .filter = EVFILT_VNODE, @@ -1402,6 +1403,7 @@ const struct dispatch_source_type_s _dispatch_source_type_sock = { , #endif // EVFILT_SOCK }; +#endif // !defined(__linux__) static void dispatch_source_type_data_init(dispatch_source_t ds, From 0c41eab5b2dd478ee40bede57b9baeff95cf7b8f Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 30 Jun 2016 14:21:42 -0700 Subject: [PATCH 15/67] Merge pull request #96 from dgrove-oss/hide_evfilt_proc Mark dispatch_source APIs that are not available on Linux as unavailable Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index f803c2ef6..3e090001e 100644 --- a/PATCHES +++ b/PATCHES @@ -246,3 +246,4 @@ github commits starting with 29bdc2f from [3339b81] APPLIED rdar://26822213 [4fa8d8d] APPLIED rdar://26822213 [e922531] APPLIED rdar://26822213 +[195cbcf] APPLIED rdar://27303844 From 63b00aa8a34324218fe76e23c32a67201dcbae52 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 13 Jul 2016 17:42:09 -0700 Subject: [PATCH 16/67] move DISPATCH_LINUX_UNAVAILABLE to base.h and match it with existing header annotation macros switch guard for vm_deallocate to HAVE_MACH Signed-off-by: Daniel A. Steffen --- dispatch/base.h | 11 +++++++++++ dispatch/dispatch.h | 13 ------------- src/data.c | 4 ++-- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/dispatch/base.h b/dispatch/base.h index 4b9013197..8adfb0bdb 100644 --- a/dispatch/base.h +++ b/dispatch/base.h @@ -64,6 +64,7 @@ #define DISPATCH_MALLOC __attribute__((__malloc__)) #define DISPATCH_ALWAYS_INLINE __attribute__((__always_inline__)) #define DISPATCH_UNAVAILABLE __attribute__((__unavailable__)) +#define DISPATCH_UNAVAILABLE_MSG(msg) __attribute__((__unavailable__(msg))) #else /*! @parseOnly */ #define DISPATCH_NORETURN @@ -99,6 +100,16 @@ #define DISPATCH_ALWAYS_INLINE /*! @parseOnly */ #define DISPATCH_UNAVAILABLE +/*! @parseOnly */ +#define DISPATCH_UNAVAILABLE_MSG(msg) +#endif + +#ifdef __linux__ +#define DISPATCH_LINUX_UNAVAILABLE() \ + DISPATCH_UNAVAILABLE_MSG( \ + "This interface is unavailable on linux systems") +#else +#define DISPATCH_LINUX_UNAVAILABLE() #endif #ifndef DISPATCH_ALIAS_V2 diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index 62647651a..ca7e05706 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -47,23 +47,10 @@ #include #include -#ifdef __has_attribute -#if __has_attribute(unavailable) -#define __DISPATCH_UNAVAILABLE(msg) __attribute__((__unavailable__(msg))) -#endif -#endif -#ifndef __DISPATCH_UNAVAILABLE -#define __DISPATCH_UNAVAILABLE(msg) -#endif - #ifdef __linux__ #ifdef __DISPATCH_BUILDING_SWIFT_MODULE__ #include // for off_t #endif -#define DISPATCH_LINUX_UNAVAILABLE() \ - __DISPATCH_UNAVAILABLE("This interface is unavailable on linux systems") -#else -#define DISPATCH_LINUX_UNAVAILABLE() #endif #define DISPATCH_API_VERSION 20160612 diff --git a/src/data.c b/src/data.c index 33906d35d..4b01ce441 100644 --- a/src/data.c +++ b/src/data.c @@ -108,7 +108,7 @@ const dispatch_block_t _dispatch_data_destructor_none = ^{ DISPATCH_INTERNAL_CRASH(0, "none destructor called"); }; -#ifndef __linux__ +#if HAVE_MACH const dispatch_block_t _dispatch_data_destructor_vm_deallocate = ^{ DISPATCH_INTERNAL_CRASH(0, "vmdeallocate destructor called"); }; @@ -249,7 +249,7 @@ dispatch_data_create_f(const void *buffer, size_t size, dispatch_queue_t queue, if (destructor != DISPATCH_DATA_DESTRUCTOR_DEFAULT && destructor != DISPATCH_DATA_DESTRUCTOR_FREE && destructor != DISPATCH_DATA_DESTRUCTOR_NONE && -#ifndef __linux__ +#if HAVE_MACH destructor != DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE && #endif destructor != DISPATCH_DATA_DESTRUCTOR_INLINE) { From 05255f97656623b78e9846c8241d3ab63f5a5121 Mon Sep 17 00:00:00 2001 From: David Grove Date: Tue, 28 Jun 2016 14:30:26 -0400 Subject: [PATCH 17/67] Initial Swift3 wrapping overlay for libdispatch A useful checkpoint along the way to a complete implementation of the Swift3 overlay for libdispatch on non-Objective C platforms. The overlay code builds successfully and simple example programs using queues and timers work as expected. The basic approach is to wrap the C libdispatch objects in Swift objects and make the C dispatch APIs available internally via the CDispatch module. A few pieces (marked with FIXME) are ifdefed out to avoid compilation problems (will get back to them in later commits) or still need to be implemented (release on deinit). Although the installed libdispatch can be used in Swift programs via 'import Dispatch', the swiftc command for the client program currently needs to pass additional command line flags (to be fixed later). For example: swiftc -Xcc -fblocks -Xcc -D__DISPATCH_BUILDING_SWIFT_MODULE__=1 Forever.swift Signed-off-by: Daniel A. Steffen --- configure.ac | 21 +- dispatch/Makefile.am | 2 +- dispatch/module.map | 7 - dispatch/module.modulemap | 16 +- src/Makefile.am | 70 +++-- src/data.c | 4 + src/swift/Block.swift | 49 ++-- src/swift/Data.swift | 83 ++---- src/swift/Dispatch.swift | 61 ++-- src/swift/{Dispatch.mm => DispatchStubs.cc} | 28 +- src/swift/IO.swift | 14 +- src/swift/Private.swift | 38 +-- src/swift/Queue.swift | 96 +++---- src/swift/Source.swift | 170 ++++++----- src/swift/Time.swift | 24 +- src/swift/Wrapper.swift | 297 ++++++++++++++++++++ 16 files changed, 671 insertions(+), 309 deletions(-) delete mode 100644 dispatch/module.map rename src/swift/{Dispatch.mm => DispatchStubs.cc} (89%) create mode 100644 src/swift/Wrapper.swift diff --git a/configure.ac b/configure.ac index b3dc10658..e5c7c5ed7 100644 --- a/configure.ac +++ b/configure.ac @@ -94,6 +94,8 @@ AS_IF([test "x$enable_apple_tsd_optimizations" = "xyes"], [Define to use non-portable pthread TSD optimizations for Mac OS X)])] ) +AC_CANONICAL_TARGET + # # Enable building Swift overlay support into libdispatch # @@ -102,17 +104,34 @@ AC_ARG_WITH([swift-toolchain], [swift_toolchain_path=${withval} AC_DEFINE(HAVE_SWIFT, 1, [Define if building for Swift]) SWIFTC="$swift_toolchain_path/bin/swiftc" + case $target_os in + linux*) + os_string="linux" + ;; + *) + os_string=$target_os + ;; + esac + SWIFT_LIBDIR="$swift_toolchain_path/lib/swift/$os_string/$target_cpu" have_swift=true], [have_swift=false] ) AM_CONDITIONAL(HAVE_SWIFT, $have_swift) AC_SUBST([SWIFTC]) +AC_SUBST([SWIFT_LIBDIR]) + +# +# Enable use of gold linker when building the Swift overlay +# to avoid a symbol relocation issue. +# Ultimately the request to use gold should be passed in as an arg +# +AC_CHECK_PROG(use_gold_linker, ld.gold, true, false) +AM_CONDITIONAL(USE_GOLD_LINKER, $use_gold_linker) # # Enable __thread based TSD on platforms where it is efficient # Allow override based on command line argument to configure # -AC_CANONICAL_TARGET AC_ARG_ENABLE([thread-local-storage], [AS_HELP_STRING([--enable-thread-local-storage], [Enable usage of thread local storage via __thread])],, diff --git a/dispatch/Makefile.am b/dispatch/Makefile.am index 53ea5986c..89fd3daf0 100644 --- a/dispatch/Makefile.am +++ b/dispatch/Makefile.am @@ -24,5 +24,5 @@ dispatch_HEADERS= \ time.h if HAVE_SWIFT -dispatch_HEADERS+=module.map +dispatch_HEADERS+=module.modulemap endif diff --git a/dispatch/module.map b/dispatch/module.map deleted file mode 100644 index eefa75159..000000000 --- a/dispatch/module.map +++ /dev/null @@ -1,7 +0,0 @@ -module Dispatch [system] { - umbrella header "dispatch.h" - requires blocks - export * - link "dispatch" - link "BlocksRuntime" -} diff --git a/dispatch/module.modulemap b/dispatch/module.modulemap index addaae436..6f3c8aab8 100644 --- a/dispatch/module.modulemap +++ b/dispatch/module.modulemap @@ -1,10 +1,20 @@ -module Dispatch [system] [extern_c] { - umbrella header "dispatch.h" - module * { export * } +module Dispatch { + requires blocks export * + link "dispatch" + link "BlocksRuntime" } module DispatchIntrospection [system] [extern_c] { header "introspection.h" export * } + +module CDispatch [system] [extern_c] { + umbrella header "dispatch.h" + module * { export * } + export * + requires blocks + link "dispatch" + link "BlocksRuntime" +} diff --git a/src/Makefile.am b/src/Makefile.am index e51d15a33..58fa4ef12 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,6 +40,7 @@ libdispatch_la_SOURCES= \ source_internal.h \ trace.h \ voucher_internal.h \ + firehose/firehose_internal.h \ shims/atomic.h \ shims/atomic_sfb.h \ shims/getprogname.h \ @@ -83,6 +84,10 @@ libdispatch_la_LDFLAGS+=-Wl,-compatibility_version,1 \ -Wl,-alias_list,$(top_srcdir)/xcodeconfig/libdispatch.aliases endif +if USE_GOLD_LINKER +libdispatch_la_LDFLAGS+=-Xcompiler -fuse-ld=gold +endif + if USE_OBJC libdispatch_la_SOURCES+=block.cpp data.m object.m libdispatch_la_OBJCFLAGS=$(AM_OBJCFLAGS) -Wno-switch -fobjc-gc @@ -114,9 +119,7 @@ DTRACE_SOURCES=provider.h endif if HAVE_SWIFT -libdispatch_la_SOURCES+=swift/Dispatch.mm -EXTRA_libdispatch_la_SOURCES+= \ - swift/Dispatch.swift \ +SWIFT_SRC_FILES=\ swift/Block.swift \ swift/Data.swift \ swift/Dispatch.swift \ @@ -124,33 +127,52 @@ EXTRA_libdispatch_la_SOURCES+= \ swift/Private.swift \ swift/Queue.swift \ swift/Source.swift \ - swift/Time.swift - -EXTRA_libdispatch_la_DEPENDENCIES+=$(abs_builddir)/Dispatch.o $(abs_builddir)/Dispatch.swiftmodule -libdispatch_la_LIBADD+=$(abs_builddir)/Dispatch.o - -SWIFT_OBJECTS= \ - $(abs_builddir)/Dispatch.swiftmodule \ - $(abs_builddir)/Dispatch.swiftdoc \ - $(abs_builddir)/Dispatch.o + swift/Time.swift \ + swift/Wrapper.swift + +SWIFT_ABS_SRC_FILES = $(SWIFT_SRC_FILES:%=$(abs_srcdir)/%) +SWIFT_OBJ_FILES = $(SWIFT_SRC_FILES:%.swift=$(abs_builddir)/%.o) + +libdispatch_la_SOURCES+=swift/DispatchStubs.cc +EXTRA_libdispatch_la_SOURCES+=$(SWIFT_SRC_FILES) + +EXTRA_libdispatch_la_DEPENDENCIES+=$(SWIFT_OBJ_FILES) $(abs_builddir)/swift/Dispatch.swiftmodule +libdispatch_la_LIBADD+=$(SWIFT_OBJ_FILES) + +SWIFT_GEN_FILES= \ + $(abs_builddir)/swift/Dispatch.swiftmodule \ + $(abs_builddir)/swift/Dispatch.swiftdoc \ + $(SWIFT_OBJ_FILES) \ + $(SWIFT_OBJ_FILES:%=%.d) \ + $(SWIFT_OBJ_FILES:%=%.swiftdeps) \ + $(SWIFT_OBJ_FILES:%=%.~partial.swiftmodule) \ + $(SWIFT_OBJ_FILES:%=%.~partial.swiftdoc) \ + $(SWIFT_OBJ_FILES:%=%.~partial.swiftdeps) + +SWIFTC_FLAGS = -Xcc -D__DISPATCH_BUILDING_SWIFT_MODULE__=1 -Xcc -fmodule-map-file=$(abs_top_srcdir)/dispatch/module.modulemap -I$(abs_top_srcdir) -Xcc -fblocks + +$(abs_builddir)/swift/%.o: $(abs_srcdir)/swift/%.swift + $(SWIFTC) -frontend -c $(SWIFT_ABS_SRC_FILES) -primary-file $< \ + $(SWIFTC_FLAGS) -module-name Dispatch -module-link-name dispatch \ + -o $@ -emit-module-path $@.~partial.swiftmodule \ + -emit-module-doc-path $@.~partial.swiftdoc -emit-dependencies-path $@.d \ + -emit-reference-dependencies-path $@.swiftdeps \ + -module-cache-path $(top_builddir) + +$(abs_builddir)/swift/Dispatch.swiftmodule: $(SWIFT_ABS_SRC_FILES) + $(SWIFTC) -frontend -emit-module $(SWIFT_OBJ_FILES:%=%.~partial.swiftmodule) \ + $(SWIFTC_FLAGS) -module-cache-path $(top_builddir) -module-link-name dispatch \ + -o $@ -emit-module-doc-path $(@:%.swiftmodule=%.swiftdoc) -SWIFTC_FLAGS = -Xcc -D__DISPATCH_BUILDING_SWIFT_MODULE__=1 -Xcc -fmodule-map-file=$(abs_top_srcdir)/dispatch/module.map -I$(abs_top_srcdir) -parse-as-library -Xcc -fblocks - -$(abs_builddir)/Dispatch.o: $(abs_srcdir)/swift/Dispatch.swift - $(SWIFTC) $(SWIFTC_FLAGS) -c -o $@ $< - -$(abs_builddir)/Dispatch.swiftmodule: $(abs_srcdir)/swift/Dispatch.swift - $(SWIFTC) $(SWIFTC_FLAGS) -emit-module -emit-module-path $@ $< - -if HAVE_SWIFT swiftmoddir=${prefix}/lib/swift/linux/${build_cpu} -swiftmod_HEADERS=$(abs_builddir)/Dispatch.swiftmodule $(abs_builddir)/Dispatch.swiftdoc -endif +swiftmod_HEADERS=\ + $(abs_builddir)/swift/Dispatch.swiftmodule \ + $(abs_builddir)/swift/Dispatch.swiftdoc endif BUILT_SOURCES=$(MIG_SOURCES) $(DTRACE_SOURCES) nodist_libdispatch_la_SOURCES=$(BUILT_SOURCES) -CLEANFILES=$(BUILT_SOURCES) $(SWIFT_OBJECTS) +CLEANFILES=$(BUILT_SOURCES) $(SWIFT_GEN_FILES) DISTCLEANFILES=pthread_machdep.h pthread System mach objc diff --git a/src/data.c b/src/data.c index 4b01ce441..489eaf265 100644 --- a/src/data.c +++ b/src/data.c @@ -108,6 +108,10 @@ const dispatch_block_t _dispatch_data_destructor_none = ^{ DISPATCH_INTERNAL_CRASH(0, "none destructor called"); }; +const dispatch_block_t _dispatch_data_destructor_munmap = ^{ + DISPATCH_INTERNAL_CRASH(0, "munmap destructor called"); +}; + #if HAVE_MACH const dispatch_block_t _dispatch_data_destructor_vm_deallocate = ^{ DISPATCH_INTERNAL_CRASH(0, "vmdeallocate destructor called"); diff --git a/src/swift/Block.swift b/src/swift/Block.swift index e32478ea0..c1266cea1 100644 --- a/src/swift/Block.swift +++ b/src/swift/Block.swift @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +import CDispatch + public struct DispatchWorkItemFlags : OptionSet, RawRepresentable { public let rawValue: UInt public init(rawValue: UInt) { self.rawValue = rawValue } @@ -38,14 +40,14 @@ public class DispatchWorkItem { internal var _group: DispatchGroup? public init(group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], block: @convention(block) () -> ()) { - _block = _swift_dispatch_block_create_with_qos_class(__dispatch_block_flags_t(flags.rawValue), - qos.qosClass.rawValue, Int32(qos.relativePriority), block) + _block = dispatch_block_create_with_qos_class(dispatch_block_flags_t(flags.rawValue), + qos.qosClass.rawValue.rawValue, Int32(qos.relativePriority), block) } // Used by DispatchQueue.synchronously to provide a @noescape path through // dispatch_block_t, as we know the lifetime of the block in question. internal init(flags: DispatchWorkItemFlags = [], noescapeBlock: @noescape () -> ()) { - _block = _swift_dispatch_block_create_noescape(__dispatch_block_flags_t(flags.rawValue), noescapeBlock) + _block = _swift_dispatch_block_create_noescape(dispatch_block_flags_t(flags.rawValue), noescapeBlock) } public func perform() { @@ -57,36 +59,36 @@ public class DispatchWorkItem { } public func wait() { - _ = _swift_dispatch_block_wait(_block, DispatchTime.distantFuture.rawValue) + _ = dispatch_block_wait(_block, DispatchTime.distantFuture.rawValue) } public func wait(timeout: DispatchTime) -> DispatchTimeoutResult { - return _swift_dispatch_block_wait(_block, timeout.rawValue) == 0 ? .Success : .TimedOut + return dispatch_block_wait(_block, timeout.rawValue) == 0 ? .Success : .TimedOut } public func wait(wallTimeout: DispatchWallTime) -> DispatchTimeoutResult { - return _swift_dispatch_block_wait(_block, wallTimeout.rawValue) == 0 ? .Success : .TimedOut + return dispatch_block_wait(_block, wallTimeout.rawValue) == 0 ? .Success : .TimedOut } public func notify(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], queue: DispatchQueue, execute: @convention(block) () -> Void) { if qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: execute) - _swift_dispatch_block_notify(_block, queue, item._block) + dispatch_block_notify(_block, queue.__wrapped, item._block) } else { - _swift_dispatch_block_notify(_block, queue, execute) + dispatch_block_notify(_block, queue.__wrapped, execute) } } public func notify(queue: DispatchQueue, execute: DispatchWorkItem) { - _swift_dispatch_block_notify(_block, queue, execute._block) + dispatch_block_notify(_block, queue.__wrapped, execute._block) } public func cancel() { - _swift_dispatch_block_cancel(_block) + dispatch_block_cancel(_block) } public var isCancelled: Bool { - return _swift_dispatch_block_testcancel(_block) != 0 + return dispatch_block_testcancel(_block) != 0 } } @@ -96,7 +98,7 @@ public extension DispatchWorkItem { public func wait(timeout: DispatchWallTime) -> Int { switch wait(wallTimeout: timeout) { case .Success: return 0 - case .TimedOut: return Int(KERN_OPERATION_TIMED_OUT) + case .TimedOut: return DispatchTimeoutResult.KERN_OPERATION_TIMED_OUT } } } @@ -106,26 +108,7 @@ public extension DispatchWorkItem { /// C blocks and Swift closures, which interferes with dispatch APIs that depend /// on the referential identity of a block. Particularly, dispatch_block_create. internal typealias _DispatchBlock = @convention(block) () -> Void - -/// APINotes also removes the old dispatch_block_t typedef from the Dispatch module -/// completely. In doing so it causes the dispatch_block_* API to lose their -/// @convention(block) attributes. As such, all of the entry points are shimmed -//// through Dispatch.mm with _DispatchBlock types. -@_silgen_name("_swift_dispatch_block_create_with_qos_class") -internal func _swift_dispatch_block_create_with_qos_class(_ flags: __dispatch_block_flags_t, _ qos: qos_class_t, _ relativePriority: Int32, _ block: _DispatchBlock) -> _DispatchBlock +internal typealias dispatch_block_t = @convention(block) () -> Void @_silgen_name("_swift_dispatch_block_create_noescape") -internal func _swift_dispatch_block_create_noescape(_ flags: __dispatch_block_flags_t, _ block: @noescape () -> ()) -> _DispatchBlock - -@_silgen_name("_swift_dispatch_block_wait") -internal func _swift_dispatch_block_wait(_ block: _DispatchBlock, _ timeout: UInt64) -> Int - -@_silgen_name("_swift_dispatch_block_notify") -internal func _swift_dispatch_block_notify(_ block: _DispatchBlock, _ queue: DispatchQueue, _ notifier: _DispatchBlock) - -@_silgen_name("_swift_dispatch_block_cancel") -internal func _swift_dispatch_block_cancel(_ block: _DispatchBlock) - -@_silgen_name("_swift_dispatch_block_testcancel") -internal func _swift_dispatch_block_testcancel(_ block: _DispatchBlock) -> Int - +internal func _swift_dispatch_block_create_noescape(_ flags: dispatch_block_flags_t, _ block: @noescape () -> ()) -> _DispatchBlock diff --git a/src/swift/Data.swift b/src/swift/Data.swift index a78bf5bca..0d21e27c0 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -10,13 +10,16 @@ // //===----------------------------------------------------------------------===// -public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { +import CDispatch + +public struct DispatchData : RandomAccessCollection { public typealias Iterator = DispatchDataIterator public typealias Index = Int public typealias Indices = DefaultRandomAccessIndices public static let empty: DispatchData = DispatchData(data: _swift_dispatch_data_empty()) +#if false /* FIXME: dragging in _TMBO (Objective-C) */ public enum Deallocator { /// Use `free` case free @@ -35,18 +38,18 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { } } } - - private var __wrapped: __DispatchData +#endif + internal var __wrapped: dispatch_data_t /// Initialize a `Data` with copied memory content. /// /// - parameter bytes: A pointer to the memory. It will be copied. /// - parameter count: The number of bytes to copy. public init(bytes buffer: UnsafeBufferPointer) { - __wrapped = __dispatch_data_create( + __wrapped = dispatch_data_create( buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default()) } - +#if false /* FIXME: dragging in _TMBO (Objective-C) */ /// Initialize a `Data` without copying the bytes. /// /// - parameter bytes: A pointer to the bytes. @@ -55,16 +58,15 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { public init(bytesNoCopy bytes: UnsafeBufferPointer, deallocator: Deallocator = .free) { let (q, b) = deallocator._deallocator - __wrapped = __dispatch_data_create( - bytes.baseAddress!, bytes.count, q, b) + __wrapped = dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b) } - - internal init(data: __DispatchData) { +#endif + internal init(data: dispatch_data_t) { __wrapped = data } public var count: Int { - return __dispatch_data_get_size(__wrapped) + return CDispatch.dispatch_data_get_size(__wrapped) } public func withUnsafeBytes( @@ -72,7 +74,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { { var ptr: UnsafePointer? = nil var size = 0; - let data = __dispatch_data_create_map(__wrapped, &ptr, &size) + let data = CDispatch.dispatch_data_create_map(__wrapped, &ptr, &size) defer { _fixLifetime(data) } return try body(UnsafePointer(ptr!)) } @@ -80,7 +82,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { public func enumerateBytes( block: @noescape (buffer: UnsafeBufferPointer, byteIndex: Int, stop: inout Bool) -> Void) { - _swift_dispatch_data_apply(__wrapped) { (data: __DispatchData, offset: Int, ptr: UnsafePointer, size: Int) in + _swift_dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in let bp = UnsafeBufferPointer(start: UnsafePointer(ptr), count: size) var stop = false block(buffer: bp, byteIndex: offset, stop: &stop) @@ -93,7 +95,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { /// - parameter bytes: A pointer to the bytes to copy in to the data. /// - parameter count: The number of bytes to copy. public mutating func append(_ bytes: UnsafePointer, count: Int) { - let data = __dispatch_data_create(bytes, count, nil, _dispatch_data_destructor_default()) + let data = dispatch_data_create(bytes, count, nil, _dispatch_data_destructor_default()) self.append(DispatchData(data: data)) } @@ -101,7 +103,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { /// /// - parameter data: The data to append to this data. public mutating func append(_ other: DispatchData) { - let data = __dispatch_data_create_concat(__wrapped, other as __DispatchData) + let data = CDispatch.dispatch_data_create_concat(__wrapped, other.__wrapped) __wrapped = data } @@ -109,12 +111,12 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { /// /// - parameter buffer: The buffer of bytes to append. The size is calculated from `SourceType` and `buffer.count`. public mutating func append(_ buffer : UnsafeBufferPointer) { - self.append(UnsafePointer(buffer.baseAddress!), count: buffer.count * sizeof(SourceType)) + self.append(UnsafePointer(buffer.baseAddress!), count: buffer.count * sizeof(SourceType.self)) } private func _copyBytesHelper(to pointer: UnsafeMutablePointer, from range: CountableRange) { var copiedCount = 0 - __dispatch_data_apply(__wrapped) { (data: __DispatchData, offset: Int, ptr: UnsafePointer, size: Int) in + _ = CDispatch.dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in let limit = Swift.min((range.endIndex - range.startIndex) - copiedCount, size) memcpy(pointer + copiedCount, ptr, limit) copiedCount += limit @@ -160,9 +162,9 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { precondition(r.endIndex >= 0) precondition(r.endIndex <= cnt, "The range is outside the bounds of the data") - copyRange = r.startIndex..<(r.startIndex + Swift.min(buffer.count * sizeof(DestinationType), r.count)) + copyRange = r.startIndex..<(r.startIndex + Swift.min(buffer.count * sizeof(DestinationType.self), r.count)) } else { - copyRange = 0.. UInt8 { var offset = 0 - let subdata = __dispatch_data_copy_region(__wrapped, index, &offset) + let subdata = CDispatch.dispatch_data_copy_region(__wrapped, index, &offset) var ptr: UnsafePointer? = nil var size = 0 - let map = __dispatch_data_create_map(subdata, &ptr, &size) + let map = CDispatch.dispatch_data_create_map(subdata, &ptr, &size) defer { _fixLifetime(map) } let pptr = UnsafePointer(ptr!) @@ -194,14 +196,14 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { /// /// - parameter range: The range to copy. public func subdata(in range: CountableRange) -> DispatchData { - let subrange = __dispatch_data_create_subrange( + let subrange = CDispatch.dispatch_data_create_subrange( __wrapped, range.startIndex, range.endIndex - range.startIndex) return DispatchData(data: subrange) } public func region(location: Int) -> (data: DispatchData, offset: Int) { var offset: Int = 0 - let data = __dispatch_data_copy_region(__wrapped, location, &offset) + let data = CDispatch.dispatch_data_copy_region(__wrapped, location, &offset) return (DispatchData(data: data), offset) } @@ -235,8 +237,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { public init(_data: DispatchData) { var ptr: UnsafePointer? self._count = 0 - self._data = __dispatch_data_create_map( - _data as __DispatchData, &ptr, &self._count) + self._data = CDispatch.dispatch_data_create_map(_data.__wrapped, &ptr, &self._count) self._ptr = UnsafePointer(ptr!) self._position = _data.startIndex } @@ -252,45 +253,19 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { return element } - internal let _data: __DispatchData + internal let _data: dispatch_data_t internal var _ptr: UnsafePointer internal var _count: Int internal var _position: DispatchData.Index } -extension DispatchData { - public static func _isBridgedToObjectiveC() -> Bool { - return true - } - - @_semantics("convertToObjectiveC") - public func _bridgeToObjectiveC() -> __DispatchData { - return unsafeBitCast(__wrapped, to: __DispatchData.self) - } - - public static func _forceBridgeFromObjectiveC(_ input: __DispatchData, result: inout DispatchData?) { - result = DispatchData(data: input) - } - - public static func _conditionallyBridgeFromObjectiveC(_ input: __DispatchData, result: inout DispatchData?) -> Bool { - result = DispatchData(data: input) - return true - } - - public static func _unconditionallyBridgeFromObjectiveC(_ source: __DispatchData?) -> DispatchData { - var result: DispatchData? = nil - _forceBridgeFromObjectiveC(source!, result: &result) - return result! - } -} - -typealias _swift_data_applier = @convention(block) @noescape (__DispatchData, Int, UnsafePointer, Int) -> Bool +typealias _swift_data_applier = @convention(block) @noescape (dispatch_data_t, Int, UnsafePointer, Int) -> Bool @_silgen_name("_swift_dispatch_data_apply") -internal func _swift_dispatch_data_apply(_ data: __DispatchData, _ block: _swift_data_applier) +internal func _swift_dispatch_data_apply(_ data: dispatch_data_t, _ block: _swift_data_applier) @_silgen_name("_swift_dispatch_data_empty") -internal func _swift_dispatch_data_empty() -> __DispatchData +internal func _swift_dispatch_data_empty() -> dispatch_data_t @_silgen_name("_swift_dispatch_data_destructor_free") internal func _dispatch_data_destructor_free() -> _DispatchBlock diff --git a/src/swift/Dispatch.swift b/src/swift/Dispatch.swift index 4ed2ad9cd..2b9cb2164 100644 --- a/src/swift/Dispatch.swift +++ b/src/swift/Dispatch.swift @@ -12,6 +12,8 @@ @_exported import Dispatch +import CDispatch + /// dispatch_assert @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) @@ -25,11 +27,11 @@ public enum DispatchPredicate { public func _dispatchPreconditionTest(_ condition: DispatchPredicate) -> Bool { switch condition { case .onQueue(let q): - __dispatch_assert_queue(q) + dispatch_assert_queue(q.__wrapped) case .onQueueAsBarrier(let q): - __dispatch_assert_queue_barrier(q) + dispatch_assert_queue_barrier(q.__wrapped) case .notOnQueue(let q): - __dispatch_assert_queue_not(q) + dispatch_assert_queue_not(q.__wrapped) } return true } @@ -94,27 +96,27 @@ public struct DispatchQoS : Equatable { case unspecified @available(OSX 10.10, iOS 8.0, *) - internal init?(qosClass: qos_class_t) { + internal init?(qosClass: _OSQoSClass) { switch qosClass { - case QOS_CLASS_BACKGROUND: self = .background - case QOS_CLASS_UTILITY: self = .utility - case QOS_CLASS_DEFAULT: self = .default - case QOS_CLASS_USER_INITIATED: self = .userInitiated - case QOS_CLASS_USER_INTERACTIVE: self = .userInteractive - case QOS_CLASS_UNSPECIFIED: self = .unspecified + case .QOS_CLASS_BACKGROUND: self = .background + case .QOS_CLASS_UTILITY: self = .utility + case .QOS_CLASS_DEFAULT: self = .default + case .QOS_CLASS_USER_INITIATED: self = .userInitiated + case .QOS_CLASS_USER_INTERACTIVE: self = .userInteractive + case .QOS_CLASS_UNSPECIFIED: self = .unspecified default: return nil } } @available(OSX 10.10, iOS 8.0, *) - internal var rawValue: qos_class_t { + internal var rawValue: _OSQoSClass { switch self { - case .background: return QOS_CLASS_BACKGROUND - case .utility: return QOS_CLASS_UTILITY - case .default: return QOS_CLASS_DEFAULT - case .userInitiated: return QOS_CLASS_USER_INITIATED - case .userInteractive: return QOS_CLASS_USER_INTERACTIVE - case .unspecified: return QOS_CLASS_UNSPECIFIED + case .background: return .QOS_CLASS_BACKGROUND + case .utility: return .QOS_CLASS_UTILITY + case .default: return .QOS_CLASS_DEFAULT + case .userInitiated: return .QOS_CLASS_USER_INITIATED + case .userInteractive: return .QOS_CLASS_USER_INTERACTIVE + case .unspecified: return .QOS_CLASS_UNSPECIFIED } } } @@ -132,6 +134,7 @@ public func ==(a: DispatchQoS, b: DispatchQoS) -> Bool { /// public enum DispatchTimeoutResult { + static let KERN_OPERATION_TIMED_OUT:Int = 49 case Success case TimedOut } @@ -142,27 +145,27 @@ public extension DispatchGroup { public func notify(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], queue: DispatchQueue, execute work: @convention(block) () -> ()) { if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: work) - __dispatch_group_notify(self, queue, item._block) + dispatch_group_notify(self.__wrapped, queue.__wrapped, item._block) } else { - __dispatch_group_notify(self, queue, work) + dispatch_group_notify(self.__wrapped, queue.__wrapped, work) } } @available(OSX 10.10, iOS 8.0, *) public func notify(queue: DispatchQueue, work: DispatchWorkItem) { - __dispatch_group_notify(self, queue, work._block) + dispatch_group_notify(self.__wrapped, queue.__wrapped, work._block) } public func wait() { - _ = __dispatch_group_wait(self, DispatchTime.distantFuture.rawValue) + _ = dispatch_group_wait(self.__wrapped, DispatchTime.distantFuture.rawValue) } public func wait(timeout: DispatchTime) -> DispatchTimeoutResult { - return __dispatch_group_wait(self, timeout.rawValue) == 0 ? .Success : .TimedOut + return dispatch_group_wait(self.__wrapped, timeout.rawValue) == 0 ? .Success : .TimedOut } public func wait(wallTimeout timeout: DispatchWallTime) -> DispatchTimeoutResult { - return __dispatch_group_wait(self, timeout.rawValue) == 0 ? .Success : .TimedOut + return dispatch_group_wait(self.__wrapped, timeout.rawValue) == 0 ? .Success : .TimedOut } } @@ -171,7 +174,7 @@ public extension DispatchGroup { public func wait(walltime timeout: DispatchWallTime) -> Int { switch wait(wallTimeout: timeout) { case .Success: return 0 - case .TimedOut: return Int(KERN_OPERATION_TIMED_OUT) + case .TimedOut: return DispatchTimeoutResult.KERN_OPERATION_TIMED_OUT } } } @@ -181,19 +184,19 @@ public extension DispatchGroup { public extension DispatchSemaphore { @discardableResult public func signal() -> Int { - return __dispatch_semaphore_signal(self) + return dispatch_semaphore_signal(self.__wrapped) } public func wait() { - _ = __dispatch_semaphore_wait(self, DispatchTime.distantFuture.rawValue) + _ = dispatch_semaphore_wait(self.__wrapped, DispatchTime.distantFuture.rawValue) } public func wait(timeout: DispatchTime) -> DispatchTimeoutResult { - return __dispatch_semaphore_wait(self, timeout.rawValue) == 0 ? .Success : .TimedOut + return dispatch_semaphore_wait(self.__wrapped, timeout.rawValue) == 0 ? .Success : .TimedOut } public func wait(wallTimeout: DispatchWallTime) -> DispatchTimeoutResult { - return __dispatch_semaphore_wait(self, wallTimeout.rawValue) == 0 ? .Success : .TimedOut + return dispatch_semaphore_wait(self.__wrapped, wallTimeout.rawValue) == 0 ? .Success : .TimedOut } } @@ -202,7 +205,7 @@ public extension DispatchSemaphore { public func wait(walltime timeout: DispatchWalltime) -> Int { switch wait(wallTimeout: timeout) { case .Success: return 0 - case .TimedOut: return Int(KERN_OPERATION_TIMED_OUT) + case .TimedOut: return DispatchTimeoutResult.KERN_OPERATION_TIMED_OUT } } } diff --git a/src/swift/Dispatch.mm b/src/swift/DispatchStubs.cc similarity index 89% rename from src/swift/Dispatch.mm rename to src/swift/DispatchStubs.cc index b66a34e8b..62a53ef6b 100644 --- a/src/swift/Dispatch.mm +++ b/src/swift/DispatchStubs.cc @@ -11,11 +11,11 @@ //===----------------------------------------------------------------------===// #include -#include #include #define DISPATCH_RUNTIME_STDLIB_INTERFACE __attribute__((__visibility__("default"))) +#if USE_OBJC @protocol OS_dispatch_source; @protocol OS_dispatch_source_mach_send; @protocol OS_dispatch_source_mach_recv; @@ -49,9 +49,15 @@ static void _dispatch_overlay_constructor() { } } +#endif /* USE_OBJC */ + +#if 0 /* FIXME -- adding directory to include path may need build-script plumbing to do properly... */ #include "swift/Runtime/Config.h" +#else +#define SWIFT_CC(x) /* FIXME!! */ +#endif -SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE extern "C" dispatch_queue_attr_t _swift_dispatch_queue_concurrent(void) { return DISPATCH_QUEUE_CONCURRENT; @@ -95,7 +101,7 @@ static void _dispatch_overlay_constructor() { SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE extern "C" dispatch_block_t -_swift_dispatch_block_create_with_qos_class(dispatch_block_flags_t flags, qos_class_t qos, int relative_priority, dispatch_block_t block) { +_swift_dispatch_block_create_with_qos_class(dispatch_block_flags_t flags, dispatch_qos_class_t qos, int relative_priority, dispatch_block_t block) { return dispatch_block_create_with_qos_class(flags, qos, relative_priority, block); } @@ -168,12 +174,28 @@ static void _dispatch_overlay_constructor() { SOURCE(DATA_ADD) SOURCE(DATA_OR) +#if HAVE_MACH SOURCE(MACH_SEND) SOURCE(MACH_RECV) SOURCE(MEMORYPRESSURE) +#endif +#ifndef __linux__ SOURCE(PROC) +#endif SOURCE(READ) SOURCE(SIGNAL) SOURCE(TIMER) +#ifndef __linux__ SOURCE(VNODE) +#endif SOURCE(WRITE) + +// See comment in CFFuntime.c explaining why objc_retainAutoreleasedReturnValue is needed. +extern "C" void swift_release(void *); +extern "C" void * objc_retainAutoreleasedReturnValue(void *obj) { + if (obj) { + swift_release(obj); + return obj; + } + else return NULL; +} diff --git a/src/swift/IO.swift b/src/swift/IO.swift index 049f54f3c..6e6b6692e 100644 --- a/src/swift/IO.swift +++ b/src/swift/IO.swift @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +import CDispatch + public extension DispatchIO { public enum StreamType : UInt { @@ -33,13 +35,13 @@ public extension DispatchIO { } public class func read(fromFileDescriptor: Int32, maxLength: Int, runningHandlerOn queue: DispatchQueue, handler: (data: DispatchData, error: Int32) -> Void) { - __dispatch_read(fromFileDescriptor, maxLength, queue) { (data: __DispatchData, error: Int32) in + dispatch_read(fromFileDescriptor, maxLength, queue.__wrapped) { (data: dispatch_data_t, error: Int32) in handler(data: DispatchData(data: data), error: error) } } public class func write(fromFileDescriptor: Int32, data: DispatchData, runningHandlerOn queue: DispatchQueue, handler: (data: DispatchData?, error: Int32) -> Void) { - __dispatch_write(fromFileDescriptor, data as __DispatchData, queue) { (data: __DispatchData?, error: Int32) in + dispatch_write(fromFileDescriptor, data.__wrapped, queue.__wrapped) { (data: dispatch_data_t?, error: Int32) in handler(data: data.flatMap { DispatchData(data: $0) }, error: error) } } @@ -74,23 +76,23 @@ public extension DispatchIO { } public func read(offset: off_t, length: Int, queue: DispatchQueue, ioHandler: (done: Bool, data: DispatchData?, error: Int32) -> Void) { - __dispatch_io_read(self, offset, length, queue) { (done: Bool, data: __DispatchData?, error: Int32) in + dispatch_io_read(self.__wrapped, offset, length, queue.__wrapped) { (done: Bool, data: dispatch_data_t?, error: Int32) in ioHandler(done: done, data: data.flatMap { DispatchData(data: $0) }, error: error) } } public func write(offset: off_t, data: DispatchData, queue: DispatchQueue, ioHandler: (done: Bool, data: DispatchData?, error: Int32) -> Void) { - __dispatch_io_write(self, offset, data as __DispatchData, queue) { (done: Bool, data: __DispatchData?, error: Int32) in + dispatch_io_write(self.__wrapped, offset, data.__wrapped, queue.__wrapped) { (done: Bool, data: dispatch_data_t?, error: Int32) in ioHandler(done: done, data: data.flatMap { DispatchData(data: $0) }, error: error) } } public func setInterval(interval: DispatchTimeInterval, flags: IntervalFlags = []) { - __dispatch_io_set_interval(self, interval.rawValue, flags.rawValue) + dispatch_io_set_interval(self.__wrapped, interval.rawValue, flags.rawValue) } public func close(flags: CloseFlags = []) { - __dispatch_io_close(self, flags.rawValue) + dispatch_io_close(self.__wrapped, flags.rawValue) } } diff --git a/src/swift/Private.swift b/src/swift/Private.swift index 3a0cdb630..e38f72861 100644 --- a/src/swift/Private.swift +++ b/src/swift/Private.swift @@ -12,14 +12,16 @@ // Redeclarations of all SwiftPrivate functions with appropriate markup. +import CDispatch + @available(*, unavailable, renamed:"DispatchQueue.init(label:attributes:target:)") -public func dispatch_queue_create(_ label: UnsafePointer?, _ attr: __OS_dispatch_queue_attr?) -> DispatchQueue +public func dispatch_queue_create(_ label: UnsafePointer?, _ attr: dispatch_queue_attr_t?) -> DispatchQueue { fatalError() } @available(*, unavailable, renamed:"DispatchQueue.init(label:attributes:target:)") -public func dispatch_queue_create_with_target(_ label: UnsafePointer?, _ attr: __OS_dispatch_queue_attr?, _ queue: DispatchQueue?) -> DispatchQueue +public func dispatch_queue_create_with_target(_ label: UnsafePointer?, _ attr: dispatch_queue_attr_t?, _ queue: DispatchQueue?) -> DispatchQueue { fatalError() } @@ -43,67 +45,67 @@ public func dispatch_io_create_with_io(_ type: UInt, _ io: DispatchIO, _ queue: } @available(*, unavailable, renamed:"DispatchIO.read(fileDescriptor:length:queue:handler:)") -public func dispatch_read(_ fd: Int32, _ length: Int, _ queue: DispatchQueue, _ handler: (__DispatchData, Int32) -> Void) +public func dispatch_read(_ fd: Int32, _ length: Int, _ queue: DispatchQueue, _ handler: (dispatch_data_t, Int32) -> Void) { fatalError() } @available(*, unavailable, renamed:"DispatchIO.read(self:offset:length:queue:ioHandler:)") -func dispatch_io_read(_ channel: DispatchIO, _ offset: off_t, _ length: Int, _ queue: DispatchQueue, _ io_handler: (Bool, __DispatchData?, Int32) -> Void) +func dispatch_io_read(_ channel: DispatchIO, _ offset: off_t, _ length: Int, _ queue: DispatchQueue, _ io_handler: (Bool, dispatch_data_t?, Int32) -> Void) { fatalError() } @available(*, unavailable, renamed:"DispatchIO.write(self:offset:data:queue:ioHandler:)") -func dispatch_io_write(_ channel: DispatchIO, _ offset: off_t, _ data: __DispatchData, _ queue: DispatchQueue, _ io_handler: (Bool, __DispatchData?, Int32) -> Void) +func dispatch_io_write(_ channel: DispatchIO, _ offset: off_t, _ data: dispatch_data_t, _ queue: DispatchQueue, _ io_handler: (Bool, dispatch_data_t?, Int32) -> Void) { fatalError() } @available(*, unavailable, renamed:"DispatchIO.write(fileDescriptor:data:queue:handler:)") -func dispatch_write(_ fd: Int32, _ data: __DispatchData, _ queue: DispatchQueue, _ handler: (__DispatchData?, Int32) -> Void) +func dispatch_write(_ fd: Int32, _ data: dispatch_data_t, _ queue: DispatchQueue, _ handler: (dispatch_data_t?, Int32) -> Void) { fatalError() } @available(*, unavailable, renamed:"DispatchData.init(bytes:)") -public func dispatch_data_create(_ buffer: UnsafePointer, _ size: Int, _ queue: DispatchQueue?, _ destructor: (() -> Void)?) -> __DispatchData +public func dispatch_data_create(_ buffer: UnsafePointer, _ size: Int, _ queue: DispatchQueue?, _ destructor: (() -> Void)?) -> dispatch_data_t { fatalError() } @available(*, unavailable, renamed:"getter:DispatchData.count(self:)") -public func dispatch_data_get_size(_ data: __DispatchData) -> Int +public func dispatch_data_get_size(_ data: dispatch_data_t) -> Int { fatalError() } @available(*, unavailable, renamed:"DispatchData.withUnsafeBytes(self:body:)") -public func dispatch_data_create_map(_ data: __DispatchData, _ buffer_ptr: UnsafeMutablePointer?>?, _ size_ptr: UnsafeMutablePointer?) -> __DispatchData +public func dispatch_data_create_map(_ data: dispatch_data_t, _ buffer_ptr: UnsafeMutablePointer?>?, _ size_ptr: UnsafeMutablePointer?) -> dispatch_data_t { fatalError() } @available(*, unavailable, renamed:"DispatchData.append(self:_:)") -public func dispatch_data_create_concat(_ data1: __DispatchData, _ data2: __DispatchData) -> __DispatchData +public func dispatch_data_create_concat(_ data1: dispatch_data_t, _ data2: dispatch_data_t) -> dispatch_data_t { fatalError() } @available(*, unavailable, renamed:"DispatchData.subdata(self:in:)") -public func dispatch_data_create_subrange(_ data: __DispatchData, _ offset: Int, _ length: Int) -> __DispatchData +public func dispatch_data_create_subrange(_ data: dispatch_data_t, _ offset: Int, _ length: Int) -> dispatch_data_t { fatalError() } @available(*, unavailable, renamed:"DispatchData.enumerateBytes(self:block:)") -public func dispatch_data_apply(_ data: __DispatchData, _ applier: (__DispatchData, Int, UnsafePointer, Int) -> Bool) -> Bool +public func dispatch_data_apply(_ data: dispatch_data_t, _ applier: (dispatch_data_t, Int, UnsafePointer, Int) -> Bool) -> Bool { fatalError() } @available(*, unavailable, renamed:"DispatchData.region(self:location:)") -public func dispatch_data_copy_region(_ data: __DispatchData, _ location: Int, _ offset_ptr: UnsafeMutablePointer) -> __DispatchData +public func dispatch_data_copy_region(_ data: dispatch_data_t, _ location: Int, _ offset_ptr: UnsafeMutablePointer) -> dispatch_data_t { fatalError() } @@ -163,19 +165,19 @@ public func dispatch_get_main_queue() -> DispatchQueue } @available(*, unavailable, renamed:"DispatchQueueAttributes.initiallyInactive") -public func dispatch_queue_attr_make_initially_inactive(_ attr: __OS_dispatch_queue_attr?) -> __OS_dispatch_queue_attr +public func dispatch_queue_attr_make_initially_inactive(_ attr: dispatch_queue_attr_t?) -> dispatch_queue_attr_t { fatalError() } @available(*, unavailable, renamed:"DispatchQueueAttributes.autoreleaseWorkItem") -public func dispatch_queue_attr_make_with_autorelease_frequency(_ attr: __OS_dispatch_queue_attr?, _ frequency: __dispatch_autorelease_frequency_t) -> __OS_dispatch_queue_attr +public func dispatch_queue_attr_make_with_autorelease_frequency(_ attr: dispatch_queue_attr_t?, _ frequency: dispatch_autorelease_frequency_t) -> dispatch_queue_attr_t { fatalError() } @available(*, unavailable, renamed:"DispatchQueueAttributes.qosUserInitiated") -public func dispatch_queue_attr_make_with_qos_class(_ attr: __OS_dispatch_queue_attr?, _ qos_class: qos_class_t, _ relative_priority: Int32) -> __OS_dispatch_queue_attr +public func dispatch_queue_attr_make_with_qos_class(_ attr: dispatch_queue_attr_t?, _ qos_class: dispatch_qos_class_t, _ relative_priority: Int32) -> dispatch_queue_attr_t { fatalError() } @@ -187,7 +189,7 @@ public func dispatch_queue_get_label(_ queue: DispatchQueue?) -> UnsafePointer?) -> qos_class_t +public func dispatch_queue_get_qos_class(_ queue: DispatchQueue, _ relative_priority_ptr: UnsafeMutablePointer?) -> dispatch_qos_class_t { fatalError() } @@ -259,7 +261,7 @@ public func dispatch_semaphore_signal(_ dsema: DispatchSemaphore) -> Int } @available(*, unavailable, message:"Use DispatchSource class methods") -public func dispatch_source_create(_ type: __dispatch_source_type_t, _ handle: UInt, _ mask: UInt, _ queue: DispatchQueue?) -> DispatchSource +public func dispatch_source_create(_ type: dispatch_source_type_t, _ handle: UInt, _ mask: UInt, _ queue: DispatchQueue?) -> DispatchSource { fatalError() } diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 6f7b541e9..1710846f0 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -12,6 +12,8 @@ // dispatch/queue.h +import CDispatch + public struct DispatchQueueAttributes : OptionSet { public let rawValue: UInt64 public init(rawValue: UInt64) { self.rawValue = rawValue } @@ -49,38 +51,38 @@ public struct DispatchQueueAttributes : OptionSet { @available(*, deprecated, message: ".noQoS has no effect, it should not be used") public static let noQoS = DispatchQueueAttributes(rawValue: 1<<11) - private var attr: __OS_dispatch_queue_attr? { - var attr: __OS_dispatch_queue_attr? + private var attr: dispatch_queue_attr_t? { + var attr: dispatch_queue_attr_t? if self.contains(.concurrent) { attr = _swift_dispatch_queue_concurrent() } if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) { if self.contains(.initiallyInactive) { - attr = __dispatch_queue_attr_make_initially_inactive(attr) + attr = CDispatch.dispatch_queue_attr_make_initially_inactive(attr) } if self.contains(.autoreleaseWorkItem) { // DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM - attr = __dispatch_queue_attr_make_with_autorelease_frequency(attr, __dispatch_autorelease_frequency_t(1)) + attr = CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(1)) } else if self.contains(.autoreleaseInherit) { // DISPATCH_AUTORELEASE_FREQUENCY_INHERIT - attr = __dispatch_queue_attr_make_with_autorelease_frequency(attr, __dispatch_autorelease_frequency_t(0)) + attr = CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(0)) } else if self.contains(.autoreleaseNever) { // DISPATCH_AUTORELEASE_FREQUENCY_NEVER - attr = __dispatch_queue_attr_make_with_autorelease_frequency(attr, __dispatch_autorelease_frequency_t(2)) + attr = CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(2)) } } if #available(OSX 10.10, iOS 8.0, *) { if self.contains(.qosUserInteractive) { - attr = __dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_USER_INTERACTIVE, 0) + attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_USER_INTERACTIVE.rawValue, 0) } else if self.contains(.qosUserInitiated) { - attr = __dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_USER_INITIATED, 0) + attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_USER_INITIATED.rawValue, 0) } else if self.contains(.qosDefault) { - attr = __dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_DEFAULT, 0) + attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_DEFAULT.rawValue, 0) } else if self.contains(.qosUtility) { - attr = __dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_UTILITY, 0) + attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_UTILITY.rawValue, 0) } else if self.contains(.qosBackground) { - attr = __dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_BACKGROUND, 0) + attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_BACKGROUND.rawValue, 0) } } return attr @@ -143,11 +145,11 @@ public extension DispatchQueue { internal var _translatedValue: Int { if #available(OSX 10.10, iOS 8.0, *) { - if self.contains(.qosUserInteractive) { return Int(QOS_CLASS_USER_INTERACTIVE.rawValue) } - else if self.contains(.qosUserInitiated) { return Int(QOS_CLASS_USER_INITIATED.rawValue) } - else if self.contains(.qosDefault) { return Int(QOS_CLASS_DEFAULT.rawValue) } - else if self.contains(.qosUtility) { return Int(QOS_CLASS_UTILITY.rawValue) } - else { return Int(QOS_CLASS_BACKGROUND.rawValue) } + if self.contains(.qosUserInteractive) { return Int(_OSQoSClass.QOS_CLASS_USER_INTERACTIVE.rawValue) } + else if self.contains(.qosUserInitiated) { return Int(_OSQoSClass.QOS_CLASS_USER_INITIATED.rawValue) } + else if self.contains(.qosDefault) { return Int(_OSQoSClass.QOS_CLASS_DEFAULT.rawValue) } + else if self.contains(.qosUtility) { return Int(_OSQoSClass.QOS_CLASS_UTILITY.rawValue) } + else { return Int(_OSQoSClass.QOS_CLASS_BACKGROUND.rawValue) } } if self.contains(._priorityHigh) { return 2 } // DISPATCH_QUEUE_PRIORITY_HIGH else if self.contains(._priorityDefault) { return 0 } // DISPATCH_QUEUE_PRIORITY_DEFAULT @@ -162,16 +164,17 @@ public extension DispatchQueue { } public class var main: DispatchQueue { - return _swift_dispatch_get_main_queue() + return DispatchQueue(queue: _swift_dispatch_get_main_queue()) } public class func global(attributes: GlobalAttributes = []) -> DispatchQueue { - return __dispatch_get_global_queue(attributes._translatedValue, 0) + // SubOptimal? Should we be caching these global DispatchQueue objects? + return DispatchQueue(queue:dispatch_get_global_queue(attributes._translatedValue, 0)) } public class func getSpecific(key: DispatchSpecificKey) -> T? { let k = Unmanaged.passUnretained(key).toOpaque() - if let p = __dispatch_get_specific(k) { + if let p = CDispatch.dispatch_get_specific(k) { let v = Unmanaged<_DispatchSpecificValue> .fromOpaque(p) .takeUnretainedValue() @@ -194,14 +197,12 @@ public extension DispatchQueue { } public var label: String { - return String(validatingUTF8: __dispatch_queue_get_label(self))! + return String(validatingUTF8: dispatch_queue_get_label(self.__wrapped))! } @available(OSX 10.10, iOS 8.0, *) public func sync(execute workItem: DispatchWorkItem) { - // _swift_dispatch_sync preserves the @convention(block) for - // work item blocks. - _swift_dispatch_sync(self, workItem._block) + dispatch_sync(self.__wrapped, workItem._block) } @available(OSX 10.10, iOS 8.0, *) @@ -209,37 +210,37 @@ public extension DispatchQueue { // _swift_dispatch_{group,}_async preserves the @convention(block) // for work item blocks. if let g = workItem._group { - _swift_dispatch_group_async(g, self, workItem._block) + dispatch_group_async(g.__wrapped, self.__wrapped, workItem._block) } else { - _swift_dispatch_async(self, workItem._block) + dispatch_async(self.__wrapped, workItem._block) } } public func async(group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { if group == nil && qos == .unspecified && flags.isEmpty { // Fast-path route for the most common API usage - __dispatch_async(self, work) + dispatch_async(self.__wrapped, work) return } if #available(OSX 10.10, iOS 8.0, *), (qos != .unspecified || !flags.isEmpty) { let workItem = DispatchWorkItem(qos: qos, flags: flags, block: work) if let g = group { - _swift_dispatch_group_async(g, self, workItem._block) + dispatch_group_async(g.__wrapped, self.__wrapped, workItem._block) } else { - _swift_dispatch_async(self, workItem._block) + dispatch_async(self.__wrapped, workItem._block) } } else { if let g = group { - __dispatch_group_async(g, self, work) + dispatch_group_async(g.__wrapped, self.__wrapped, work) } else { - __dispatch_async(self, work) + dispatch_async(self.__wrapped, work) } } } private func _syncBarrier(block: @noescape () -> ()) { - __dispatch_barrier_sync(self, block) + dispatch_barrier_sync(self.__wrapped, block) } private func _syncHelper( @@ -304,41 +305,41 @@ public extension DispatchQueue { public func after(when: DispatchTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: work) - __dispatch_after(when.rawValue, self, item._block) + dispatch_after(when.rawValue, self.__wrapped, item._block) } else { - __dispatch_after(when.rawValue, self, work) + dispatch_after(when.rawValue, self.__wrapped, work) } } @available(OSX 10.10, iOS 8.0, *) public func after(when: DispatchTime, execute: DispatchWorkItem) { - __dispatch_after(when.rawValue, self, execute._block) + dispatch_after(when.rawValue, self.__wrapped, execute._block) } public func after(walltime when: DispatchWallTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: work) - __dispatch_after(when.rawValue, self, item._block) + dispatch_after(when.rawValue, self.__wrapped, item._block) } else { - __dispatch_after(when.rawValue, self, work) + dispatch_after(when.rawValue, self.__wrapped, work) } } @available(OSX 10.10, iOS 8.0, *) public func after(walltime when: DispatchWallTime, execute: DispatchWorkItem) { - __dispatch_after(when.rawValue, self, execute._block) + dispatch_after(when.rawValue, self.__wrapped, execute._block) } @available(OSX 10.10, iOS 8.0, *) public var qos: DispatchQoS { var relPri: Int32 = 0 - let cls = DispatchQoS.QoSClass(qosClass: __dispatch_queue_get_qos_class(self, &relPri))! + let cls = DispatchQoS.QoSClass(qosClass: _OSQoSClass(qosClass: dispatch_queue_get_qos_class(self.__wrapped, &relPri))!)! return DispatchQoS(qosClass: cls, relativePriority: Int(relPri)) } public func getSpecific(key: DispatchSpecificKey) -> T? { let k = Unmanaged.passUnretained(key).toOpaque() - if let p = __dispatch_queue_get_specific(self, k) { + if let p = dispatch_queue_get_specific(self.__wrapped, k) { let v = Unmanaged<_DispatchSpecificValue> .fromOpaque(p) .takeUnretainedValue() @@ -351,7 +352,7 @@ public extension DispatchQueue { let v = _DispatchSpecificValue(value: value) let k = Unmanaged.passUnretained(key).toOpaque() let p = Unmanaged.passRetained(v).toOpaque() - __dispatch_queue_set_specific(self, k, p, _destructDispatchSpecificValue) + dispatch_queue_set_specific(self.__wrapped, k, p, _destructDispatchSpecificValue) } } @@ -408,22 +409,13 @@ private func _destructDispatchSpecificValue(ptr: UnsafeMutablePointer?) { } @_silgen_name("_swift_dispatch_queue_concurrent") -internal func _swift_dispatch_queue_concurrent() -> __OS_dispatch_queue_attr +internal func _swift_dispatch_queue_concurrent() -> dispatch_queue_attr_t @_silgen_name("_swift_dispatch_get_main_queue") -internal func _swift_dispatch_get_main_queue() -> DispatchQueue +internal func _swift_dispatch_get_main_queue() -> dispatch_queue_t @_silgen_name("_swift_dispatch_apply_current_root_queue") -internal func _swift_dispatch_apply_current_root_queue() -> DispatchQueue - -@_silgen_name("_swift_dispatch_async") -internal func _swift_dispatch_async(_ queue: DispatchQueue, _ block: _DispatchBlock) - -@_silgen_name("_swift_dispatch_group_async") -internal func _swift_dispatch_group_async(_ group: DispatchGroup, _ queue: DispatchQueue, _ block: _DispatchBlock) - -@_silgen_name("_swift_dispatch_sync") -internal func _swift_dispatch_sync(_ queue: DispatchQueue, _ block: _DispatchBlock) +internal func _swift_dispatch_apply_current_root_queue() -> dispatch_queue_t @_silgen_name("_swift_dispatch_apply_current") internal func _swift_dispatch_apply_current(_ iterations: Int, _ block: @convention(block) @noescape (Int) -> Void) diff --git a/src/swift/Source.swift b/src/swift/Source.swift index 6ea3960f0..2830f010e 100644 --- a/src/swift/Source.swift +++ b/src/swift/Source.swift @@ -10,51 +10,50 @@ // //===----------------------------------------------------------------------===// -// import Foundation +import CDispatch public extension DispatchSourceType { - typealias DispatchSourceHandler = @convention(block) () -> Void public func setEventHandler(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], handler: DispatchSourceHandler?) { if #available(OSX 10.10, iOS 8.0, *), let h = handler where qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: h) - __dispatch_source_set_event_handler(self as! DispatchSource, item._block) + CDispatch.dispatch_source_set_event_handler((self as! DispatchSource).__wrapped, item._block) } else { - __dispatch_source_set_event_handler(self as! DispatchSource, handler) + CDispatch.dispatch_source_set_event_handler((self as! DispatchSource).__wrapped, handler) } } @available(OSX 10.10, iOS 8.0, *) public func setEventHandler(handler: DispatchWorkItem) { - __dispatch_source_set_event_handler(self as! DispatchSource, handler._block) + CDispatch.dispatch_source_set_event_handler((self as! DispatchSource).__wrapped, handler._block) } public func setCancelHandler(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], handler: DispatchSourceHandler?) { if #available(OSX 10.10, iOS 8.0, *), let h = handler where qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: h) - __dispatch_source_set_cancel_handler(self as! DispatchSource, item._block) + CDispatch.dispatch_source_set_cancel_handler((self as! DispatchSource).__wrapped, item._block) } else { - __dispatch_source_set_cancel_handler(self as! DispatchSource, handler) + CDispatch.dispatch_source_set_cancel_handler((self as! DispatchSource).__wrapped, handler) } } @available(OSX 10.10, iOS 8.0, *) public func setCancelHandler(handler: DispatchWorkItem) { - __dispatch_source_set_cancel_handler(self as! DispatchSource, handler._block) + CDispatch.dispatch_source_set_cancel_handler((self as! DispatchSource).__wrapped, handler._block) } public func setRegistrationHandler(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], handler: DispatchSourceHandler?) { if #available(OSX 10.10, iOS 8.0, *), let h = handler where qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: h) - __dispatch_source_set_registration_handler(self as! DispatchSource, item._block) + CDispatch.dispatch_source_set_registration_handler((self as! DispatchSource).__wrapped, item._block) } else { - __dispatch_source_set_registration_handler(self as! DispatchSource, handler) + CDispatch.dispatch_source_set_registration_handler((self as! DispatchSource).__wrapped, handler) } } @available(OSX 10.10, iOS 8.0, *) public func setRegistrationHandler(handler: DispatchWorkItem) { - __dispatch_source_set_registration_handler(self as! DispatchSource, handler._block) + CDispatch.dispatch_source_set_registration_handler((self as! DispatchSource).__wrapped, handler._block) } @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) @@ -63,7 +62,7 @@ public extension DispatchSourceType { } public func cancel() { - __dispatch_source_cancel(self as! DispatchSource) + CDispatch.dispatch_source_cancel((self as! DispatchSource).__wrapped) } public func resume() { @@ -75,30 +74,33 @@ public extension DispatchSourceType { } public var handle: UInt { - return __dispatch_source_get_handle(self as! DispatchSource) + return CDispatch.dispatch_source_get_handle((self as! DispatchSource).__wrapped) } public var mask: UInt { - return __dispatch_source_get_mask(self as! DispatchSource) + return CDispatch.dispatch_source_get_mask((self as! DispatchSource).__wrapped) } public var data: UInt { - return __dispatch_source_get_data(self as! DispatchSource) + return CDispatch.dispatch_source_get_data((self as! DispatchSource).__wrapped) } public var isCancelled: Bool { - return __dispatch_source_testcancel(self as! DispatchSource) != 0 + return CDispatch.dispatch_source_testcancel((self as! DispatchSource).__wrapped) != 0 } } public extension DispatchSource { +#if HAVE_MACH public struct MachSendEvent : OptionSet, RawRepresentable { public let rawValue: UInt public init(rawValue: UInt) { self.rawValue = rawValue } public static let dead = MachSendEvent(rawValue: 0x1) } +#endif +#if HAVE_MACH public struct MemoryPressureEvent : OptionSet, RawRepresentable { public let rawValue: UInt public init(rawValue: UInt) { self.rawValue = rawValue } @@ -108,7 +110,9 @@ public extension DispatchSource { public static let critical = MemoryPressureEvent(rawValue: 0x4) public static let all: MemoryPressureEvent = [.normal, .warning, .critical] } +#endif +#if !os(Linux) public struct ProcessEvent : OptionSet, RawRepresentable { public let rawValue: UInt public init(rawValue: UInt) { self.rawValue = rawValue } @@ -119,6 +123,7 @@ public extension DispatchSource { public static let signal = ProcessEvent(rawValue: 0x08000000) public static let all: ProcessEvent = [.exit, .fork, .exec, .signal] } +#endif public struct TimerFlags : OptionSet, RawRepresentable { public let rawValue: UInt @@ -144,132 +149,153 @@ public extension DispatchSource { .delete, .write, .extend, .attrib, .link, .rename, .revoke] } +#if HAVE_MACH public class func machSend(port: mach_port_t, eventMask: MachSendEvent, queue: DispatchQueue? = nil) -> DispatchSourceMachSend { - return __dispatch_source_create( - _swift_dispatch_source_type_mach_send(), UInt(port), eventMask.rawValue, queue) as DispatchSourceMachSend + let source = dispatch_source_create(_swift_dispatch_source_type_mach_send(), UInt(port), eventMask.rawValue, queue?.__wrapped) + return DispatchSource(source: source) as DispatchSourceMachSend } +#endif +#if HAVE_MACH public class func machReceive(port: mach_port_t, queue: DispatchQueue? = nil) -> DispatchSourceMachReceive { - return __dispatch_source_create( - _swift_dispatch_source_type_mach_recv(), UInt(port), 0, queue) as DispatchSourceMachReceive + let source = dispatch_source_create(_swift_dispatch_source_type_mach_recv(), UInt(port), 0, queue?.__wrapped) + return DispatchSource(source) as DispatchSourceMachReceive } +#endif +#if HAVE_MACH public class func memoryPressure(eventMask: MemoryPressureEvent, queue: DispatchQueue? = nil) -> DispatchSourceMemoryPressure { - return __dispatch_source_create( - _swift_dispatch_source_type_memorypressure(), 0, eventMask.rawValue, queue) as DispatchSourceMemoryPressure + let source = dispatch_source_create(_swift_dispatch_source_type_memorypressure(), 0, eventMask.rawValue, queue.__wrapped) + return DispatchSourceMemoryPressure(source) } +#endif +#if !os(Linux) public class func process(identifier: pid_t, eventMask: ProcessEvent, queue: DispatchQueue? = nil) -> DispatchSourceProcess { - return __dispatch_source_create( - _swift_dispatch_source_type_proc(), UInt(identifier), eventMask.rawValue, queue) as DispatchSourceProcess + let source = dispatch_source_create(_swift_dispatch_source_type_proc(), UInt(identifier), eventMask.rawValue, queue?.__wrapped) + return DispatchSource(source: source) as DispatchSourceProcess } +#endif public class func read(fileDescriptor: Int32, queue: DispatchQueue? = nil) -> DispatchSourceRead { - return __dispatch_source_create( - _swift_dispatch_source_type_read(), UInt(fileDescriptor), 0, queue) as DispatchSourceRead + let source = dispatch_source_create(_swift_dispatch_source_type_read(), UInt(fileDescriptor), 0, queue?.__wrapped) + return DispatchSource(source: source) as DispatchSourceRead } public class func signal(signal: Int32, queue: DispatchQueue? = nil) -> DispatchSourceSignal { - return __dispatch_source_create( - _swift_dispatch_source_type_read(), UInt(signal), 0, queue) as DispatchSourceSignal + let source = dispatch_source_create(_swift_dispatch_source_type_signal(), UInt(signal), 0, queue?.__wrapped) + return DispatchSource(source: source) as DispatchSourceSignal } public class func timer(flags: TimerFlags = [], queue: DispatchQueue? = nil) -> DispatchSourceTimer { - return __dispatch_source_create(_swift_dispatch_source_type_timer(), 0, flags.rawValue, queue) as DispatchSourceTimer + let source = dispatch_source_create(_swift_dispatch_source_type_timer(), 0, flags.rawValue, queue?.__wrapped) + return DispatchSource(source: source) as DispatchSourceTimer } public class func userDataAdd(queue: DispatchQueue? = nil) -> DispatchSourceUserDataAdd { - return __dispatch_source_create(_swift_dispatch_source_type_data_add(), 0, 0, queue) as DispatchSourceUserDataAdd + let source = dispatch_source_create(_swift_dispatch_source_type_data_add(), 0, 0, queue?.__wrapped) + return DispatchSource(source: source) as DispatchSourceUserDataAdd } public class func userDataOr(queue: DispatchQueue? = nil) -> DispatchSourceUserDataOr { - return __dispatch_source_create(_swift_dispatch_source_type_data_or(), 0, 0, queue) as DispatchSourceUserDataOr + let source = dispatch_source_create(_swift_dispatch_source_type_data_or(), 0, 0, queue?.__wrapped) + return DispatchSource(source: source) as DispatchSourceUserDataOr } +#if !os(Linux) public class func fileSystemObject(fileDescriptor: Int32, eventMask: FileSystemEvent, queue: DispatchQueue? = nil) -> DispatchSourceFileSystemObject { - return __dispatch_source_create( - _swift_dispatch_source_type_vnode(), UInt(fileDescriptor), eventMask.rawValue, queue) as DispatchSourceFileSystemObject + let source = dispatch_source_create(_swift_dispatch_source_type_vnode(), UInt(fileDescriptor), eventMask.rawValue, queue?.__wrapped) + return DispatchSource(source: source) as DispatchSourceFileSystemObject } +#endif public class func write(fileDescriptor: Int32, queue: DispatchQueue? = nil) -> DispatchSourceWrite { - return __dispatch_source_create( - _swift_dispatch_source_type_write(), UInt(fileDescriptor), 0, queue) as DispatchSourceWrite + let source = dispatch_source_create(_swift_dispatch_source_type_write(), UInt(fileDescriptor), 0, queue?.__wrapped) + return DispatchSource(source: source) as DispatchSourceWrite } } +#if HAVE_MACH public extension DispatchSourceMachSend { public var handle: mach_port_t { - return mach_port_t(__dispatch_source_get_handle(self as! DispatchSource)) + return mach_port_t(dispatch_source_get_handle(self as! DispatchSource)) } public var data: DispatchSource.MachSendEvent { - let data = __dispatch_source_get_data(self as! DispatchSource) + let data = dispatch_source_get_data(self as! DispatchSource) return DispatchSource.MachSendEvent(rawValue: data) } public var mask: DispatchSource.MachSendEvent { - let mask = __dispatch_source_get_mask(self as! DispatchSource) + let mask = dispatch_source_get_mask(self as! DispatchSource) return DispatchSource.MachSendEvent(rawValue: mask) } } +#endif +#if HAVE_MACH public extension DispatchSourceMachReceive { public var handle: mach_port_t { - return mach_port_t(__dispatch_source_get_handle(self as! DispatchSource)) + return mach_port_t(dispatch_source_get_handle(self as! DispatchSource)) } } +#endif +#if HAVE_MACH public extension DispatchSourceMemoryPressure { public var data: DispatchSource.MemoryPressureEvent { - let data = __dispatch_source_get_data(self as! DispatchSource) + let data = dispatch_source_get_data(self as! DispatchSource) return DispatchSource.MemoryPressureEvent(rawValue: data) } public var mask: DispatchSource.MemoryPressureEvent { - let mask = __dispatch_source_get_mask(self as! DispatchSource) + let mask = dispatch_source_get_mask(self as! DispatchSource) return DispatchSource.MemoryPressureEvent(rawValue: mask) } } +#endif +#if !os(Linux) public extension DispatchSourceProcess { public var handle: pid_t { - return pid_t(__dispatch_source_get_handle(self as! DispatchSource)) + return pid_t(dispatch_source_get_handle(self as! DispatchSource)) } public var data: DispatchSource.ProcessEvent { - let data = __dispatch_source_get_data(self as! DispatchSource) + let data = dispatch_source_get_data(self as! DispatchSource) return DispatchSource.ProcessEvent(rawValue: data) } public var mask: DispatchSource.ProcessEvent { - let mask = __dispatch_source_get_mask(self as! DispatchSource) + let mask = dispatch_source_get_mask(self as! DispatchSource) return DispatchSource.ProcessEvent(rawValue: mask) } } +#endif public extension DispatchSourceTimer { public func scheduleOneshot(deadline: DispatchTime, leeway: DispatchTimeInterval = .nanoseconds(0)) { - __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, ~0, UInt64(leeway.rawValue)) + dispatch_source_set_timer((self as! DispatchSource).__wrapped, deadline.rawValue, ~0, UInt64(leeway.rawValue)) } public func scheduleOneshot(wallDeadline: DispatchWallTime, leeway: DispatchTimeInterval = .nanoseconds(0)) { - __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, ~0, UInt64(leeway.rawValue)) + dispatch_source_set_timer((self as! DispatchSource).__wrapped, wallDeadline.rawValue, ~0, UInt64(leeway.rawValue)) } public func scheduleRepeating(deadline: DispatchTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .nanoseconds(0)) { - __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, interval.rawValue, UInt64(leeway.rawValue)) + dispatch_source_set_timer((self as! DispatchSource).__wrapped, deadline.rawValue, interval.rawValue, UInt64(leeway.rawValue)) } public func scheduleRepeating(deadline: DispatchTime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { - __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) + dispatch_source_set_timer((self as! DispatchSource).__wrapped, deadline.rawValue, UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) } public func scheduleRepeating(wallDeadline: DispatchWallTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .nanoseconds(0)) { - __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, interval.rawValue, UInt64(leeway.rawValue)) + dispatch_source_set_timer((self as! DispatchSource).__wrapped, wallDeadline.rawValue, interval.rawValue, UInt64(leeway.rawValue)) } public func scheduleRepeating(wallDeadline: DispatchWallTime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { - __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) + dispatch_source_set_timer((self as! DispatchSource).__wrapped, wallDeadline.rawValue, UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) } } @@ -300,26 +326,28 @@ public extension DispatchSourceTimer { } @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleRepeating(self:wallDeadline:interval:leeway:)") - public func setTimer(walltime start: DispatchWalltime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { + public func setTimer(walltime start: DispatchWallTime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { scheduleRepeating(wallDeadline: start, interval: interval, leeway: leeway) } } +#if !os(Linux) public extension DispatchSourceFileSystemObject { public var handle: Int32 { - return Int32(__dispatch_source_get_handle(self as! DispatchSource)) + return Int32(dispatch_source_get_handle((self as! DispatchSource).__wrapped)) } public var data: DispatchSource.FileSystemEvent { - let data = __dispatch_source_get_data(self as! DispatchSource) + let data = dispatch_source_get_data((self as! DispatchSource).__wrapped) return DispatchSource.FileSystemEvent(rawValue: data) } public var mask: DispatchSource.FileSystemEvent { - let data = __dispatch_source_get_mask(self as! DispatchSource) + let data = dispatch_source_get_mask((self as! DispatchSource).__wrapped) return DispatchSource.FileSystemEvent(rawValue: data) } } +#endif public extension DispatchSourceUserDataAdd { /// @function mergeData @@ -334,11 +362,12 @@ public extension DispatchSourceUserDataAdd { /// as specified by the dispatch source type. A value of zero has no effect /// and will not result in the submission of the event handler block. public func mergeData(value: UInt) { - __dispatch_source_merge_data(self as! DispatchSource, value) + dispatch_source_merge_data((self as! DispatchSource).__wrapped, value) } } public extension DispatchSourceUserDataOr { +#if false /*FIXME: clashes with UserDataAdd?? */ /// @function mergeData /// /// @abstract @@ -351,39 +380,46 @@ public extension DispatchSourceUserDataOr { /// as specified by the dispatch source type. A value of zero has no effect /// and will not result in the submission of the event handler block. public func mergeData(value: UInt) { - __dispatch_source_merge_data(self as! DispatchSource, value) + dispatch_source_merge_data((self as! DispatchSource).__wrapped, value) } +#endif } @_silgen_name("_swift_dispatch_source_type_DATA_ADD") -internal func _swift_dispatch_source_type_data_add() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_data_add() -> dispatch_source_type_t @_silgen_name("_swift_dispatch_source_type_DATA_OR") -internal func _swift_dispatch_source_type_data_or() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_data_or() -> dispatch_source_type_t +#if HAVE_MACH @_silgen_name("_swift_dispatch_source_type_MACH_SEND") -internal func _swift_dispatch_source_type_mach_send() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_mach_send() -> dispatch_source_type_t @_silgen_name("_swift_dispatch_source_type_MACH_RECV") -internal func _swift_dispatch_source_type_mach_recv() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_mach_recv() -> dispatch_source_type_t @_silgen_name("_swift_dispatch_source_type_MEMORYPRESSURE") -internal func _swift_dispatch_source_type_memorypressure() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_memorypressure() -> dispatch_source_type_t +#endif +#if !os(Linux) @_silgen_name("_swift_dispatch_source_type_PROC") -internal func _swift_dispatch_source_type_proc() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_proc() -> dispatch_source_type_t +#endif @_silgen_name("_swift_dispatch_source_type_READ") -internal func _swift_dispatch_source_type_read() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_read() -> dispatch_source_type_t @_silgen_name("_swift_dispatch_source_type_SIGNAL") -internal func _swift_dispatch_source_type_signal() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_signal() -> dispatch_source_type_t @_silgen_name("_swift_dispatch_source_type_TIMER") -internal func _swift_dispatch_source_type_timer() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_timer() -> dispatch_source_type_t +#if !os(Linux) @_silgen_name("_swift_dispatch_source_type_VNODE") -internal func _swift_dispatch_source_type_vnode() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_vnode() -> dispatch_source_type_t +#endif @_silgen_name("_swift_dispatch_source_type_WRITE") -internal func _swift_dispatch_source_type_write() -> __dispatch_source_type_t +internal func _swift_dispatch_source_type_write() -> dispatch_source_type_t diff --git a/src/swift/Time.swift b/src/swift/Time.swift index e0b63b814..76a6979eb 100644 --- a/src/swift/Time.swift +++ b/src/swift/Time.swift @@ -14,11 +14,13 @@ // DISPATCH_TIME_NOW: ok // DISPATCH_TIME_FOREVER: ok +import CDispatch + public struct DispatchTime { public let rawValue: dispatch_time_t public static func now() -> DispatchTime { - let t = __dispatch_time(0, 0) + let t = CDispatch.dispatch_time(0, 0) return DispatchTime(rawValue: t) } @@ -33,7 +35,7 @@ public struct DispatchWallTime { public let rawValue: dispatch_time_t public static func now() -> DispatchWallTime { - return DispatchWallTime(rawValue: __dispatch_walltime(nil, 0)) + return DispatchWallTime(rawValue: CDispatch.dispatch_walltime(nil, 0)) } public static let distantFuture = DispatchWallTime(rawValue: ~0) @@ -44,7 +46,7 @@ public struct DispatchWallTime { public init(time: timespec) { var t = time - self.rawValue = __dispatch_walltime(&t, 0) + self.rawValue = CDispatch.dispatch_walltime(&t, 0) } } @@ -68,41 +70,41 @@ public enum DispatchTimeInterval { } public func +(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime { - let t = __dispatch_time(time.rawValue, Int64(interval.rawValue)) + let t = CDispatch.dispatch_time(time.rawValue, Int64(interval.rawValue)) return DispatchTime(rawValue: t) } public func -(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime { - let t = __dispatch_time(time.rawValue, -Int64(interval.rawValue)) + let t = CDispatch.dispatch_time(time.rawValue, -Int64(interval.rawValue)) return DispatchTime(rawValue: t) } public func +(time: DispatchTime, seconds: Double) -> DispatchTime { - let t = __dispatch_time(time.rawValue, Int64(seconds * Double(NSEC_PER_SEC))) + let t = CDispatch.dispatch_time(time.rawValue, Int64(seconds * Double(NSEC_PER_SEC))) return DispatchTime(rawValue: t) } public func -(time: DispatchTime, seconds: Double) -> DispatchTime { - let t = __dispatch_time(time.rawValue, Int64(-seconds * Double(NSEC_PER_SEC))) + let t = CDispatch.dispatch_time(time.rawValue, Int64(-seconds * Double(NSEC_PER_SEC))) return DispatchTime(rawValue: t) } public func +(time: DispatchWallTime, interval: DispatchTimeInterval) -> DispatchWallTime { - let t = __dispatch_time(time.rawValue, Int64(interval.rawValue)) + let t = CDispatch.dispatch_time(time.rawValue, Int64(interval.rawValue)) return DispatchWallTime(rawValue: t) } public func -(time: DispatchWallTime, interval: DispatchTimeInterval) -> DispatchWallTime { - let t = __dispatch_time(time.rawValue, -Int64(interval.rawValue)) + let t = CDispatch.dispatch_time(time.rawValue, -Int64(interval.rawValue)) return DispatchWallTime(rawValue: t) } public func +(time: DispatchWallTime, seconds: Double) -> DispatchWallTime { - let t = __dispatch_time(time.rawValue, Int64(seconds * Double(NSEC_PER_SEC))) + let t = CDispatch.dispatch_time(time.rawValue, Int64(seconds * Double(NSEC_PER_SEC))) return DispatchWallTime(rawValue: t) } public func -(time: DispatchWallTime, seconds: Double) -> DispatchWallTime { - let t = __dispatch_time(time.rawValue, Int64(-seconds * Double(NSEC_PER_SEC))) + let t = CDispatch.dispatch_time(time.rawValue, Int64(-seconds * Double(NSEC_PER_SEC))) return DispatchWallTime(rawValue: t) } diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift new file mode 100644 index 000000000..a0d1e8e4f --- /dev/null +++ b/src/swift/Wrapper.swift @@ -0,0 +1,297 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import CDispatch + +// This file contains declarations that are provided by the +// importer via Dispatch.apinote when the platform has Objective-C support + +public class DispatchObject { + // TODO: add deinit method to invoke dispatch_release on wrapped() + + internal func wrapped() -> dispatch_object_t { + assert(false, "should be override in subclass") + } + + public func setTarget(queue:DispatchQueue) { + dispatch_set_target_queue(wrapped(), queue.__wrapped) + } + + public func activate() { + dispatch_activate(wrapped()) + } + + public func suspend() { + dispatch_suspend(wrapped()) + } + + public func resume() { + dispatch_resume(wrapped()) + } +} + + +public class DispatchGroup : DispatchObject { + internal let __wrapped:dispatch_group_t; + + internal override func wrapped() -> dispatch_object_t { + return unsafeBitCast(__wrapped, to: dispatch_object_t.self) + } + + public override init() { + __wrapped = dispatch_group_create() + } + + public func enter() { + dispatch_group_enter(__wrapped) + } + + public func leave() { + dispatch_group_enter(__wrapped) + } +} + +public class DispatchSemaphore : DispatchObject { + internal let __wrapped: dispatch_semaphore_t; + + internal override func wrapped() -> dispatch_object_t { + return unsafeBitCast(__wrapped, to: dispatch_object_t.self) + } + + public init(value: Int) { + __wrapped = dispatch_semaphore_create(value) + } +} + +public class DispatchIO : DispatchObject { + internal let __wrapped:dispatch_io_t + + internal override func wrapped() -> dispatch_object_t { + return unsafeBitCast(__wrapped, to: dispatch_object_t.self) + } + + internal init(__type: UInt, fd: Int32, queue: DispatchQueue, + handler: (error: Int32) -> Void) { + __wrapped = dispatch_io_create(__type, fd, queue.__wrapped, handler) + } + + internal init(__type: UInt, path: UnsafePointer, oflag: Int32, + mode: mode_t, queue: DispatchQueue, handler: (error: Int32) -> Void) { + __wrapped = dispatch_io_create_with_path(__type, path, oflag, mode, queue.__wrapped, handler) + } + + internal init(__type: UInt, io: DispatchIO, + queue: DispatchQueue, handler: (error: Int32) -> Void) { + __wrapped = dispatch_io_create_with_io(__type, io.__wrapped, queue.__wrapped, handler) + } + + internal init(queue:dispatch_queue_t) { + __wrapped = queue + } + + public func barrier(execute: () -> ()) { + dispatch_io_barrier(self.__wrapped, execute) + } + + public var fileDescriptor: Int32 { + return dispatch_io_get_descriptor(__wrapped) + } + + public func setLimit(highWater: Int) { + dispatch_io_set_high_water(__wrapped, highWater) + } + + public func setLimit(lowWater: Int) { + dispatch_io_set_low_water(__wrapped, lowWater) + } +} + +public class DispatchQueue : DispatchObject { + internal let __wrapped:dispatch_queue_t; + + internal override func wrapped() -> dispatch_object_t { + return unsafeBitCast(__wrapped, to: dispatch_object_t.self) + } + + internal init(__label: String, attr: dispatch_queue_attr_t?) { + __wrapped = dispatch_queue_create(__label, attr) + } + + internal init(__label: String, attr: dispatch_queue_attr_t?, queue: DispatchQueue?) { + __wrapped = dispatch_queue_create_with_target(__label, attr, queue?.__wrapped) + } + + internal init(queue:dispatch_queue_t) { + __wrapped = queue + } + + public func sync(execute workItem: @noescape ()->()) { + dispatch_sync(self.__wrapped, workItem) + } +} + +public class DispatchSource : DispatchObject, + DispatchSourceType, DispatchSourceRead, + DispatchSourceSignal, DispatchSourceTimer, + DispatchSourceUserDataAdd, DispatchSourceUserDataOr, + DispatchSourceWrite { + internal let __wrapped:dispatch_source_t + + internal override func wrapped() -> dispatch_object_t { + return unsafeBitCast(__wrapped, to: dispatch_object_t.self) + } + + internal init(source:dispatch_source_t) { + __wrapped = source + } +} + +#if HAVE_MACH +extension DispatchSource : DispatchSourceMachSend, + DispatchSourceMachReceive, DispatchSourceMemoryPressure { +} +#endif + +#if !os(Linux) +extension DispatchSource : DispatchSourceProcess, + DispatchSourceFileSystemObject { +} +#endif + +public typealias DispatchSourceHandler = @convention(block) () -> Void + +public protocol DispatchSourceType { + func setEventHandler(qos: DispatchQoS, flags: DispatchWorkItemFlags, handler: DispatchSourceHandler?) + + func setEventHandler(handler: DispatchWorkItem) + + func setCancelHandler(qos: DispatchQoS, flags: DispatchWorkItemFlags, handler: DispatchSourceHandler?) + + func setCancelHandler(handler: DispatchWorkItem) + + func setRegistrationHandler(qos: DispatchQoS, flags: DispatchWorkItemFlags, handler: DispatchSourceHandler?) + + func setRegistrationHandler(handler: DispatchWorkItem) + + func cancel() + + func resume() + + func suspend() + + var handle: UInt { get } + + var mask: UInt { get } + + var data: UInt { get } + + var isCancelled: Bool { get } +} + +public protocol DispatchSourceUserDataAdd : DispatchSourceType { + func mergeData(value: UInt) +} + +public protocol DispatchSourceUserDataOr { +#if false /*FIXME: clashes with UserDataAdd?? */ + func mergeData(value: UInt) +#endif +} + +#if HAVE_MACH +public protocol DispatchSourceMachSend : DispatchSourceType { + public var handle: mach_port_t { get } + + public var data: DispatchSource.MachSendEvent { get } + + public var mask: DispatchSource.MachSendEvent { get } +} +#endif + +#if HAVE_MACH +public protocol DispatchSourceMachReceive : DispatchSourceType { + var handle: mach_port_t { get } +} +#endif + +#if HAVE_MACH +public protocol DispatchSourceMemoryPressure : DispatchSourceType { + public var data: DispatchSource.MemoryPressureEvent { get } + + public var mask: DispatchSource.MemoryPressureEvent { get } +} +#endif + +#if !os(Linux) +public protocol DispatchSourceProcess : DispatchSourceType { + var handle: pid_t { get } + + var data: DispatchSource.ProcessEvent { get } + + var mask: DispatchSource.ProcessEvent { get } +} +#endif + +public protocol DispatchSourceRead : DispatchSourceType { +} + +public protocol DispatchSourceSignal : DispatchSourceType { +} + +public protocol DispatchSourceTimer : DispatchSourceType { + func setTimer(start: DispatchTime, leeway: DispatchTimeInterval) + + func setTimer(walltime start: DispatchWallTime, leeway: DispatchTimeInterval) + + func setTimer(start: DispatchTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval) + + func setTimer(start: DispatchTime, interval: Double, leeway: DispatchTimeInterval) + + func setTimer(walltime start: DispatchWallTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval) + + func setTimer(walltime start: DispatchWallTime, interval: Double, leeway: DispatchTimeInterval) +} + +#if !os(Linux) +public protocol DispatchSourceFileSystemObject : DispatchSourceType { + var handle: Int32 { get } + + var data: DispatchSource.FileSystemEvent { get } + + var mask: DispatchSource.FileSystemEvent { get } +} +#endif + +public protocol DispatchSourceWrite : DispatchSourceType { +} + + +internal enum _OSQoSClass : UInt32 { + case QOS_CLASS_USER_INTERACTIVE = 0x21 + case QOS_CLASS_USER_INITIATED = 0x19 + case QOS_CLASS_DEFAULT = 0x15 + case QOS_CLASS_UTILITY = 0x11 + case QOS_CLASS_BACKGROUND = 0x09 + case QOS_CLASS_UNSPECIFIED = 0x00 + + internal init?(qosClass:dispatch_qos_class_t) { + switch qosClass { + case 0x21: self = .QOS_CLASS_USER_INTERACTIVE + case 0x19: self = .QOS_CLASS_USER_INITIATED + case 0x15: self = .QOS_CLASS_DEFAULT + case 0x11: self = QOS_CLASS_UTILITY + case 0x09: self = QOS_CLASS_BACKGROUND + case 0x00: self = QOS_CLASS_UNSPECIFIED + default: return nil + } + } +} From acea6474c0fa6ce1adfe87235a6c863a57863659 Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Fri, 1 Jul 2016 12:20:59 -0700 Subject: [PATCH 18/67] Merge pull request #94 from dgrove-oss/swift3-overlay-pr1 Initial Swift3 wrapping overlay for libdispatch Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 3e090001e..46fabf2f1 100644 --- a/PATCHES +++ b/PATCHES @@ -247,3 +247,4 @@ github commits starting with 29bdc2f from [4fa8d8d] APPLIED rdar://26822213 [e922531] APPLIED rdar://26822213 [195cbcf] APPLIED rdar://27303844 +[5b893c8] APPLIED rdar://27303844 From c40d5546f559752dd607524f69b95b2da9f75927 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 13 Jul 2016 18:01:20 -0700 Subject: [PATCH 19/67] need to guard definition of _dispatch_data_destructor_munmap Signed-off-by: Daniel A. Steffen --- src/data.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/data.c b/src/data.c index 489eaf265..644328911 100644 --- a/src/data.c +++ b/src/data.c @@ -108,11 +108,12 @@ const dispatch_block_t _dispatch_data_destructor_none = ^{ DISPATCH_INTERNAL_CRASH(0, "none destructor called"); }; +#if !HAVE_MACH const dispatch_block_t _dispatch_data_destructor_munmap = ^{ DISPATCH_INTERNAL_CRASH(0, "munmap destructor called"); }; - -#if HAVE_MACH +#else +// _dispatch_data_destructor_munmap is a linker alias to the following const dispatch_block_t _dispatch_data_destructor_vm_deallocate = ^{ DISPATCH_INTERNAL_CRASH(0, "vmdeallocate destructor called"); }; From 17b73825518f292a6da2d5ea8dd932f51782e51e Mon Sep 17 00:00:00 2001 From: David Grove Date: Tue, 5 Jul 2016 14:31:17 -0400 Subject: [PATCH 20/67] avoid requiring __DISPATCH_BUILDING_SWIFT_MODULE__ macro on Linux Instead of using a special macro, check for __has_feature(modules) to activate including stdio.h in dispatch.h on Linux. Also, fix one place where OS_OBJECT_SWIFT_3 was used outside of an OS_OBJECT_USE_OBJC block (to prepare for SWIFT_SDK_OVERLAY_DISPATCH_EPOCH being defined by the clang importer on non-Darwin platforms). Signed-off-by: Daniel A. Steffen --- dispatch/dispatch.h | 4 ++-- dispatch/object.h | 2 +- src/Makefile.am | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index ca7e05706..944312b47 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -48,8 +48,8 @@ #include #ifdef __linux__ -#ifdef __DISPATCH_BUILDING_SWIFT_MODULE__ -#include // for off_t +#if __has_feature(modules) +#include // for off_t (to match Glibc.modulemap) #endif #endif diff --git a/dispatch/object.h b/dispatch/object.h index 041ee8116..8b2030138 100644 --- a/dispatch/object.h +++ b/dispatch/object.h @@ -108,7 +108,7 @@ typedef union { #define DISPATCH_RETURNS_RETAINED #endif -#if OS_OBJECT_SWIFT3 +#if OS_OBJECT_SWIFT3 && OS_OBJECT_USE_OBJC #define DISPATCH_SOURCE_TYPE_DECL(name) \ DISPATCH_EXPORT struct dispatch_source_type_s \ _dispatch_source_type_##name; \ diff --git a/src/Makefile.am b/src/Makefile.am index 58fa4ef12..f06a49347 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -149,7 +149,7 @@ SWIFT_GEN_FILES= \ $(SWIFT_OBJ_FILES:%=%.~partial.swiftdoc) \ $(SWIFT_OBJ_FILES:%=%.~partial.swiftdeps) -SWIFTC_FLAGS = -Xcc -D__DISPATCH_BUILDING_SWIFT_MODULE__=1 -Xcc -fmodule-map-file=$(abs_top_srcdir)/dispatch/module.modulemap -I$(abs_top_srcdir) -Xcc -fblocks +SWIFTC_FLAGS = -Xcc -fmodule-map-file=$(abs_top_srcdir)/dispatch/module.modulemap -I$(abs_top_srcdir) -Xcc -fblocks $(abs_builddir)/swift/%.o: $(abs_srcdir)/swift/%.swift $(SWIFTC) -frontend -c $(SWIFT_ABS_SRC_FILES) -primary-file $< \ From 47369eb66b3ff2e87e7db8c9bd2fe1f655a869f0 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 6 Jul 2016 07:28:44 -0700 Subject: [PATCH 21/67] Merge pull request #97 from dgrove-oss/define-dispatch-bridging-macro-on-linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use SWIFT_SDK_OVERLAY_DISPATCH_EPOCH to detect that an overlay is bei… Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 46fabf2f1..208dafe0f 100644 --- a/PATCHES +++ b/PATCHES @@ -248,3 +248,4 @@ github commits starting with 29bdc2f from [e922531] APPLIED rdar://26822213 [195cbcf] APPLIED rdar://27303844 [5b893c8] APPLIED rdar://27303844 +[92689ed] APPLIED rdar://27303844 From 13dd2ef7948b60bb2d0fb5c486462609e193c04e Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 13 Jul 2016 17:46:31 -0700 Subject: [PATCH 22/67] missing #ifdef __has_feature Signed-off-by: Daniel A. Steffen --- dispatch/dispatch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index 944312b47..5fa04565b 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -47,7 +47,7 @@ #include #include -#ifdef __linux__ +#if defined(__linux__) && defined(__has_feature) #if __has_feature(modules) #include // for off_t (to match Glibc.modulemap) #endif From f3fc31760547d506490fc9faa85462729207bdbb Mon Sep 17 00:00:00 2001 From: David Grove Date: Tue, 5 Jul 2016 16:30:25 -0400 Subject: [PATCH 23/67] release wrapped C objects when Swift object deinitialized ARC support in wrapping overlay. Add deinit methods to wrapping Swift classes that call dispatch_release on the wrapped C objects. Signed-off-by: Daniel A. Steffen --- src/swift/DispatchStubs.cc | 6 ++++++ src/swift/Wrapper.swift | 36 +++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/swift/DispatchStubs.cc b/src/swift/DispatchStubs.cc index 62a53ef6b..1e5ec74f7 100644 --- a/src/swift/DispatchStubs.cc +++ b/src/swift/DispatchStubs.cc @@ -159,6 +159,12 @@ _swift_dispatch_sync(dispatch_queue_t queue, dispatch_block_t block) { dispatch_sync(queue, block); } +SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE +extern "C" void +_swift_dispatch_release(dispatch_object_t obj) { + dispatch_release(obj); +} + // DISPATCH_RUNTIME_STDLIB_INTERFACE // extern "C" dispatch_queue_t // _swift_apply_current_root_queue() { diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index a0d1e8e4f..ef7bf30d9 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -16,10 +16,9 @@ import CDispatch // importer via Dispatch.apinote when the platform has Objective-C support public class DispatchObject { - // TODO: add deinit method to invoke dispatch_release on wrapped() internal func wrapped() -> dispatch_object_t { - assert(false, "should be override in subclass") + fatalError("should be overriden in subclass") } public func setTarget(queue:DispatchQueue) { @@ -43,7 +42,7 @@ public class DispatchObject { public class DispatchGroup : DispatchObject { internal let __wrapped:dispatch_group_t; - internal override func wrapped() -> dispatch_object_t { + final internal override func wrapped() -> dispatch_object_t { return unsafeBitCast(__wrapped, to: dispatch_object_t.self) } @@ -51,6 +50,10 @@ public class DispatchGroup : DispatchObject { __wrapped = dispatch_group_create() } + deinit { + _swift_dispatch_release(wrapped()) + } + public func enter() { dispatch_group_enter(__wrapped) } @@ -63,19 +66,23 @@ public class DispatchGroup : DispatchObject { public class DispatchSemaphore : DispatchObject { internal let __wrapped: dispatch_semaphore_t; - internal override func wrapped() -> dispatch_object_t { + final internal override func wrapped() -> dispatch_object_t { return unsafeBitCast(__wrapped, to: dispatch_object_t.self) } public init(value: Int) { __wrapped = dispatch_semaphore_create(value) } + + deinit { + _swift_dispatch_release(wrapped()) + } } public class DispatchIO : DispatchObject { internal let __wrapped:dispatch_io_t - internal override func wrapped() -> dispatch_object_t { + final internal override func wrapped() -> dispatch_object_t { return unsafeBitCast(__wrapped, to: dispatch_object_t.self) } @@ -98,6 +105,10 @@ public class DispatchIO : DispatchObject { __wrapped = queue } + deinit { + _swift_dispatch_release(wrapped()) + } + public func barrier(execute: () -> ()) { dispatch_io_barrier(self.__wrapped, execute) } @@ -118,7 +129,7 @@ public class DispatchIO : DispatchObject { public class DispatchQueue : DispatchObject { internal let __wrapped:dispatch_queue_t; - internal override func wrapped() -> dispatch_object_t { + final internal override func wrapped() -> dispatch_object_t { return unsafeBitCast(__wrapped, to: dispatch_object_t.self) } @@ -134,6 +145,10 @@ public class DispatchQueue : DispatchObject { __wrapped = queue } + deinit { + _swift_dispatch_release(wrapped()) + } + public func sync(execute workItem: @noescape ()->()) { dispatch_sync(self.__wrapped, workItem) } @@ -146,13 +161,17 @@ public class DispatchSource : DispatchObject, DispatchSourceWrite { internal let __wrapped:dispatch_source_t - internal override func wrapped() -> dispatch_object_t { + final internal override func wrapped() -> dispatch_object_t { return unsafeBitCast(__wrapped, to: dispatch_object_t.self) } internal init(source:dispatch_source_t) { __wrapped = source } + + deinit { + _swift_dispatch_release(wrapped()) + } } #if HAVE_MACH @@ -295,3 +314,6 @@ internal enum _OSQoSClass : UInt32 { } } } + +@_silgen_name("_swift_dispatch_release") +internal func _swift_dispatch_release(_ obj: dispatch_object_t) -> Void From c9c0aac3294e3348c3c2c5a28e3ffca9a54ac6da Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Wed, 6 Jul 2016 10:24:13 -0700 Subject: [PATCH 24/67] Merge pull request #98 from dgrove-oss/release-in-deinit release wrapped C objects when Swift object deinitialized Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 208dafe0f..81e4a2ba4 100644 --- a/PATCHES +++ b/PATCHES @@ -249,3 +249,4 @@ github commits starting with 29bdc2f from [195cbcf] APPLIED rdar://27303844 [5b893c8] APPLIED rdar://27303844 [92689ed] APPLIED rdar://27303844 +[ecc14fa] APPLIED rdar://27303844 From 2ab938a278c3452d0be44b4f5bff0dfc60bedaf5 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 13 Jul 2016 17:14:07 -0700 Subject: [PATCH 25/67] whitespace Signed-off-by: Daniel A. Steffen --- src/swift/Wrapper.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index ef7bf30d9..d38bb9358 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -316,4 +316,4 @@ internal enum _OSQoSClass : UInt32 { } @_silgen_name("_swift_dispatch_release") -internal func _swift_dispatch_release(_ obj: dispatch_object_t) -> Void +internal func _swift_dispatch_release(_ obj: dispatch_object_t) -> Void From d3bb7e5e6b562f4a4ef4a0691e9899b01568a62f Mon Sep 17 00:00:00 2001 From: David Grove Date: Wed, 6 Jul 2016 11:21:51 -0400 Subject: [PATCH 26/67] Linux: avoid zombie process when dispatch_main is called If the main thread calls pthread_exit on Linux, the process becomes a zombie. Modify dispatch_main to avoid this by adding a pthread_key destructor that calls dispatch_sig_thread (effectively stalling pthread exit until the program really exits). This patch relies on the TSD destructors being called in order of creation, which is currently the case in glibc. Signed-off-by: Daniel A. Steffen --- src/queue.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/queue.c b/src/queue.c index ef6a2c639..a7f4e4a10 100644 --- a/src/queue.c +++ b/src/queue.c @@ -48,6 +48,7 @@ #define pthread_workqueue_t void* #endif +static void _dispatch_sig_thread(void *ctxt); static void _dispatch_cache_cleanup(void *value); static void _dispatch_sync_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func, pthread_priority_t pp); @@ -5690,6 +5691,17 @@ dispatch_main(void) _dispatch_object_debug(&_dispatch_main_q, "%s", __func__); _dispatch_program_is_probably_callback_driven = true; _dispatch_ktrace0(ARIADNE_ENTER_DISPATCH_MAIN_CODE); +#ifdef __linux__ + // On Linux, if the main thread calls pthread_exit, the process becomes a zombie. + // To avoid that, just before calling pthread_exit we register a TSD destructor + // that will call _dispatch_sig_thread -- thus capturing the main thread in sigsuspend. + // This relies on an implementation detail (currently true in glibc) that TSD destructors + // will be called in the order of creation to cause all the TSD cleanup functions to + // run before the thread becomes trapped in sigsuspend. + pthread_key_t dispatch_main_key; + pthread_key_create(&dispatch_main_key, _dispatch_sig_thread); + pthread_setspecific(dispatch_main_key, &dispatch_main_key); +#endif pthread_exit(NULL); DISPATCH_INTERNAL_CRASH(errno, "pthread_exit() returned"); #if HAVE_PTHREAD_MAIN_NP @@ -5773,11 +5785,14 @@ _dispatch_queue_cleanup2(void) // overload the "probably" variable to mean that dispatch_main() or // similar non-POSIX API was called // this has to run before the DISPATCH_COCOA_COMPAT below + // See dispatch_main for call to _dispatch_sig_thread on linux. +#ifndef __linux__ if (_dispatch_program_is_probably_callback_driven) { _dispatch_barrier_async_detached_f(_dispatch_get_root_queue( _DISPATCH_QOS_CLASS_DEFAULT, true), NULL, _dispatch_sig_thread); sleep(1); // workaround 6778970 } +#endif #if DISPATCH_COCOA_COMPAT dispatch_once_f(&_dispatch_main_q_port_pred, dq, From fc3a731ee31004c9449a2bfc70e0e9e8a2b6903b Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 6 Jul 2016 10:50:05 -0700 Subject: [PATCH 27/67] Merge pull request #99 from dgrove-oss/dispatch-main-zombie Linux: avoid zombie process when dispatch_main is called Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 81e4a2ba4..ae83b7903 100644 --- a/PATCHES +++ b/PATCHES @@ -250,3 +250,4 @@ github commits starting with 29bdc2f from [5b893c8] APPLIED rdar://27303844 [92689ed] APPLIED rdar://27303844 [ecc14fa] APPLIED rdar://27303844 +[2dbf83c] APPLIED rdar://27303844 From f3c6254ac1899c13a028af2df21d08eaa808f063 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 12 Jul 2016 09:35:27 -0700 Subject: [PATCH 28/67] Update for SE-0112: ErrorProtocol has been renamed to Error Signed-off-by: Daniel A. Steffen --- src/swift/Queue.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 1710846f0..2a8c70189 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -246,10 +246,10 @@ public extension DispatchQueue { private func _syncHelper( fn: (@noescape () -> ()) -> (), execute work: @noescape () throws -> T, - rescue: ((ErrorProtocol) throws -> (T))) rethrows -> T + rescue: ((Swift.Error) throws -> (T))) rethrows -> T { var result: T? - var error: ErrorProtocol? + var error: Swift.Error? fn { do { result = try work() @@ -269,10 +269,10 @@ public extension DispatchQueue { fn: (DispatchWorkItem) -> (), flags: DispatchWorkItemFlags, execute work: @noescape () throws -> T, - rescue: ((ErrorProtocol) throws -> (T))) rethrows -> T + rescue: ((Swift.Error) throws -> (T))) rethrows -> T { var result: T? - var error: ErrorProtocol? + var error: Swift.Error? let workItem = DispatchWorkItem(flags: flags, noescapeBlock: { do { result = try work() From 3830f55a640057853c33a376bfc46bfbb1bfa8ac Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 12 Jul 2016 10:52:28 -0700 Subject: [PATCH 29/67] Merge pull request #103 from apple/nserror-bridging Update for SE-0112: ErrorProtocol has been renamed to Error Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index ae83b7903..249f7d7c0 100644 --- a/PATCHES +++ b/PATCHES @@ -251,3 +251,4 @@ github commits starting with 29bdc2f from [92689ed] APPLIED rdar://27303844 [ecc14fa] APPLIED rdar://27303844 [2dbf83c] APPLIED rdar://27303844 +[78b9e82] APPLIED rdar://27303844 From 3bbed1bce14d8bcbe0ac5f95f832a272bd99f7c8 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 13 Jul 2016 17:14:51 -0700 Subject: [PATCH 30/67] whitespace Signed-off-by: Daniel A. Steffen --- src/swift/Queue.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 2a8c70189..5a45fdcd1 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -246,7 +246,7 @@ public extension DispatchQueue { private func _syncHelper( fn: (@noescape () -> ()) -> (), execute work: @noescape () throws -> T, - rescue: ((Swift.Error) throws -> (T))) rethrows -> T + rescue: ((Swift.Error) throws -> (T))) rethrows -> T { var result: T? var error: Swift.Error? @@ -269,7 +269,7 @@ public extension DispatchQueue { fn: (DispatchWorkItem) -> (), flags: DispatchWorkItemFlags, execute work: @noescape () throws -> T, - rescue: ((Swift.Error) throws -> (T))) rethrows -> T + rescue: ((Swift.Error) throws -> (T))) rethrows -> T { var result: T? var error: Swift.Error? From 989c9dda53606c783b312664117789f679707120 Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 7 Jul 2016 17:24:17 -0400 Subject: [PATCH 31/67] Enable CF runloop support for linux Signed-off-by: Daniel A. Steffen --- private/private.h | 34 ++++++--- src/internal.h | 3 + src/queue.c | 161 ++++++++++++++++++++++++++++++++-------- src/shims/linux_stubs.c | 6 -- 4 files changed, 156 insertions(+), 48 deletions(-) diff --git a/private/private.h b/private/private.h index f4cd3a8f3..6f4b08b31 100644 --- a/private/private.h +++ b/private/private.h @@ -166,31 +166,43 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit); * SPI for CoreFoundation/Foundation ONLY */ -#define DISPATCH_COCOA_COMPAT (TARGET_OS_MAC || TARGET_OS_WIN32) +#if TARGET_OS_MAC +#define DISPATCH_COCOA_COMPAT 1 +#elif defined(__linux__) +#define DISPATCH_COCOA_COMPAT 1 +#else +#define DISPATCH_COCOA_COMPAT 0 +#endif #if DISPATCH_COCOA_COMPAT +#define DISPATCH_CF_SPI_VERSION 20160712 + +#if TARGET_OS_MAC +typedef mach_port_t dispatch_runloop_handle_t; +#elif defined(__linux__) +typedef int dispatch_runloop_handle_t; +#else +#error "runloop support not implemented on this platform" +#endif + #if TARGET_OS_MAC __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) DISPATCH_EXPORT DISPATCH_CONST DISPATCH_WARN_RESULT DISPATCH_NOTHROW -mach_port_t +dispatch_runloop_handle_t _dispatch_get_main_queue_port_4CF(void); +#endif -__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) -DISPATCH_EXPORT DISPATCH_NOTHROW -void -_dispatch_main_queue_callback_4CF(mach_msg_header_t *_Null_unspecified msg); -#elif TARGET_OS_WIN32 -__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) +__TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0) DISPATCH_EXPORT DISPATCH_NOTHROW -HANDLE +dispatch_runloop_handle_t _dispatch_get_main_queue_handle_4CF(void); __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) DISPATCH_EXPORT DISPATCH_NOTHROW void -_dispatch_main_queue_callback_4CF(void); -#endif // TARGET_OS_WIN32 +_dispatch_main_queue_callback_4CF(void *_Null_unspecified msg); __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0) DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT diff --git a/src/internal.h b/src/internal.h index a6261e11f..94828503f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -251,6 +251,9 @@ DISPATCH_EXPORT DISPATCH_NOTHROW void dispatch_atfork_child(void); #include #include #endif +#if defined(__linux__) +#include +#endif #ifdef __BLOCKS__ #include diff --git a/src/queue.c b/src/queue.c index a7f4e4a10..d89adc3db 100644 --- a/src/queue.c +++ b/src/queue.c @@ -74,11 +74,11 @@ static int _dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset); #endif #if DISPATCH_COCOA_COMPAT -static dispatch_once_t _dispatch_main_q_port_pred; +static dispatch_once_t _dispatch_main_q_handle_pred; static void _dispatch_runloop_queue_poke(dispatch_queue_t dq, pthread_priority_t pp, dispatch_wakeup_flags_t flags); -static void _dispatch_runloop_queue_port_init(void *ctxt); -static void _dispatch_runloop_queue_port_dispose(dispatch_queue_t dq); +static void _dispatch_runloop_queue_handle_init(void *ctxt); +static void _dispatch_runloop_queue_handle_dispose(dispatch_queue_t dq); #endif static void _dispatch_root_queues_init_once(void *context); @@ -4058,6 +4058,49 @@ _dispatch_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, } } +#if DISPATCH_COCOA_COMPAT +DISPATCH_ALWAYS_INLINE +static inline bool +_dispatch_runloop_handle_is_valid(dispatch_runloop_handle_t handle) +{ +#if TARGET_OS_MAC + return MACH_PORT_VALID(handle); +#elif defined(__linux__) + return handle >= 0; +#else +#error "runloop support not implemented on this platform" +#endif +} + +DISPATCH_ALWAYS_INLINE +static inline dispatch_runloop_handle_t +_dispatch_runloop_queue_get_handle(dispatch_queue_t dq) +{ +#if TARGET_OS_MAC + return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt); +#elif defined(__linux__) + // decode: 0 is a valid fd, so offset by 1 to distinguish from NULL + return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1; +#else +#error "runloop support not implemented on this platform" +#endif +} + +DISPATCH_ALWAYS_INLINE +static inline void +_dispatch_runloop_queue_set_handle(dispatch_queue_t dq, dispatch_runloop_handle_t handle) +{ +#if TARGET_OS_MAC + dq->do_ctxt = (void *)(uintptr_t)handle; +#elif defined(__linux__) + // encode: 0 is a valid fd, so offset by 1 to distinguish from NULL + dq->do_ctxt = (void *)(uintptr_t)(handle + 1); +#else +#error "runloop support not implemented on this platform" +#endif +} +#endif // DISPATCH_COCOA_COMPAT + void _dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, dispatch_wakeup_flags_t flags) @@ -4084,8 +4127,6 @@ _dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp, if (flags & DISPATCH_WAKEUP_CONSUME) { return _dispatch_release_tailcall(dq); } -#elif defined(__linux__) - LINUX_PORT_ERROR(); #else return _dispatch_queue_wakeup(dq, pp, flags); #endif @@ -4122,10 +4163,13 @@ _dispatch_root_queue_wakeup(dispatch_queue_t dq, static inline void _dispatch_runloop_queue_class_poke(dispatch_queue_t dq) { - mach_port_t mp = (mach_port_t)dq->do_ctxt; - if (!mp) { + dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle(dq); + if (!_dispatch_runloop_handle_is_valid(handle)) { return; } + +#if TARGET_OS_MAC + mach_port_t mp = handle; kern_return_t kr = _dispatch_send_wakeup_runloop_thread(mp, 0); switch (kr) { case MACH_SEND_TIMEOUT: @@ -4136,6 +4180,15 @@ _dispatch_runloop_queue_class_poke(dispatch_queue_t dq) (void)dispatch_assume_zero(kr); break; } +#elif defined(__linux__) + int result; + do { + result = eventfd_write(handle, 1); + } while (result == -1 && errno == EINTR); + (void)dispatch_assume_zero(result); +#else +#error "runloop support not implemented on this platform" +#endif } DISPATCH_NOINLINE @@ -4150,8 +4203,8 @@ _dispatch_runloop_queue_poke(dispatch_queue_t dq, // or in _dispatch_queue_cleanup2() for the main thread. if (dq == &_dispatch_main_q) { - dispatch_once_f(&_dispatch_main_q_port_pred, dq, - _dispatch_runloop_queue_port_init); + dispatch_once_f(&_dispatch_main_q_handle_pred, dq, + _dispatch_runloop_queue_handle_init); } _dispatch_queue_override_priority(dq, /* inout */ &pp, /* inout */ &flags); if (flags & DISPATCH_WAKEUP_OVERRIDING) { @@ -4493,8 +4546,8 @@ _dispatch_main_queue_drain(void) " from the wrong thread"); } - dispatch_once_f(&_dispatch_main_q_port_pred, dq, - _dispatch_runloop_queue_port_init); + dispatch_once_f(&_dispatch_main_q_handle_pred, dq, + _dispatch_runloop_queue_handle_init); _dispatch_perfmon_start(); // hide the frame chaining when CFRunLoop @@ -5544,7 +5597,7 @@ _dispatch_runloop_root_queue_create_4CF(const char *label, unsigned long flags) _dispatch_queue_init(dq, DQF_THREAD_BOUND | DQF_CANNOT_TRYSYNC, 1, false); dq->do_targetq = _dispatch_get_root_queue(_DISPATCH_QOS_CLASS_DEFAULT,true); dq->dq_label = label ? label : "runloop-queue"; // no-copy contract - _dispatch_runloop_queue_port_init(dq); + _dispatch_runloop_queue_handle_init(dq); _dispatch_queue_set_bound_thread(dq); _dispatch_object_debug(dq, "%s", __func__); return _dispatch_introspection_queue_create(dq); @@ -5566,7 +5619,7 @@ _dispatch_runloop_queue_dispose(dispatch_queue_t dq) { _dispatch_object_debug(dq, "%s", __func__); _dispatch_introspection_queue_dispose(dq); - _dispatch_runloop_queue_port_dispose(dq); + _dispatch_runloop_queue_handle_dispose(dq); _dispatch_queue_destroy(dq); } @@ -5591,23 +5644,26 @@ _dispatch_runloop_root_queue_wakeup_4CF(dispatch_queue_t dq) _dispatch_runloop_queue_wakeup(dq, 0, false); } -mach_port_t +dispatch_runloop_handle_t _dispatch_runloop_root_queue_get_port_4CF(dispatch_queue_t dq) { if (slowpath(dq->do_vtable != DISPATCH_VTABLE(queue_runloop))) { DISPATCH_CLIENT_CRASH(dq->do_vtable, "Not a runloop queue"); } - return (mach_port_t)dq->do_ctxt; + return _dispatch_runloop_queue_get_handle(dq); } static void -_dispatch_runloop_queue_port_init(void *ctxt) +_dispatch_runloop_queue_handle_init(void *ctxt) { dispatch_queue_t dq = (dispatch_queue_t)ctxt; - mach_port_t mp; - kern_return_t kr; + dispatch_runloop_handle_t handle; _dispatch_fork_becomes_unsafe(); + +#if TARGET_OS_MAC + mach_port_t mp; + kern_return_t kr; kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp); DISPATCH_VERIFY_MIG(kr); (void)dispatch_assume_zero(kr); @@ -5625,38 +5681,81 @@ _dispatch_runloop_queue_port_init(void *ctxt) DISPATCH_VERIFY_MIG(kr); (void)dispatch_assume_zero(kr); } - dq->do_ctxt = (void*)(uintptr_t)mp; + handle = mp; +#elif defined(__linux__) + int fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (fd == -1) { + int err = errno; + switch (err) { + case EMFILE: + DISPATCH_CLIENT_CRASH(err, "eventfd() failure: " + "process is out of file descriptors"); + break; + case ENFILE: + DISPATCH_CLIENT_CRASH(err, "eventfd() failure: " + "system is out of file descriptors"); + break; + case ENOMEM: + DISPATCH_CLIENT_CRASH(err, "eventfd() failure: " + "kernel is out of memory"); + break; + default: + DISPATCH_INTERNAL_CRASH(err, "eventfd() failure"); + break; + } + } + handle = fd; +#else +#error "runloop support not implemented on this platform" +#endif + _dispatch_runloop_queue_set_handle(dq, handle); _dispatch_program_is_probably_callback_driven = true; } static void -_dispatch_runloop_queue_port_dispose(dispatch_queue_t dq) +_dispatch_runloop_queue_handle_dispose(dispatch_queue_t dq) { - mach_port_t mp = (mach_port_t)dq->do_ctxt; - if (!mp) { + dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle(dq); + if (!_dispatch_runloop_handle_is_valid(handle)) { return; } dq->do_ctxt = NULL; +#if TARGET_OS_MAC + mach_port_t mp = handle; kern_return_t kr = mach_port_deallocate(mach_task_self(), mp); DISPATCH_VERIFY_MIG(kr); (void)dispatch_assume_zero(kr); kr = mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1); DISPATCH_VERIFY_MIG(kr); (void)dispatch_assume_zero(kr); +#elif defined(__linux__) + int rc = close(handle); + (void)dispatch_assume_zero(rc); +#else +#error "runloop support not implemented on this platform" +#endif } #pragma mark - #pragma mark dispatch_main_queue -mach_port_t -_dispatch_get_main_queue_port_4CF(void) +dispatch_runloop_handle_t +_dispatch_get_main_queue_handle_4CF(void) { dispatch_queue_t dq = &_dispatch_main_q; - dispatch_once_f(&_dispatch_main_q_port_pred, dq, - _dispatch_runloop_queue_port_init); - return (mach_port_t)dq->do_ctxt; + dispatch_once_f(&_dispatch_main_q_handle_pred, dq, + _dispatch_runloop_queue_handle_init); + return _dispatch_runloop_queue_get_handle(dq); +} + +#if TARGET_OS_MAC +dispatch_runloop_handle_t +_dispatch_get_main_queue_port_4CF(void) +{ + return _dispatch_get_main_queue_handle_4CF(); } +#endif static bool main_q_is_draining; @@ -5670,7 +5769,7 @@ _dispatch_queue_set_mainq_drain_state(bool arg) } void -_dispatch_main_queue_callback_4CF(mach_msg_header_t *msg DISPATCH_UNUSED) +_dispatch_main_queue_callback_4CF(void *ignored DISPATCH_UNUSED) { if (main_q_is_draining) { return; @@ -5795,9 +5894,9 @@ _dispatch_queue_cleanup2(void) #endif #if DISPATCH_COCOA_COMPAT - dispatch_once_f(&_dispatch_main_q_port_pred, dq, - _dispatch_runloop_queue_port_init); - _dispatch_runloop_queue_port_dispose(dq); + dispatch_once_f(&_dispatch_main_q_handle_pred, dq, + _dispatch_runloop_queue_handle_init); + _dispatch_runloop_queue_handle_dispose(dq); #endif } diff --git a/src/shims/linux_stubs.c b/src/shims/linux_stubs.c index d5618d572..07ee8bc06 100644 --- a/src/shims/linux_stubs.c +++ b/src/shims/linux_stubs.c @@ -33,12 +33,6 @@ #undef LINUX_PORT_ERROR #define LINUX_PORT_ERROR() do { printf("LINUX_PORT_ERROR_CALLED %s:%d: %s\n",__FILE__,__LINE__,__FUNCTION__); abort(); } while (0) -unsigned long _dispatch_runloop_queue_probe(dispatch_queue_t dq) { - LINUX_PORT_ERROR(); -} -void _dispatch_runloop_queue_xref_dispose() { LINUX_PORT_ERROR(); } - -void _dispatch_runloop_queue_dispose() { LINUX_PORT_ERROR(); } /* * Stubbed out static data From 56eb6b55f07a8ca8c4e2aa94ef9d944372f3c696 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Tue, 12 Jul 2016 11:21:17 -0700 Subject: [PATCH 32/67] Merge pull request #101 from dgrove-oss/cf-runloop-hooks Enable CF runloop support for linux Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 249f7d7c0..28f7c5248 100644 --- a/PATCHES +++ b/PATCHES @@ -252,3 +252,4 @@ github commits starting with 29bdc2f from [ecc14fa] APPLIED rdar://27303844 [2dbf83c] APPLIED rdar://27303844 [78b9e82] APPLIED rdar://27303844 +[2c0e5ee] APPLIED rdar://27303844 From 627df61b5fea85993aebb57df310407335fc5704 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 13 Jul 2016 17:44:07 -0700 Subject: [PATCH 33/67] workaround CF build failure, add resolvers for new symbol, whitespace Signed-off-by: Daniel A. Steffen --- private/private.h | 7 +++++++ src/queue.c | 10 ++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/private/private.h b/private/private.h index 6f4b08b31..5a75335cb 100644 --- a/private/private.h +++ b/private/private.h @@ -199,10 +199,17 @@ DISPATCH_EXPORT DISPATCH_NOTHROW dispatch_runloop_handle_t _dispatch_get_main_queue_handle_4CF(void); +#if TARGET_OS_MAC +__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) +DISPATCH_EXPORT DISPATCH_NOTHROW +void +_dispatch_main_queue_callback_4CF(mach_msg_header_t *_Null_unspecified msg); +#else __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0) DISPATCH_EXPORT DISPATCH_NOTHROW void _dispatch_main_queue_callback_4CF(void *_Null_unspecified msg); +#endif __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0) DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT diff --git a/src/queue.c b/src/queue.c index d89adc3db..2602994dc 100644 --- a/src/queue.c +++ b/src/queue.c @@ -5707,7 +5707,7 @@ _dispatch_runloop_queue_handle_init(void *ctxt) handle = fd; #else #error "runloop support not implemented on this platform" -#endif +#endif _dispatch_runloop_queue_set_handle(dq, handle); _dispatch_program_is_probably_callback_driven = true; @@ -5769,7 +5769,13 @@ _dispatch_queue_set_mainq_drain_state(bool arg) } void -_dispatch_main_queue_callback_4CF(void *ignored DISPATCH_UNUSED) +_dispatch_main_queue_callback_4CF( +#if TARGET_OS_MAC + mach_msg_header_t *_Null_unspecified msg +#else + void *ignored +#endif + DISPATCH_UNUSED) { if (main_q_is_draining) { return; From eff2273b4e6416ac3432390c6a07d4a73a3fe318 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 14 Jul 2016 23:50:29 -0700 Subject: [PATCH 34/67] Revert modulemaps changes from PR #94 The Linux and Darwin module maps need to be kept separate as they have different linkage requirements. Signed-off-by: Daniel A. Steffen --- dispatch/Makefile.am | 2 +- dispatch/module.map | 20 ++++++++++++++++++++ dispatch/module.modulemap | 16 +++------------- src/Makefile.am | 2 +- 4 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 dispatch/module.map diff --git a/dispatch/Makefile.am b/dispatch/Makefile.am index 89fd3daf0..53ea5986c 100644 --- a/dispatch/Makefile.am +++ b/dispatch/Makefile.am @@ -24,5 +24,5 @@ dispatch_HEADERS= \ time.h if HAVE_SWIFT -dispatch_HEADERS+=module.modulemap +dispatch_HEADERS+=module.map endif diff --git a/dispatch/module.map b/dispatch/module.map new file mode 100644 index 000000000..6f3c8aab8 --- /dev/null +++ b/dispatch/module.map @@ -0,0 +1,20 @@ +module Dispatch { + requires blocks + export * + link "dispatch" + link "BlocksRuntime" +} + +module DispatchIntrospection [system] [extern_c] { + header "introspection.h" + export * +} + +module CDispatch [system] [extern_c] { + umbrella header "dispatch.h" + module * { export * } + export * + requires blocks + link "dispatch" + link "BlocksRuntime" +} diff --git a/dispatch/module.modulemap b/dispatch/module.modulemap index 6f3c8aab8..addaae436 100644 --- a/dispatch/module.modulemap +++ b/dispatch/module.modulemap @@ -1,20 +1,10 @@ -module Dispatch { - requires blocks +module Dispatch [system] [extern_c] { + umbrella header "dispatch.h" + module * { export * } export * - link "dispatch" - link "BlocksRuntime" } module DispatchIntrospection [system] [extern_c] { header "introspection.h" export * } - -module CDispatch [system] [extern_c] { - umbrella header "dispatch.h" - module * { export * } - export * - requires blocks - link "dispatch" - link "BlocksRuntime" -} diff --git a/src/Makefile.am b/src/Makefile.am index f06a49347..c417aec97 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -149,7 +149,7 @@ SWIFT_GEN_FILES= \ $(SWIFT_OBJ_FILES:%=%.~partial.swiftdoc) \ $(SWIFT_OBJ_FILES:%=%.~partial.swiftdeps) -SWIFTC_FLAGS = -Xcc -fmodule-map-file=$(abs_top_srcdir)/dispatch/module.modulemap -I$(abs_top_srcdir) -Xcc -fblocks +SWIFTC_FLAGS = -Xcc -fmodule-map-file=$(abs_top_srcdir)/dispatch/module.map -I$(abs_top_srcdir) -Xcc -fblocks $(abs_builddir)/swift/%.o: $(abs_srcdir)/swift/%.swift $(SWIFTC) -frontend -c $(SWIFT_ABS_SRC_FILES) -primary-file $< \ From f3bfb6fe432d2f2924f87b011248fc44eb5cc982 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 28 Jul 2016 16:55:20 -0700 Subject: [PATCH 35/67] Merge libdispatch-703.1.4 Signed-off-by: Daniel A. Steffen --- dispatch/dispatch.h | 2 +- dispatch/group.h | 5 +- man/dispatch_source_create.3 | 11 +- os/firehose_buffer_private.h | 2 +- private/private.h | 2 +- private/queue_private.h | 17 ++ src/apply.c | 11 ++ src/firehose/firehose_buffer.c | 8 +- src/firehose/firehose_server.c | 45 +++-- src/inline_internal.h | 97 +++++------ src/internal.h | 12 +- src/io.c | 177 ++++++++++++------- src/once.c | 2 +- src/queue.c | 302 +++++++++++++++++++-------------- src/shims/lock.h | 18 +- src/source.c | 21 ++- 16 files changed, 444 insertions(+), 288 deletions(-) diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index 5fa04565b..a26b95107 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -53,7 +53,7 @@ #endif #endif -#define DISPATCH_API_VERSION 20160612 +#define DISPATCH_API_VERSION 20160712 #ifndef __DISPATCH_BUILDING_DISPATCH__ diff --git a/dispatch/group.h b/dispatch/group.h index 5756a401d..c50ad89d1 100644 --- a/dispatch/group.h +++ b/dispatch/group.h @@ -134,8 +134,7 @@ dispatch_group_async_f(dispatch_group_t group, * @discussion * This function waits for the completion of the blocks associated with the * given dispatch group, and returns after all blocks have completed or when - * the specified timeout has elapsed. When a timeout occurs, the group is - * restored to its original state. + * the specified timeout has elapsed. * * This function will return immediately if there are no blocks associated * with the dispatch group (i.e. the group is empty). @@ -262,7 +261,7 @@ dispatch_group_enter(dispatch_group_t group); * * @discussion * Calling this function indicates block has completed and left the dispatch - * groupJ by a means other than dispatch_group_async(). + * group by a means other than dispatch_group_async(). * * @param group * The dispatch group to update. diff --git a/man/dispatch_source_create.3 b/man/dispatch_source_create.3 index 1c1951b77..4da708cfb 100644 --- a/man/dispatch_source_create.3 +++ b/man/dispatch_source_create.3 @@ -271,8 +271,8 @@ Sources of this type allow applications to manually trigger the source's event handler via a call to .Fn dispatch_source_merge_data . The data will be merged with the source's pending data via an atomic add or -logic OR (based on the source's type), and the event handler block will be -submitted to the source's target queue. The +atomic bitwise OR (based on the source's type), and the event handler block will +be submitted to the source's target queue. The .Fa data is application defined. These sources have no .Fa handle @@ -297,7 +297,8 @@ The data returned by .Fn dispatch_source_get_data indicates which of the events in the .Fa mask -were observed. Note that because this source type will request notifications on the provided port, it should not be mixed with the use of +were observed. Note that because this source type will request notifications on +the provided port, it should not be mixed with the use of .Fn mach_port_request_notification on the same port. .Pp @@ -314,8 +315,8 @@ on the mach port is waiting to be received. .Pp .Vt DISPATCH_SOURCE_TYPE_MEMORYPRESSURE .Pp -Sources of this type monitor the system memory pressure condition for state changes. -The +Sources of this type monitor the system memory pressure condition for state +changes. The .Fa handle is unused and should be zero. The .Fa mask diff --git a/os/firehose_buffer_private.h b/os/firehose_buffer_private.h index 0c8516421..2c6466f94 100644 --- a/os/firehose_buffer_private.h +++ b/os/firehose_buffer_private.h @@ -69,7 +69,7 @@ typedef struct firehose_buffer_chunk_s { uint8_t fbc_data[FIREHOSE_BUFFER_CHUNK_SIZE - sizeof(firehose_buffer_pos_u) - sizeof(uint64_t)]; -} *firehose_buffer_chunk_t; +} __attribute__((aligned(8))) *firehose_buffer_chunk_t; typedef struct firehose_buffer_range_s { uint16_t fbr_offset; // offset from the start of the buffer diff --git a/private/private.h b/private/private.h index 5a75335cb..3c37bed0d 100644 --- a/private/private.h +++ b/private/private.h @@ -66,7 +66,7 @@ #endif /* !__DISPATCH_BUILDING_DISPATCH__ */ // Check that public and private dispatch headers match -#if DISPATCH_API_VERSION != 20160612 // Keep in sync with +#if DISPATCH_API_VERSION != 20160712 // Keep in sync with #error "Dispatch header mismatch between /usr/include and /usr/local/include" #endif diff --git a/private/queue_private.h b/private/queue_private.h index 0acaceb91..33de371c8 100644 --- a/private/queue_private.h +++ b/private/queue_private.h @@ -227,6 +227,23 @@ dispatch_pthread_root_queue_flags_pool_size(uint8_t pool_size) #endif /* __BLOCKS__ */ +/*! + * @function dispatch_pthread_root_queue_copy_current + * + * @abstract + * Returns a reference to the pthread root queue object that has created the + * currently executing thread, or NULL if the current thread is not associated + * to a pthread root queue. + * + * @result + * A new reference to a pthread root queue object or NULL. + */ +__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) +__TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0) +DISPATCH_EXPORT DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT DISPATCH_NOTHROW +dispatch_queue_t _Nullable +dispatch_pthread_root_queue_copy_current(void); + /*! * @constant DISPATCH_APPLY_CURRENT_ROOT_QUEUE * @discussion Constant to pass to the dispatch_apply() and dispatch_apply_f() diff --git a/src/apply.c b/src/apply.c index 57021e534..e051a1630 100644 --- a/src/apply.c +++ b/src/apply.c @@ -87,6 +87,9 @@ _dispatch_apply_invoke2(void *ctxt, long invoke_flags) _dispatch_thread_event_destroy(&da->da_event); } if (os_atomic_dec2o(da, da_thr_cnt, release) == 0) { +#if DISPATCH_INTROSPECTION + _dispatch_continuation_free(da->da_dc); +#endif _dispatch_continuation_free((dispatch_continuation_t)da); } } @@ -145,6 +148,9 @@ _dispatch_apply_serial(void *ctxt) }); } while (++idx < iter); +#if DISPATCH_INTROSPECTION + _dispatch_continuation_free(da->da_dc); +#endif _dispatch_continuation_free((dispatch_continuation_t)da); } @@ -262,7 +268,12 @@ dispatch_apply_f(size_t iterations, dispatch_queue_t dq, void *ctxt, da->da_iterations = iterations; da->da_nested = nested; da->da_thr_cnt = thr_cnt; +#if DISPATCH_INTROSPECTION + da->da_dc = _dispatch_continuation_alloc(); + *da->da_dc = dc; +#else da->da_dc = &dc; +#endif da->da_flags = 0; if (slowpath(dq->dq_width == 1) || slowpath(thr_cnt <= 1)) { diff --git a/src/firehose/firehose_buffer.c b/src/firehose/firehose_buffer.c index 5cdd9a71d..1305bdea6 100644 --- a/src/firehose/firehose_buffer.c +++ b/src/firehose/firehose_buffer.c @@ -305,10 +305,10 @@ firehose_buffer_create(mach_port_t logd_port, uint64_t unique_pid, "Invalid values for MADVISE_CHUNK_COUNT / CHUNK_SIZE"); } - kr = mach_vm_map(mach_task_self(), &vm_addr, sizeof(*fb), - 0, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_GENEALOGY), - MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_ALL, - VM_INHERIT_NONE); + kr = mach_vm_map(mach_task_self(), &vm_addr, sizeof(*fb), 0, + VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE | + VM_MAKE_TAG(VM_MEMORY_GENEALOGY), MEMORY_OBJECT_NULL, 0, FALSE, + VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_NONE); if (slowpath(kr)) { if (kr != KERN_NO_SPACE) dispatch_assume_zero(kr); firehose_mach_port_send_release(logd_port); diff --git a/src/firehose/firehose_server.c b/src/firehose/firehose_server.c index 1af06e0d8..a6be2fab7 100644 --- a/src/firehose/firehose_server.c +++ b/src/firehose/firehose_server.c @@ -149,10 +149,12 @@ firehose_client_snapshot_mark_done(firehose_client_t fc, } #define DRAIN_BATCH_SIZE 4 +#define FIREHOSE_DRAIN_FOR_IO 0x1 +#define FIREHOSE_DRAIN_POLL 0x2 OS_NOINLINE static void -firehose_client_drain(firehose_client_t fc, mach_port_t port, bool for_io) +firehose_client_drain(firehose_client_t fc, mach_port_t port, uint32_t flags) { firehose_buffer_t fb = fc->fc_buffer; firehose_buffer_chunk_t fbc; @@ -161,6 +163,7 @@ firehose_client_drain(firehose_client_t fc, mach_port_t port, bool for_io) uint16_t flushed, ref, count = 0; uint16_t client_head, client_flushed, sent_flushed; firehose_snapshot_t snapshot = NULL; + bool for_io = (flags & FIREHOSE_DRAIN_FOR_IO); if (for_io) { evt = FIREHOSE_EVENT_IO_BUFFER_RECEIVED; @@ -201,9 +204,9 @@ firehose_client_drain(firehose_client_t fc, mach_port_t port, bool for_io) } } - ref = (flushed + count) & FIREHOSE_RING_POS_IDX_MASK; // see firehose_buffer_ring_enqueue do { + ref = (flushed + count) & FIREHOSE_RING_POS_IDX_MASK; ref = os_atomic_load(&fbh_ring[ref], relaxed); ref &= FIREHOSE_RING_POS_IDX_MASK; } while (fc->fc_is_kernel && !ref); @@ -251,13 +254,24 @@ firehose_client_drain(firehose_client_t fc, mach_port_t port, bool for_io) firehose_client_notify(fc, port); } if (fc->fc_is_kernel) { - // see firehose_client_kernel_source_handle_event - dispatch_resume(fc->fc_kernel_source); - } else if (fc->fc_use_notifs && count >= DRAIN_BATCH_SIZE) { - // if we hit the drain batch size, the client probably logs a lot - // and there's more to drain, so optimistically schedule draining again - // this is cheap since the queue is hot, and is fair for other clients - firehose_client_push_async_merge(fc, 0, for_io); + if (!(flags & FIREHOSE_DRAIN_POLL)) { + // see firehose_client_kernel_source_handle_event + dispatch_resume(fc->fc_kernel_source); + } + } else { + if (fc->fc_use_notifs && count >= DRAIN_BATCH_SIZE) { + // if we hit the drain batch size, the client probably logs a lot + // and there's more to drain, so optimistically schedule draining + // again this is cheap since the queue is hot, and is fair for other + // clients + firehose_client_push_async_merge(fc, 0, for_io); + } + if (count && server_config.fs_kernel_client) { + // the kernel is special because it can drop messages, so if we're + // draining, poll the kernel each time while we're bound to a thread + firehose_client_drain(server_config.fs_kernel_client, + MACH_PORT_NULL, flags | FIREHOSE_DRAIN_POLL); + } } return; @@ -277,13 +291,13 @@ firehose_client_drain(firehose_client_t fc, mach_port_t port, bool for_io) static void firehose_client_drain_io_async(void *ctx) { - firehose_client_drain(ctx, MACH_PORT_NULL, true); + firehose_client_drain(ctx, MACH_PORT_NULL, FIREHOSE_DRAIN_FOR_IO); } static void firehose_client_drain_mem_async(void *ctx) { - firehose_client_drain(ctx, MACH_PORT_NULL, false); + firehose_client_drain(ctx, MACH_PORT_NULL, 0); } OS_NOINLINE @@ -751,8 +765,6 @@ firehose_server_resume(void) { struct firehose_server_s *fs = &server_config; - dispatch_mach_connect(fs->fs_mach_channel, fs->fs_bootstrap_port, - MACH_PORT_NULL, NULL); if (fs->fs_kernel_client) { dispatch_async(fs->fs_io_drain_queue, ^{ struct firehose_client_connected_info_s fcci = { @@ -761,6 +773,8 @@ firehose_server_resume(void) firehose_client_resume(fs->fs_kernel_client, &fcci); }); } + dispatch_mach_connect(fs->fs_mach_channel, fs->fs_bootstrap_port, + MACH_PORT_NULL, NULL); } #pragma mark - @@ -1035,7 +1049,7 @@ firehose_server_register(mach_port_t server_port OS_UNUSED, if (extra_info_port && extra_info_size) { mach_vm_address_t addr = 0; kr = mach_vm_map(mach_task_self(), &addr, extra_info_size, 0, - VM_FLAGS_ANYWHERE, mem_port, 0, FALSE, + VM_FLAGS_ANYWHERE, extra_info_port, 0, FALSE, VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE); if (dispatch_assume_zero(kr)) { mach_vm_deallocate(mach_task_self(), base_addr, mem_size); @@ -1104,7 +1118,8 @@ firehose_server_push(mach_port_t server_port OS_UNUSED, } block = dispatch_block_create_with_qos_class(flags, qos, 0, ^{ - firehose_client_drain(fc, reply_port, for_io); + firehose_client_drain(fc, reply_port, + for_io ? FIREHOSE_DRAIN_FOR_IO : 0); }); dispatch_async(q, block); _Block_release(block); diff --git a/src/inline_internal.h b/src/inline_internal.h index 5d941a297..d1c73dd4e 100644 --- a/src/inline_internal.h +++ b/src/inline_internal.h @@ -861,8 +861,6 @@ static inline pthread_priority_t _dispatch_get_defaultpriority(void); static inline void _dispatch_set_defaultpriority_override(void); static inline void _dispatch_reset_defaultpriority(pthread_priority_t pp); static inline pthread_priority_t _dispatch_get_priority(void); -static inline void _dispatch_set_priority(pthread_priority_t pp, - _dispatch_thread_set_self_t flags); static inline pthread_priority_t _dispatch_set_defaultpriority( pthread_priority_t pp, pthread_priority_t *new_pp); @@ -1553,36 +1551,38 @@ _dispatch_queue_push_inline(dispatch_queue_t dq, dispatch_object_t _tail, } struct _dispatch_identity_s { - pthread_priority_t old_pri; pthread_priority_t old_pp; }; DISPATCH_ALWAYS_INLINE static inline void _dispatch_root_queue_identity_assume(struct _dispatch_identity_s *di, - pthread_priority_t pp, _dispatch_thread_set_self_t flags) + pthread_priority_t pp) { // assumed_rq was set by the caller, we need to fake the priorities dispatch_queue_t assumed_rq = _dispatch_queue_get_current(); dispatch_assert(dx_type(assumed_rq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE); - di->old_pri = _dispatch_get_priority(); - // _dispatch_root_queue_drain_deferred_item() may turn a manager thread - // into a regular root queue, and we must never try to restore the manager - // flag once we became a regular work queue thread. - di->old_pri &= ~(pthread_priority_t)_PTHREAD_PRIORITY_EVENT_MANAGER_FLAG; di->old_pp = _dispatch_get_defaultpriority(); - if (!pp) pp = di->old_pri; - if ((pp & _PTHREAD_PRIORITY_QOS_CLASS_MASK) > - (assumed_rq->dq_priority & _PTHREAD_PRIORITY_QOS_CLASS_MASK)) { - _dispatch_wqthread_override_start(_dispatch_tid_self(), pp); - // Ensure that the root queue sees that this thread was overridden. - _dispatch_set_defaultpriority_override(); + if (!(assumed_rq->dq_priority & _PTHREAD_PRIORITY_DEFAULTQUEUE_FLAG)) { + if (!pp) { + pp = _dispatch_get_priority(); + // _dispatch_root_queue_drain_deferred_item() may turn a manager + // thread into a regular root queue, and we must never try to + // restore the manager flag once we became a regular work queue + // thread. + pp &= ~(pthread_priority_t)_PTHREAD_PRIORITY_EVENT_MANAGER_FLAG; + } + if ((pp & _PTHREAD_PRIORITY_QOS_CLASS_MASK) > + (assumed_rq->dq_priority & _PTHREAD_PRIORITY_QOS_CLASS_MASK)) { + _dispatch_wqthread_override_start(_dispatch_tid_self(), pp); + // Ensure that the root queue sees that this thread was overridden. + _dispatch_set_defaultpriority_override(); + } } _dispatch_reset_defaultpriority(assumed_rq->dq_priority); - _dispatch_set_priority(assumed_rq->dq_priority, flags); } DISPATCH_ALWAYS_INLINE @@ -1590,7 +1590,6 @@ static inline void _dispatch_root_queue_identity_restore(struct _dispatch_identity_s *di) { _dispatch_reset_defaultpriority(di->old_pp); - _dispatch_set_priority(di->old_pri, 0); } typedef dispatch_queue_t @@ -1631,7 +1630,7 @@ _dispatch_queue_class_invoke(dispatch_object_t dou, if (overriding) { _dispatch_object_debug(dq, "stolen onto thread 0x%x, 0x%lx", _dispatch_tid_self(), _dispatch_get_defaultpriority()); - _dispatch_root_queue_identity_assume(&di, 0, 0); + _dispatch_root_queue_identity_assume(&di, 0); } if (!(flags & DISPATCH_INVOKE_MANAGER_DRAIN)) { @@ -1819,6 +1818,23 @@ _dispatch_get_root_queue_for_priority(pthread_priority_t pp, bool overcommit) } #endif +DISPATCH_ALWAYS_INLINE DISPATCH_CONST +static inline dispatch_queue_t +_dispatch_get_root_queue_with_overcommit(dispatch_queue_t rq, bool overcommit) +{ + bool rq_overcommit = (rq->dq_priority & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG); + // root queues in _dispatch_root_queues are not overcommit for even indices + // and overcommit for odd ones, so fixing overcommit is either returning + // the same queue, or picking its neighbour in _dispatch_root_queues + if (overcommit && !rq_overcommit) { + return rq + 1; + } + if (!overcommit && rq_overcommit) { + return rq - 1; + } + return rq; +} + DISPATCH_ALWAYS_INLINE static inline void _dispatch_queue_set_bound_thread(dispatch_queue_t dq) @@ -1927,10 +1943,16 @@ _dispatch_queue_priority_inherit_from_target(dispatch_queue_t dq, #if HAVE_PTHREAD_WORKQUEUE_QOS const dispatch_priority_t rootqueue_flag = _PTHREAD_PRIORITY_ROOTQUEUE_FLAG; const dispatch_priority_t inherited_flag = _PTHREAD_PRIORITY_INHERIT_FLAG; + const dispatch_priority_t defaultqueue_flag = + _PTHREAD_PRIORITY_DEFAULTQUEUE_FLAG; dispatch_priority_t dqp = dq->dq_priority, tqp = tq->dq_priority; if ((!(dqp & ~_PTHREAD_PRIORITY_FLAGS_MASK) || (dqp & inherited_flag)) && (tqp & rootqueue_flag)) { - dq->dq_priority = (tqp & ~rootqueue_flag) | inherited_flag; + if (tqp & defaultqueue_flag) { + dq->dq_priority = 0; + } else { + dq->dq_priority = (tqp & ~rootqueue_flag) | inherited_flag; + } } #else (void)dq; (void)tq; @@ -2007,10 +2029,11 @@ _dispatch_priority_inherit_from_root_queue(pthread_priority_t pp, #if HAVE_PTHREAD_WORKQUEUE_QOS pthread_priority_t p = pp & ~_PTHREAD_PRIORITY_FLAGS_MASK; pthread_priority_t rqp = rq->dq_priority & ~_PTHREAD_PRIORITY_FLAGS_MASK; - bool defaultqueue = rq->dq_priority & _PTHREAD_PRIORITY_DEFAULTQUEUE_FLAG; + pthread_priority_t defaultqueue = + rq->dq_priority & _PTHREAD_PRIORITY_DEFAULTQUEUE_FLAG; if (!p || (!defaultqueue && p < rqp)) { - p = rqp; + p = rqp | defaultqueue; } return p | (rq->dq_priority & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG); #else @@ -2032,12 +2055,11 @@ _dispatch_get_priority(void) #endif } +#if HAVE_PTHREAD_WORKQUEUE_QOS DISPATCH_ALWAYS_INLINE static inline pthread_priority_t -_dispatch_priority_compute_update(pthread_priority_t pp, - _dispatch_thread_set_self_t flags) +_dispatch_priority_compute_update(pthread_priority_t pp) { -#if HAVE_PTHREAD_WORKQUEUE_QOS dispatch_assert(pp != DISPATCH_NO_PRIORITY); if (!_dispatch_set_qos_class_enabled) return 0; // the priority in _dispatch_get_priority() only tracks manager-ness @@ -2051,11 +2073,7 @@ _dispatch_priority_compute_update(pthread_priority_t pp, pthread_priority_t cur_priority = _dispatch_get_priority(); pthread_priority_t unbind = _PTHREAD_PRIORITY_NEEDS_UNBIND_FLAG; pthread_priority_t overcommit = _PTHREAD_PRIORITY_OVERCOMMIT_FLAG; - if (flags & DISPATCH_IGNORE_UNBIND) { - // if DISPATCH_IGNORE_UNBIND is passed, we want to ignore the - // difference if it is limited to the NEEDS_UNBIND flag - cur_priority &= ~(unbind | overcommit); - } else if (unlikely(cur_priority & unbind)) { + if (unlikely(cur_priority & unbind)) { // else we always need an update if the NEEDS_UNBIND flag is set // the slowpath in _dispatch_set_priority_and_voucher_slow() will // adjust the priority further with the proper overcommitness @@ -2064,11 +2082,9 @@ _dispatch_priority_compute_update(pthread_priority_t pp, cur_priority &= ~overcommit; } if (unlikely(pp != cur_priority)) return pp; -#else - (void)pp; (void)flags; -#endif return 0; } +#endif DISPATCH_ALWAYS_INLINE DISPATCH_WARN_RESULT static inline voucher_t @@ -2076,7 +2092,7 @@ _dispatch_set_priority_and_voucher(pthread_priority_t pp, voucher_t v, _dispatch_thread_set_self_t flags) { #if HAVE_PTHREAD_WORKQUEUE_QOS - pp = _dispatch_priority_compute_update(pp, flags); + pp = _dispatch_priority_compute_update(pp); if (likely(!pp)) { if (v == DISPATCH_NO_VOUCHER) { return DISPATCH_NO_VOUCHER; @@ -2128,21 +2144,6 @@ _dispatch_reset_voucher(voucher_t v, _dispatch_thread_set_self_t flags) (void)_dispatch_set_priority_and_voucher(0, v, flags); } -DISPATCH_ALWAYS_INLINE -static inline void -_dispatch_set_priority(pthread_priority_t pp, - _dispatch_thread_set_self_t flags) -{ - dispatch_assert(pp != DISPATCH_NO_PRIORITY); - pp = _dispatch_priority_compute_update(pp, flags); - if (likely(!pp)) { - return; - } -#if HAVE_PTHREAD_WORKQUEUE_QOS - _dispatch_set_priority_and_mach_voucher_slow(pp, VOUCHER_NO_MACH_VOUCHER); -#endif -} - DISPATCH_ALWAYS_INLINE static inline bool _dispatch_queue_need_override(dispatch_queue_class_t dqu, pthread_priority_t pp) diff --git a/src/internal.h b/src/internal.h index 94828503f..a9aee1123 100644 --- a/src/internal.h +++ b/src/internal.h @@ -408,8 +408,9 @@ DISPATCH_EXPORT DISPATCH_NOINLINE __attribute__((__format__(__printf__,1,2))) void _dispatch_log(const char *msg, ...); #endif // DISPATCH_USE_OS_DEBUG_LOG -#define dsnprintf(...) \ - ({ int _r = snprintf(__VA_ARGS__); _r < 0 ? 0u : (size_t)_r; }) +#define dsnprintf(buf, siz, ...) \ + ({ size_t _siz = siz; int _r = snprintf(buf, _siz, __VA_ARGS__); \ + _r < 0 ? 0u : ((size_t)_r > _siz ? _siz : (size_t)_r); }) #if __GNUC__ #define dispatch_static_assert(e) ({ \ @@ -864,12 +865,16 @@ typedef struct kevent64_s _dispatch_kevent_qos_s; #define DISPATCH_TRACE_SUBCLASS_DEFAULT 0 #define DISPATCH_TRACE_SUBCLASS_VOUCHER 1 #define DISPATCH_TRACE_SUBCLASS_PERF 2 +#define DISPATCH_TRACE_SUBCLASS_MACH_MSG 3 + #define DISPATCH_PERF_non_leaf_retarget DISPATCH_CODE(PERF, 1) #define DISPATCH_PERF_post_activate_retarget DISPATCH_CODE(PERF, 2) #define DISPATCH_PERF_post_activate_mutation DISPATCH_CODE(PERF, 3) #define DISPATCH_PERF_delayed_registration DISPATCH_CODE(PERF, 4) #define DISPATCH_PERF_mutable_target DISPATCH_CODE(PERF, 5) +#define DISPATCH_MACH_MSG_hdr_move DISPATCH_CODE(MACH_MSG, 1) + DISPATCH_ALWAYS_INLINE static inline void _dispatch_ktrace_impl(uint32_t code, uint64_t a, uint64_t b, @@ -1034,8 +1039,7 @@ DISPATCH_ENUM(_dispatch_thread_set_self, unsigned long, DISPATCH_PRIORITY_ENFORCE = 0x1, DISPATCH_VOUCHER_REPLACE = 0x2, DISPATCH_VOUCHER_CONSUME = 0x4, - DISPATCH_IGNORE_UNBIND = 0x8, - DISPATCH_THREAD_PARK = 0x10, + DISPATCH_THREAD_PARK = 0x8, ); DISPATCH_WARN_RESULT static inline voucher_t _dispatch_adopt_priority_and_set_voucher( diff --git a/src/io.c b/src/io.c index e2a123217..e4f05aec9 100644 --- a/src/io.c +++ b/src/io.c @@ -24,13 +24,6 @@ #define DISPATCH_IO_DEBUG DISPATCH_DEBUG #endif -#if DISPATCH_IO_DEBUG -#define _dispatch_fd_debug(msg, fd, args...) \ - _dispatch_debug("fd[0x%x]: " msg, (fd), ##args) -#else -#define _dispatch_fd_debug(msg, fd, args...) -#endif - #if DISPATCH_DATA_IS_BRIDGED_TO_NSDATA #define _dispatch_io_data_retain(x) _dispatch_objc_retain(x) #define _dispatch_io_data_release(x) _dispatch_objc_release(x) @@ -75,7 +68,7 @@ static void _dispatch_disk_enqueue_operation(dispatch_disk_t dsk, dispatch_operation_t operation, dispatch_data_t data); static void _dispatch_stream_cleanup_operations(dispatch_stream_t stream, dispatch_io_t channel); -static void _dispatch_disk_cleanup_operations(dispatch_disk_t disk, +static void _dispatch_disk_cleanup_inactive_operations(dispatch_disk_t disk, dispatch_io_t channel); static void _dispatch_stream_source_handler(void *ctx); static void _dispatch_stream_queue_handler(void *ctx); @@ -119,6 +112,38 @@ enum { #define _dispatch_io_Block_copy(x) \ ((typeof(x))_dispatch_Block_copy((dispatch_block_t)(x))) +#pragma mark - +#pragma mark dispatch_io_debug + +#if DISPATCH_IO_DEBUG +#if !DISPATCH_DEBUG +#define _dispatch_io_log(x, ...) do { \ + _dispatch_log("%llu\t%p\t" x, _dispatch_absolute_time(), \ + (void *)_dispatch_thread_self(), ##__VA_ARGS__); \ + } while (0) +#ifdef _dispatch_object_debug +#undef _dispatch_object_debug +#define _dispatch_object_debug dispatch_debug +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif +#else +#define _dispatch_io_log(x, ...) _dispatch_debug(x, ##__VA_ARGS__) +#endif // DISPATCH_DEBUG +#else +#define _dispatch_io_log(x, ...) +#endif // DISPATCH_IO_DEBUG + +#define _dispatch_fd_debug(msg, fd, ...) \ + _dispatch_io_log("fd[0x%x]: " msg, fd, ##__VA_ARGS__) +#define _dispatch_op_debug(msg, op, ...) \ + _dispatch_io_log("op[%p]: " msg, op, ##__VA_ARGS__) +#define _dispatch_channel_debug(msg, channel, ...) \ + _dispatch_io_log("channel[%p]: " msg, channel, ##__VA_ARGS__) +#define _dispatch_fd_entry_debug(msg, fd_entry, ...) \ + _dispatch_io_log("fd_entry[%p]: " msg, fd_entry, ##__VA_ARGS__) +#define _dispatch_disk_debug(msg, disk, ...) \ + _dispatch_io_log("disk[%p]: " msg, disk, ##__VA_ARGS__) + #pragma mark - #pragma mark dispatch_io_hashtables @@ -227,7 +252,8 @@ _dispatch_io_init(dispatch_io_t channel, dispatch_fd_entry_t fd_entry, _dispatch_retain(queue); dispatch_async(!err ? fd_entry->close_queue : channel->queue, ^{ dispatch_async(queue, ^{ - _dispatch_fd_debug("cleanup handler invoke", -1); + _dispatch_channel_debug("cleanup handler invoke: err %d", + channel, err); cleanup_handler(err); }); _dispatch_release(queue); @@ -318,9 +344,9 @@ dispatch_io_create(dispatch_io_type_t type, dispatch_fd_t fd, if (type != DISPATCH_IO_STREAM && type != DISPATCH_IO_RANDOM) { return DISPATCH_BAD_INPUT; } - _dispatch_fd_debug("io create", fd); dispatch_io_t channel = _dispatch_io_create(type); channel->fd = fd; + _dispatch_channel_debug("create", channel); channel->fd_actual = fd; dispatch_suspend(channel->queue); _dispatch_retain(queue); @@ -374,9 +400,9 @@ dispatch_io_create_with_path(dispatch_io_type_t type, const char *path, if (!path_data) { return DISPATCH_OUT_OF_MEMORY; } - _dispatch_fd_debug("io create with path %s", -1, path); dispatch_io_t channel = _dispatch_io_create(type); channel->fd = -1; + _dispatch_channel_debug("create with path %s", channel, path); channel->fd_actual = -1; path_data->channel = channel; path_data->oflag = oflag; @@ -461,8 +487,8 @@ dispatch_io_create_with_io(dispatch_io_type_t type, dispatch_io_t in_channel, if (type != DISPATCH_IO_STREAM && type != DISPATCH_IO_RANDOM) { return DISPATCH_BAD_INPUT; } - _dispatch_fd_debug("io create with io %p", -1, in_channel); dispatch_io_t channel = _dispatch_io_create(type); + _dispatch_channel_debug("create with channel %p", channel, in_channel); dispatch_suspend(channel->queue); _dispatch_retain(queue); _dispatch_retain(channel); @@ -569,7 +595,7 @@ dispatch_io_set_high_water(dispatch_io_t channel, size_t high_water) { _dispatch_retain(channel); dispatch_async(channel->queue, ^{ - _dispatch_fd_debug("io set high water", channel->fd); + _dispatch_channel_debug("set high water: %zu", channel, high_water); if (channel->params.low > high_water) { channel->params.low = high_water; } @@ -583,7 +609,7 @@ dispatch_io_set_low_water(dispatch_io_t channel, size_t low_water) { _dispatch_retain(channel); dispatch_async(channel->queue, ^{ - _dispatch_fd_debug("io set low water", channel->fd); + _dispatch_channel_debug("set low water: %zu", channel, low_water); if (channel->params.high < low_water) { channel->params.high = low_water ? low_water : 1; } @@ -598,7 +624,7 @@ dispatch_io_set_interval(dispatch_io_t channel, uint64_t interval, { _dispatch_retain(channel); dispatch_async(channel->queue, ^{ - _dispatch_fd_debug("io set interval", channel->fd); + _dispatch_channel_debug("set interval: %llu", channel, interval); channel->params.interval = interval < INT64_MAX ? interval : INT64_MAX; channel->params.interval_flags = flags; _dispatch_release(channel); @@ -642,7 +668,7 @@ dispatch_io_get_descriptor(dispatch_io_t channel) static void _dispatch_io_stop(dispatch_io_t channel) { - _dispatch_fd_debug("io stop", channel->fd); + _dispatch_channel_debug("stop", channel); (void)os_atomic_or2o(channel, atomic_flags, DIO_STOPPED, relaxed); _dispatch_retain(channel); dispatch_async(channel->queue, ^{ @@ -650,7 +676,7 @@ _dispatch_io_stop(dispatch_io_t channel) _dispatch_object_debug(channel, "%s", __func__); dispatch_fd_entry_t fd_entry = channel->fd_entry; if (fd_entry) { - _dispatch_fd_debug("io stop cleanup", channel->fd); + _dispatch_channel_debug("stop cleanup", channel); _dispatch_fd_entry_cleanup_operations(fd_entry, channel); if (!(channel->atomic_flags & DIO_CLOSED)) { channel->fd_entry = NULL; @@ -661,8 +687,8 @@ _dispatch_io_stop(dispatch_io_t channel) _dispatch_retain(channel); dispatch_async(_dispatch_io_fds_lockq, ^{ _dispatch_object_debug(channel, "%s", __func__); - _dispatch_fd_debug("io stop after close cleanup", - channel->fd); + _dispatch_channel_debug("stop cleanup after close", + channel); dispatch_fd_entry_t fdi; uintptr_t hash = DIO_HASH(channel->fd); TAILQ_FOREACH(fdi, &_dispatch_io_fds[hash], fd_list) { @@ -697,7 +723,7 @@ dispatch_io_close(dispatch_io_t channel, unsigned long flags) dispatch_async(channel->queue, ^{ dispatch_async(channel->barrier_queue, ^{ _dispatch_object_debug(channel, "%s", __func__); - _dispatch_fd_debug("io close", channel->fd); + _dispatch_channel_debug("close", channel); if (!(channel->atomic_flags & (DIO_CLOSED|DIO_STOPPED))) { (void)os_atomic_or2o(channel, atomic_flags, DIO_CLOSED, relaxed); @@ -967,10 +993,6 @@ _dispatch_operation_create(dispatch_op_direction_t direction, { // On channel queue dispatch_assert(direction < DOP_DIR_MAX); - _dispatch_fd_debug("operation create", channel->fd); -#if DISPATCH_IO_DEBUG - int fd = channel->fd; -#endif // Safe to call _dispatch_io_get_error() with channel->fd_entry since // that can only be NULL if atomic_flags are set rdar://problem/8362514 int err = _dispatch_io_get_error(NULL, channel, false); @@ -985,7 +1007,8 @@ _dispatch_operation_create(dispatch_op_direction_t direction, } else if (direction == DOP_DIR_WRITE && !err) { d = NULL; } - _dispatch_fd_debug("IO handler invoke", fd); + _dispatch_channel_debug("IO handler invoke: err %d", channel, + err); handler(true, d, err); _dispatch_io_data_release(data); }); @@ -995,6 +1018,7 @@ _dispatch_operation_create(dispatch_op_direction_t direction, } dispatch_operation_t op = _dispatch_alloc(DISPATCH_VTABLE(operation), sizeof(struct dispatch_operation_s)); + _dispatch_channel_debug("operation create: %p", channel, op); op->do_next = DISPATCH_OBJECT_LISTLESS; op->do_xref_cnt = -1; // operation object is not exposed externally op->op_q = dispatch_queue_create("com.apple.libdispatch-io.opq", NULL); @@ -1023,6 +1047,7 @@ void _dispatch_operation_dispose(dispatch_operation_t op) { _dispatch_object_debug(op, "%s", __func__); + _dispatch_op_debug("dispose", op); // Deliver the data if there's any if (op->fd_entry) { _dispatch_operation_deliver_data(op, DOP_DONE); @@ -1049,6 +1074,7 @@ _dispatch_operation_dispose(dispatch_operation_t op) dispatch_release(op->op_q); } Block_release(op->handler); + _dispatch_op_debug("disposed", op); } static void @@ -1071,6 +1097,7 @@ _dispatch_operation_enqueue(dispatch_operation_t op, handler(true, d, err); _dispatch_io_data_release(data); }); + _dispatch_op_debug("release -> %d, err %d", op, op->do_ref_cnt, err); _dispatch_release(op); return; } @@ -1098,13 +1125,14 @@ _dispatch_operation_should_enqueue(dispatch_operation_t op, dispatch_queue_t tq, dispatch_data_t data) { // On stream queue or disk queue - _dispatch_fd_debug("enqueue operation", op->fd_entry->fd); + _dispatch_op_debug("enqueue", op); _dispatch_io_data_retain(data); op->data = data; int err = _dispatch_io_get_error(op, NULL, true); if (err) { op->err = err; // Final release + _dispatch_op_debug("release -> %d, err %d", op, op->do_ref_cnt, err); _dispatch_release(op); return false; } @@ -1241,7 +1269,6 @@ _dispatch_fd_entry_init_async(dispatch_fd_t fd, dispatch_once_f(&_dispatch_io_fds_lockq_pred, NULL, _dispatch_io_fds_lockq_init); dispatch_async(_dispatch_io_fds_lockq, ^{ - _dispatch_fd_debug("fd entry init", fd); dispatch_fd_entry_t fd_entry = NULL; // Check to see if there is an existing entry for the given fd uintptr_t hash = DIO_HASH(fd); @@ -1257,8 +1284,9 @@ _dispatch_fd_entry_init_async(dispatch_fd_t fd, // If we did not find an existing entry, create one fd_entry = _dispatch_fd_entry_create_with_fd(fd, hash); } + _dispatch_fd_entry_debug("init", fd_entry); dispatch_async(fd_entry->barrier_queue, ^{ - _dispatch_fd_debug("fd entry init completion", fd); + _dispatch_fd_entry_debug("init completion", fd_entry); completion_callback(fd_entry); // stat() is complete, release reference to fd_entry _dispatch_fd_entry_release(fd_entry); @@ -1286,16 +1314,16 @@ static dispatch_fd_entry_t _dispatch_fd_entry_create_with_fd(dispatch_fd_t fd, uintptr_t hash) { // On fds lock queue - _dispatch_fd_debug("fd entry create", fd); dispatch_fd_entry_t fd_entry = _dispatch_fd_entry_create( _dispatch_io_fds_lockq); + _dispatch_fd_entry_debug("create: fd %d", fd_entry, fd); fd_entry->fd = fd; TAILQ_INSERT_TAIL(&_dispatch_io_fds[hash], fd_entry, fd_list); fd_entry->barrier_queue = dispatch_queue_create( "com.apple.libdispatch-io.barrierq", NULL); fd_entry->barrier_group = dispatch_group_create(); dispatch_async(fd_entry->barrier_queue, ^{ - _dispatch_fd_debug("fd entry stat", fd); + _dispatch_fd_entry_debug("stat", fd_entry); int err, orig_flags, orig_nosigpipe = -1; struct stat st; _dispatch_io_syscall_switch(err, @@ -1367,7 +1395,7 @@ _dispatch_fd_entry_create_with_fd(dispatch_fd_t fd, uintptr_t hash) // all operations associated with this entry have been freed dispatch_async(fd_entry->close_queue, ^{ if (!fd_entry->disk) { - _dispatch_fd_debug("close queue fd_entry cleanup", fd); + _dispatch_fd_entry_debug("close queue cleanup", fd_entry); dispatch_op_direction_t dir; for (dir = 0; dir < DOP_DIR_MAX; dir++) { _dispatch_stream_dispose(fd_entry, dir); @@ -1385,11 +1413,11 @@ _dispatch_fd_entry_create_with_fd(dispatch_fd_t fd, uintptr_t hash) // source cancels it and suspends the close queue. Freeing the fd_entry // structure must happen after the source cancel handler has finished dispatch_async(fd_entry->close_queue, ^{ - _dispatch_fd_debug("close queue release", fd); + _dispatch_fd_entry_debug("close queue release", fd_entry); dispatch_release(fd_entry->close_queue); - _dispatch_fd_debug("barrier queue release", fd); + _dispatch_fd_entry_debug("barrier queue release", fd_entry); dispatch_release(fd_entry->barrier_queue); - _dispatch_fd_debug("barrier group release", fd); + _dispatch_fd_entry_debug("barrier group release", fd_entry); dispatch_release(fd_entry->barrier_group); if (fd_entry->orig_flags != -1) { _dispatch_io_syscall( @@ -1418,9 +1446,9 @@ _dispatch_fd_entry_create_with_path(dispatch_io_path_data_t path_data, dev_t dev, mode_t mode) { // On devs lock queue - _dispatch_fd_debug("fd entry create with path %s", -1, path_data->path); dispatch_fd_entry_t fd_entry = _dispatch_fd_entry_create( path_data->channel->queue); + _dispatch_fd_entry_debug("create: path %s", fd_entry, path_data->path); if (S_ISREG(mode)) { _dispatch_disk_init(fd_entry, major(dev)); } else { @@ -1439,7 +1467,7 @@ _dispatch_fd_entry_create_with_path(dispatch_io_path_data_t path_data, // that the channel associated with this entry has been closed and that // all operations associated with this entry have been freed dispatch_async(fd_entry->close_queue, ^{ - _dispatch_fd_debug("close queue fd_entry cleanup", -1); + _dispatch_fd_entry_debug("close queue cleanup", fd_entry); if (!fd_entry->disk) { dispatch_op_direction_t dir; for (dir = 0; dir < DOP_DIR_MAX; dir++) { @@ -1458,7 +1486,7 @@ _dispatch_fd_entry_create_with_path(dispatch_io_path_data_t path_data, } }); dispatch_async(fd_entry->close_queue, ^{ - _dispatch_fd_debug("close queue release", -1); + _dispatch_fd_entry_debug("close queue release", fd_entry); dispatch_release(fd_entry->close_queue); dispatch_release(fd_entry->barrier_queue); dispatch_release(fd_entry->barrier_group); @@ -1511,7 +1539,7 @@ _dispatch_fd_entry_cleanup_operations(dispatch_fd_entry_t fd_entry, } _dispatch_fd_entry_retain(fd_entry); dispatch_async(fd_entry->disk->pick_queue, ^{ - _dispatch_disk_cleanup_operations(fd_entry->disk, channel); + _dispatch_disk_cleanup_inactive_operations(fd_entry->disk, channel); _dispatch_fd_entry_release(fd_entry); if (channel) { _dispatch_release(channel); @@ -1683,7 +1711,7 @@ _dispatch_stream_complete_operation(dispatch_stream_t stream, { // On stream queue _dispatch_object_debug(op, "%s", __func__); - _dispatch_fd_debug("complete operation", op->fd_entry->fd); + _dispatch_op_debug("complete: stream %p", op, stream); TAILQ_REMOVE(&stream->operations[op->params.type], op, operation_list); if (op == stream->op) { stream->op = NULL; @@ -1692,6 +1720,7 @@ _dispatch_stream_complete_operation(dispatch_stream_t stream, dispatch_source_cancel(op->timer); } // Final release will deliver any pending data + _dispatch_op_debug("release -> %d (stream complete)", op, op->do_ref_cnt); _dispatch_release(op); } @@ -1700,7 +1729,7 @@ _dispatch_disk_complete_operation(dispatch_disk_t disk, dispatch_operation_t op) { // On pick queue _dispatch_object_debug(op, "%s", __func__); - _dispatch_fd_debug("complete operation", op->fd_entry->fd); + _dispatch_op_debug("complete: disk %p", op, disk); // Current request is always the last op returned if (disk->cur_rq == op) { disk->cur_rq = TAILQ_PREV(op, dispatch_disk_operations_s, @@ -1719,6 +1748,7 @@ _dispatch_disk_complete_operation(dispatch_disk_t disk, dispatch_operation_t op) dispatch_source_cancel(op->timer); } // Final release will deliver any pending data + _dispatch_op_debug("release -> %d (disk complete)", op, op->do_ref_cnt); _dispatch_release(op); } @@ -1806,18 +1836,34 @@ _dispatch_stream_cleanup_operations(dispatch_stream_t stream, } } -static void -_dispatch_disk_cleanup_operations(dispatch_disk_t disk, dispatch_io_t channel) +static inline void +_dispatch_disk_cleanup_specified_operations(dispatch_disk_t disk, + dispatch_io_t channel, bool inactive_only) { // On pick queue dispatch_operation_t op, tmp; TAILQ_FOREACH_SAFE(op, &disk->operations, operation_list, tmp) { + if (inactive_only && op->active) continue; if (!channel || op->channel == channel) { + _dispatch_op_debug("cleanup: disk %p", op, disk); _dispatch_disk_complete_operation(disk, op); } } } +static void +_dispatch_disk_cleanup_operations(dispatch_disk_t disk, dispatch_io_t channel) +{ + _dispatch_disk_cleanup_specified_operations(disk, channel, false); +} + +static void +_dispatch_disk_cleanup_inactive_operations(dispatch_disk_t disk, + dispatch_io_t channel) +{ + _dispatch_disk_cleanup_specified_operations(disk, channel, true); +} + #pragma mark - #pragma mark dispatch_stream_handler/dispatch_disk_handler @@ -1829,7 +1875,7 @@ _dispatch_stream_source(dispatch_stream_t stream, dispatch_operation_t op) return stream->source; } dispatch_fd_t fd = op->fd_entry->fd; - _dispatch_fd_debug("stream source create", fd); + _dispatch_op_debug("stream source create", op); dispatch_source_t source = NULL; if (op->direction == DOP_DIR_READ) { source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, @@ -1848,7 +1894,7 @@ _dispatch_stream_source(dispatch_stream_t stream, dispatch_operation_t op) // unregistered dispatch_queue_t close_queue = op->fd_entry->close_queue; dispatch_source_set_cancel_handler(source, ^{ - _dispatch_fd_debug("stream source cancel", fd); + _dispatch_op_debug("stream source cancel", op); dispatch_resume(close_queue); }); stream->source = source; @@ -1896,13 +1942,13 @@ _dispatch_stream_handler(void *ctx) goto pick; } stream->op = op; - _dispatch_fd_debug("stream handler", op->fd_entry->fd); + _dispatch_op_debug("stream handler", op); dispatch_fd_entry_t fd_entry = op->fd_entry; _dispatch_fd_entry_retain(fd_entry); // For performance analysis if (!op->total && dispatch_io_defaults.initial_delivery) { // Empty delivery to signal the start of the operation - _dispatch_fd_debug("initial delivery", op->fd_entry->fd); + _dispatch_op_debug("initial delivery", op); _dispatch_operation_deliver_data(op, DOP_DELIVER); } // TODO: perform on the operation target queue to get correct priority @@ -1960,7 +2006,7 @@ _dispatch_disk_handler(void *ctx) if (disk->io_active) { return; } - _dispatch_fd_debug("disk handler", -1); + _dispatch_disk_debug("disk handler", disk); dispatch_operation_t op; size_t i = disk->free_idx, j = disk->req_idx; if (j <= i) { @@ -1976,8 +2022,10 @@ _dispatch_disk_handler(void *ctx) continue; } _dispatch_retain(op); + _dispatch_op_debug("retain -> %d", op, op->do_ref_cnt + 1); disk->advise_list[i%disk->advise_list_depth] = op; op->active = true; + _dispatch_op_debug("activate: disk %p", op, disk); _dispatch_object_debug(op, "%s", __func__); } else { // No more operations to get @@ -1989,6 +2037,7 @@ _dispatch_disk_handler(void *ctx) op = disk->advise_list[disk->req_idx]; if (op) { disk->io_active = true; + _dispatch_op_debug("async perform: disk %p", op, disk); dispatch_async_f(op->do_targetq, disk, _dispatch_disk_perform); } } @@ -1997,8 +2046,8 @@ static void _dispatch_disk_perform(void *ctxt) { dispatch_disk_t disk = ctxt; + _dispatch_disk_debug("disk perform", disk); size_t chunk_size = dispatch_io_defaults.chunk_size; - _dispatch_fd_debug("disk perform", -1); dispatch_operation_t op; size_t i = disk->advise_idx, j = disk->free_idx; if (j <= i) { @@ -2022,7 +2071,7 @@ _dispatch_disk_perform(void *ctxt) // For performance analysis if (!op->total && dispatch_io_defaults.initial_delivery) { // Empty delivery to signal the start of the operation - _dispatch_fd_debug("initial delivery", op->fd_entry->fd); + _dispatch_op_debug("initial delivery", op); _dispatch_operation_deliver_data(op, DOP_DELIVER); } // Advise two chunks if the list only has one element and this is the @@ -2038,7 +2087,9 @@ _dispatch_disk_perform(void *ctxt) int result = _dispatch_operation_perform(op); disk->advise_list[disk->req_idx] = NULL; disk->req_idx = (++disk->req_idx)%disk->advise_list_depth; + _dispatch_op_debug("async perform completion: disk %p", op, disk); dispatch_async(disk->pick_queue, ^{ + _dispatch_op_debug("perform completion", op); switch (result) { case DISPATCH_OP_DELIVER: _dispatch_operation_deliver_data(op, DOP_DEFAULT); @@ -2060,12 +2111,15 @@ _dispatch_disk_perform(void *ctxt) dispatch_assert(result); break; } + _dispatch_op_debug("deactivate: disk %p", op, disk); op->active = false; disk->io_active = false; _dispatch_disk_handler(disk); // Balancing the retain in _dispatch_disk_handler. Note that op must be // released at the very end, since it might hold the last reference to // the disk + _dispatch_op_debug("release -> %d (disk perform complete)", op, + op->do_ref_cnt); _dispatch_release(op); }); } @@ -2076,6 +2130,8 @@ _dispatch_disk_perform(void *ctxt) static void _dispatch_operation_advise(dispatch_operation_t op, size_t chunk_size) { + _dispatch_op_debug("advise", op); + if (_dispatch_io_get_error(op, NULL, true)) return; #ifdef __linux__ // linux does not support fcntl (F_RDAVISE) // define necessary datastructure and use readahead @@ -2123,6 +2179,7 @@ _dispatch_operation_advise(dispatch_operation_t op, size_t chunk_size) static int _dispatch_operation_perform(dispatch_operation_t op) { + _dispatch_op_debug("perform", op); int err = _dispatch_io_get_error(op, NULL, true); if (err) { goto error; @@ -2151,7 +2208,7 @@ _dispatch_operation_perform(dispatch_operation_t op) op->buf_siz = max_buf_siz; } op->buf = valloc(op->buf_siz); - _dispatch_fd_debug("buffer allocated", op->fd_entry->fd); + _dispatch_op_debug("buffer allocated", op); } else if (op->direction == DOP_DIR_WRITE) { // Always write the first data piece, if that is smaller than a // chunk, accumulate further data pieces until chunk size is reached @@ -2177,7 +2234,7 @@ _dispatch_operation_perform(dispatch_operation_t op) op->buf_data = dispatch_data_create_map(d, (const void**)&op->buf, NULL); _dispatch_io_data_release(d); - _dispatch_fd_debug("buffer mapped", op->fd_entry->fd); + _dispatch_op_debug("buffer mapped", op); } } if (op->fd_entry->fd == -1) { @@ -2214,7 +2271,7 @@ _dispatch_operation_perform(dispatch_operation_t op) } // EOF is indicated by two handler invocations if (processed == 0) { - _dispatch_fd_debug("EOF", op->fd_entry->fd); + _dispatch_op_debug("performed: EOF", op); return DISPATCH_OP_DELIVER_AND_COMPLETE; } op->buf_len += (size_t)processed; @@ -2230,7 +2287,7 @@ _dispatch_operation_perform(dispatch_operation_t op) if (err == EAGAIN) { // For disk based files with blocking I/O we should never get EAGAIN dispatch_assert(!op->fd_entry->disk); - _dispatch_fd_debug("EAGAIN %d", op->fd_entry->fd, err); + _dispatch_op_debug("performed: EAGAIN", op); if (op->direction == DOP_DIR_READ && op->total && op->channel == op->fd_entry->convenience_channel) { // Convenience read with available data completes on EAGAIN @@ -2238,6 +2295,7 @@ _dispatch_operation_perform(dispatch_operation_t op) } return DISPATCH_OP_RESUME; } + _dispatch_op_debug("performed: err %d", op, err); op->err = err; switch (err) { case ECANCELED: @@ -2267,7 +2325,7 @@ _dispatch_operation_deliver_data(dispatch_operation_t op, deliver = true; } else if (op->buf_len < op->buf_siz) { // Request buffer is not yet used up - _dispatch_fd_debug("buffer data", op->fd_entry->fd); + _dispatch_op_debug("buffer data: undelivered %zu", op, undelivered); return; } } else { @@ -2321,17 +2379,14 @@ _dispatch_operation_deliver_data(dispatch_operation_t op, } if (!deliver || ((flags & DOP_NO_EMPTY) && !dispatch_data_get_size(data))) { op->undelivered = undelivered; - _dispatch_fd_debug("buffer data", op->fd_entry->fd); + _dispatch_op_debug("buffer data: undelivered %zu", op, undelivered); return; } op->undelivered = 0; _dispatch_object_debug(op, "%s", __func__); - _dispatch_fd_debug("deliver data", op->fd_entry->fd); + _dispatch_op_debug("deliver data", op); dispatch_op_direction_t direction = op->direction; dispatch_io_handler_t handler = op->handler; -#if DISPATCH_IO_DEBUG - int fd = op->fd_entry->fd; -#endif dispatch_fd_entry_t fd_entry = op->fd_entry; _dispatch_fd_entry_retain(fd_entry); dispatch_io_t channel = op->channel; @@ -2343,7 +2398,7 @@ _dispatch_operation_deliver_data(dispatch_operation_t op, if (done) { if (direction == DOP_DIR_READ && err) { if (dispatch_data_get_size(d)) { - _dispatch_fd_debug("IO handler invoke", fd); + _dispatch_op_debug("IO handler invoke", op); handler(false, d, 0); } d = NULL; @@ -2351,7 +2406,7 @@ _dispatch_operation_deliver_data(dispatch_operation_t op, d = NULL; } } - _dispatch_fd_debug("IO handler invoke", fd); + _dispatch_op_debug("IO handler invoke: err %d", op, err); handler(done, d, err); _dispatch_release(channel); _dispatch_fd_entry_release(fd_entry); diff --git a/src/once.c b/src/once.c index 82885ccd9..d7d6a8e64 100644 --- a/src/once.c +++ b/src/once.c @@ -60,7 +60,7 @@ dispatch_once_f(dispatch_once_t *val, void *ctxt, dispatch_function_t func) dispatch_thread_event_t event; if (os_atomic_cmpxchg(vval, NULL, tail, acquire)) { - dow.dow_thread = _dispatch_thread_port(); + dow.dow_thread = _dispatch_tid_self(); _dispatch_client_callout(ctxt, func); // The next barrier must be long and strong. diff --git a/src/queue.c b/src/queue.c index 2602994dc..58c545b17 100644 --- a/src/queue.c +++ b/src/queue.c @@ -1235,56 +1235,38 @@ _dispatch_queue_create_with_target(const char *label, dispatch_queue_attr_t dqa, DISPATCH_CLIENT_CRASH(dqa->do_vtable, "Invalid queue attribute"); } - _dispatch_queue_attr_overcommit_t overcommit = dqa->dqa_overcommit; - qos_class_t qos = dqa->dqa_qos_class; - dispatch_queue_flags_t dqf = 0; - const void *vtable; + // + // Step 1: Normalize arguments (qos, overcommit, tq) + // - if (overcommit != _dispatch_queue_attr_overcommit_unspecified && tq) { - if (tq->do_targetq) { - DISPATCH_CLIENT_CRASH(tq, "Cannot specify both overcommit and " - "a non global target queue"); - } + qos_class_t qos = dqa->dqa_qos_class; +#if DISPATCH_USE_NOQOS_WORKQUEUE_FALLBACK + if (qos == _DISPATCH_QOS_CLASS_USER_INTERACTIVE && + !_dispatch_root_queues[ + DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS].dq_priority) { + qos = _DISPATCH_QOS_CLASS_USER_INITIATED; } - - if (legacy) { - // if any of these attributes is specified, use non legacy classes - if (dqa->dqa_inactive || dqa->dqa_autorelease_frequency -#if 0 // - || overcommit != _dispatch_queue_attr_overcommit_unspecified #endif - ) { - legacy = false; + bool maintenance_fallback = false; +#if DISPATCH_USE_NOQOS_WORKQUEUE_FALLBACK + maintenance_fallback = true; +#endif // DISPATCH_USE_NOQOS_WORKQUEUE_FALLBACK + if (maintenance_fallback) { + if (qos == _DISPATCH_QOS_CLASS_MAINTENANCE && + !_dispatch_root_queues[ + DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS].dq_priority) { + qos = _DISPATCH_QOS_CLASS_BACKGROUND; } } - if (legacy) { - vtable = DISPATCH_VTABLE(queue); - } else if (dqa->dqa_concurrent) { - vtable = DISPATCH_VTABLE(queue_concurrent); - } else { - vtable = DISPATCH_VTABLE(queue_serial); - } - switch (dqa->dqa_autorelease_frequency) { - case DISPATCH_AUTORELEASE_FREQUENCY_NEVER: - dqf |= DQF_AUTORELEASE_NEVER; - break; - case DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM: - dqf |= DQF_AUTORELEASE_ALWAYS; - break; - } - if (label) { - const char *tmp = _dispatch_strdup_if_mutable(label); - if (tmp != label) { - dqf |= DQF_LABEL_NEEDS_FREE; - label = tmp; + + _dispatch_queue_attr_overcommit_t overcommit = dqa->dqa_overcommit; + if (overcommit != _dispatch_queue_attr_overcommit_unspecified && tq) { + if (tq->do_targetq) { + DISPATCH_CLIENT_CRASH(tq, "Cannot specify both overcommit and " + "a non-global target queue"); } } - dispatch_queue_t dq = _dispatch_alloc(vtable, - sizeof(struct dispatch_queue_s) - DISPATCH_QUEUE_CACHELINE_PAD); - _dispatch_queue_init(dq, dqf, dqa->dqa_concurrent ? - DISPATCH_QUEUE_WIDTH_MAX : 1, dqa->dqa_inactive); - dq->dq_label = label; if (tq && !tq->do_targetq && tq->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { // Handle discrepancies between attr and target queue, attributes win @@ -1296,15 +1278,8 @@ _dispatch_queue_create_with_target(const char *label, dispatch_queue_attr_t dqa, } } if (qos == _DISPATCH_QOS_CLASS_UNSPECIFIED) { - if (overcommit == _dispatch_queue_attr_overcommit_enabled) { - if (!(tq->dq_priority & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG)) { - tq++; - } - } else { - if (tq->dq_priority & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG) { - tq--; - } - } + tq = _dispatch_get_root_queue_with_overcommit(tq, + overcommit == _dispatch_queue_attr_overcommit_enabled); } else { tq = NULL; } @@ -1327,43 +1302,68 @@ _dispatch_queue_create_with_target(const char *label, dispatch_queue_attr_t dqa, _dispatch_queue_attr_overcommit_enabled; } } -#if HAVE_PTHREAD_WORKQUEUE_QOS - dq->dq_priority = (dispatch_priority_t)_pthread_qos_class_encode(qos, - dqa->dqa_relative_priority, - overcommit == _dispatch_queue_attr_overcommit_enabled ? - _PTHREAD_PRIORITY_OVERCOMMIT_FLAG : 0); -#endif if (!tq) { - if (qos == _DISPATCH_QOS_CLASS_UNSPECIFIED) { - qos = _DISPATCH_QOS_CLASS_DEFAULT; - } -#if DISPATCH_USE_NOQOS_WORKQUEUE_FALLBACK - if (qos == _DISPATCH_QOS_CLASS_USER_INTERACTIVE && - !_dispatch_root_queues[ - DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS].dq_priority) { - qos = _DISPATCH_QOS_CLASS_USER_INITIATED; - } -#endif - bool maintenance_fallback = false; -#if DISPATCH_USE_NOQOS_WORKQUEUE_FALLBACK - maintenance_fallback = true; -#endif // DISPATCH_USE_NOQOS_WORKQUEUE_FALLBACK - if (maintenance_fallback) { - if (qos == _DISPATCH_QOS_CLASS_MAINTENANCE && - !_dispatch_root_queues[ - DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS].dq_priority) { - qos = _DISPATCH_QOS_CLASS_BACKGROUND; - } - } - - tq = _dispatch_get_root_queue(qos, overcommit == + qos_class_t tq_qos = qos == _DISPATCH_QOS_CLASS_UNSPECIFIED ? + _DISPATCH_QOS_CLASS_DEFAULT : qos; + tq = _dispatch_get_root_queue(tq_qos, overcommit == _dispatch_queue_attr_overcommit_enabled); if (slowpath(!tq)) { DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute"); } + } + + // + // Step 2: Initialize the queue + // + + if (legacy) { + // if any of these attributes is specified, use non legacy classes + if (dqa->dqa_inactive || dqa->dqa_autorelease_frequency) { + legacy = false; + } + } + + const void *vtable; + dispatch_queue_flags_t dqf = 0; + if (legacy) { + vtable = DISPATCH_VTABLE(queue); + } else if (dqa->dqa_concurrent) { + vtable = DISPATCH_VTABLE(queue_concurrent); } else { + vtable = DISPATCH_VTABLE(queue_serial); + } + switch (dqa->dqa_autorelease_frequency) { + case DISPATCH_AUTORELEASE_FREQUENCY_NEVER: + dqf |= DQF_AUTORELEASE_NEVER; + break; + case DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM: + dqf |= DQF_AUTORELEASE_ALWAYS; + break; + } + if (label) { + const char *tmp = _dispatch_strdup_if_mutable(label); + if (tmp != label) { + dqf |= DQF_LABEL_NEEDS_FREE; + label = tmp; + } + } + + dispatch_queue_t dq = _dispatch_alloc(vtable, + sizeof(struct dispatch_queue_s) - DISPATCH_QUEUE_CACHELINE_PAD); + _dispatch_queue_init(dq, dqf, dqa->dqa_concurrent ? + DISPATCH_QUEUE_WIDTH_MAX : 1, dqa->dqa_inactive); + + dq->dq_label = label; + +#if HAVE_PTHREAD_WORKQUEUE_QOS + dq->dq_priority = (dispatch_priority_t)_pthread_qos_class_encode(qos, + dqa->dqa_relative_priority, + overcommit == _dispatch_queue_attr_overcommit_enabled ? + _PTHREAD_PRIORITY_OVERCOMMIT_FLAG : 0); +#endif + _dispatch_retain(tq); + if (qos == _DISPATCH_QOS_CLASS_UNSPECIFIED) { // legacy way of inherithing the QoS from the target - _dispatch_retain(tq); _dispatch_queue_priority_inherit_from_target(dq, tq); } if (!dqa->dqa_inactive) { @@ -2194,6 +2194,21 @@ _dispatch_pthread_root_queue_create_with_observer_hooks_4IOHID(const char *label } #endif +dispatch_queue_t +dispatch_pthread_root_queue_copy_current(void) +{ + dispatch_queue_t dq = _dispatch_queue_get_current(); + if (!dq) return NULL; + while (slowpath(dq->do_targetq)) { + dq = dq->do_targetq; + } + if (dx_type(dq) != DISPATCH_QUEUE_GLOBAL_ROOT_TYPE || + dq->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { + return NULL; + } + return (dispatch_queue_t)_os_object_retain_with_resurrect(dq->_as_os_obj); +} + #endif // DISPATCH_ENABLE_PTHREAD_ROOT_QUEUES void @@ -2550,7 +2565,7 @@ _dispatch_set_priority_and_mach_voucher_slow(pthread_priority_t pp, if (!pflags) return; int r = _pthread_set_properties_self(pflags, pp, kv); if (r == EINVAL) { - DISPATCH_INTERNAL_CRASH(0, "_pthread_set_properties_self failed"); + DISPATCH_INTERNAL_CRASH(pp, "_pthread_set_properties_self failed"); } (void)dispatch_assume_zero(r); } @@ -3174,10 +3189,24 @@ _dispatch_async_redirect_invoke(dispatch_continuation_t dc, dispatch_thread_frame_s dtf; struct dispatch_continuation_s *other_dc = dc->dc_other; dispatch_invoke_flags_t ctxt_flags = (dispatch_invoke_flags_t)dc->dc_ctxt; - dispatch_queue_t dq = dc->dc_data, rq, old_dq, old_rq = NULL; + // if we went through _dispatch_root_queue_push_override, + // the "right" root queue was stuffed into dc_func + dispatch_queue_t assumed_rq = (dispatch_queue_t)dc->dc_func; + dispatch_queue_t dq = dc->dc_data, rq, old_dq; + struct _dispatch_identity_s di; pthread_priority_t op, dp, old_dp; + if (ctxt_flags) { + flags &= ~_DISPATCH_INVOKE_AUTORELEASE_MASK; + flags |= ctxt_flags; + } + old_dq = _dispatch_get_current_queue(); + if (assumed_rq) { + _dispatch_queue_set_current(assumed_rq); + _dispatch_root_queue_identity_assume(&di, 0); + } + old_dp = _dispatch_set_defaultpriority(dq->dq_priority, &dp); op = dq->dq_override; if (op > (dp & _PTHREAD_PRIORITY_QOS_CLASS_MASK)) { @@ -3186,28 +3215,19 @@ _dispatch_async_redirect_invoke(dispatch_continuation_t dc, _dispatch_set_defaultpriority_override(); } - if (ctxt_flags) { - flags &= ~_DISPATCH_INVOKE_AUTORELEASE_MASK; - flags |= ctxt_flags; - } - if (dc->dc_func) { - // if we went through _dispatch_root_queue_push_override, - // the "right" root queue was stuffed into dc_func - old_rq = _dispatch_get_current_queue(); - _dispatch_queue_set_current((dispatch_queue_t)dc->dc_func); - } _dispatch_thread_frame_push(&dtf, dq); _dispatch_continuation_pop_forwarded(dc, DISPATCH_NO_VOUCHER, DISPATCH_OBJ_CONSUME_BIT, { _dispatch_continuation_pop(other_dc, dq, flags); }); - _dispatch_reset_defaultpriority(old_dp); _dispatch_thread_frame_pop(&dtf); - if (old_rq) { - _dispatch_queue_set_current(old_rq); + if (assumed_rq) { + _dispatch_root_queue_identity_restore(&di); + _dispatch_queue_set_current(old_dq); } + _dispatch_reset_defaultpriority(old_dp); + rq = dq->do_targetq; - old_dq = _dispatch_get_current_queue(); while (slowpath(rq->do_targetq) && rq != old_dq) { _dispatch_non_barrier_complete(rq); rq = rq->do_targetq; @@ -4230,9 +4250,6 @@ _dispatch_global_queue_poke_slow(dispatch_queue_t dq, unsigned int n) int r; _dispatch_debug_root_queue(dq, __func__); - dispatch_once_f(&_dispatch_root_queues_pred, NULL, - _dispatch_root_queues_init_once); - #if HAVE_PTHREAD_WORKQUEUES #if DISPATCH_USE_PTHREAD_POOL if (qc->dgq_kworkqueue != (void*)(~0ul)) @@ -4863,13 +4880,30 @@ _dispatch_queue_override_invoke(dispatch_continuation_t dc, DISPATCH_ALWAYS_INLINE static inline bool -_dispatch_root_queue_push_needs_override(dispatch_queue_t rq, +_dispatch_need_global_root_queue_push_override(dispatch_queue_t rq, pthread_priority_t pp) { - if (dx_type(rq) != DISPATCH_QUEUE_GLOBAL_ROOT_TYPE || !rq->dq_priority) { - return false; - } - return pp > (rq->dq_priority & _PTHREAD_PRIORITY_QOS_CLASS_MASK); + pthread_priority_t rqp = rq->dq_priority & _PTHREAD_PRIORITY_QOS_CLASS_MASK; + bool defaultqueue = rq->dq_priority & _PTHREAD_PRIORITY_DEFAULTQUEUE_FLAG; + + if (unlikely(!rqp)) return false; + + pp &= _PTHREAD_PRIORITY_QOS_CLASS_MASK; + return defaultqueue ? pp && pp != rqp : pp > rqp; +} + +DISPATCH_ALWAYS_INLINE +static inline bool +_dispatch_need_global_root_queue_push_override_stealer(dispatch_queue_t rq, + pthread_priority_t pp) +{ + pthread_priority_t rqp = rq->dq_priority & _PTHREAD_PRIORITY_QOS_CLASS_MASK; + bool defaultqueue = rq->dq_priority & _PTHREAD_PRIORITY_DEFAULTQUEUE_FLAG; + + if (unlikely(!rqp)) return false; + + pp &= _PTHREAD_PRIORITY_QOS_CLASS_MASK; + return defaultqueue || pp > rqp; } DISPATCH_NOINLINE @@ -5006,8 +5040,10 @@ _dispatch_queue_class_wakeup_with_override(dispatch_queue_t dq, } apply_again: - if (_dispatch_root_queue_push_needs_override(tq, pp)) { - _dispatch_root_queue_push_override_stealer(tq, dq, pp); + if (dx_type(tq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE) { + if (_dispatch_need_global_root_queue_push_override_stealer(tq, pp)) { + _dispatch_root_queue_push_override_stealer(tq, dq, pp); + } } else if (_dispatch_queue_need_override(tq, pp)) { dx_wakeup(tq, pp, DISPATCH_WAKEUP_OVERRIDING); } @@ -5095,8 +5131,7 @@ _dispatch_trystash_to_deferred_items(dispatch_queue_t dq, dispatch_object_t dou, dq = old_dq; dou._do = old_dou; } - if ((pp & _PTHREAD_PRIORITY_QOS_CLASS_MASK) > - (dq->dq_priority & _PTHREAD_PRIORITY_QOS_CLASS_MASK)) { + if (_dispatch_need_global_root_queue_push_override(dq, pp)) { return _dispatch_root_queue_push_override(dq, dou, pp); } // bit of cheating: we should really pass `pp` but we know that we are @@ -5107,23 +5142,37 @@ _dispatch_trystash_to_deferred_items(dispatch_queue_t dq, dispatch_object_t dou, } #endif +DISPATCH_NOINLINE +static void +_dispatch_queue_push_slow(dispatch_queue_t dq, dispatch_object_t dou, + pthread_priority_t pp) +{ + dispatch_once_f(&_dispatch_root_queues_pred, NULL, + _dispatch_root_queues_init_once); + _dispatch_queue_push(dq, dou, pp); +} + DISPATCH_NOINLINE void _dispatch_queue_push(dispatch_queue_t dq, dispatch_object_t dou, pthread_priority_t pp) { _dispatch_assert_is_valid_qos_override(pp); - if (dx_type(dq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE && dq->dq_priority) { + if (dx_type(dq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE) { #if DISPATCH_USE_KEVENT_WORKQUEUE dispatch_deferred_items_t ddi = _dispatch_deferred_items_get(); if (unlikely(ddi && !(ddi->ddi_stashed_pp & (dispatch_priority_t)_PTHREAD_PRIORITY_FLAGS_MASK))) { + dispatch_assert(_dispatch_root_queues_pred == DLOCK_ONCE_DONE); return _dispatch_trystash_to_deferred_items(dq, dou, pp, ddi); } #endif #if HAVE_PTHREAD_WORKQUEUE_QOS - if ((pp & _PTHREAD_PRIORITY_QOS_CLASS_MASK) > - (dq->dq_priority & _PTHREAD_PRIORITY_QOS_CLASS_MASK)) { + // can't use dispatch_once_f() as it would create a frame + if (unlikely(_dispatch_root_queues_pred != DLOCK_ONCE_DONE)) { + return _dispatch_queue_push_slow(dq, dou, pp); + } + if (_dispatch_need_global_root_queue_push_override(dq, pp)) { return _dispatch_root_queue_push_override(dq, dou, pp); } #endif @@ -5213,7 +5262,7 @@ _dispatch_queue_class_wakeup(dispatch_queue_t dq, pthread_priority_t pp, flags ^= DISPATCH_WAKEUP_SLOW_WAITER; dispatch_assert(!(flags & DISPATCH_WAKEUP_CONSUME)); - os_atomic_rmw_loop2o(dq, dq_state, old_state, new_state, release,{ + os_atomic_rmw_loop2o(dq, dq_state, old_state, new_state, release, { new_state = old_state | bits; if (_dq_state_drain_pended(old_state)) { // same as DISPATCH_QUEUE_DRAIN_UNLOCK_PRESERVE_WAITERS_BIT @@ -5221,21 +5270,22 @@ _dispatch_queue_class_wakeup(dispatch_queue_t dq, pthread_priority_t pp, new_state &= ~DISPATCH_QUEUE_DRAIN_OWNER_MASK; new_state &= ~DISPATCH_QUEUE_DRAIN_PENDED; } - if (likely(_dq_state_is_runnable(new_state) && - !_dq_state_drain_locked(new_state))) { - if (_dq_state_has_pending_barrier(old_state) || - new_state + pending_barrier_width < - DISPATCH_QUEUE_WIDTH_FULL_BIT) { - // see _dispatch_queue_drain_try_lock - new_state &= DISPATCH_QUEUE_DRAIN_PRESERVED_BITS_MASK; - new_state ^= xor_owner_and_set_full_width_and_in_barrier; - } else { - new_state |= DISPATCH_QUEUE_ENQUEUED; - } - } else if (_dq_state_drain_locked(new_state)) { + if (unlikely(_dq_state_drain_locked(new_state))) { #ifdef DLOCK_NOWAITERS_BIT new_state &= ~(uint64_t)DLOCK_NOWAITERS_BIT; #endif + } else if (unlikely(!_dq_state_is_runnable(new_state) || + !(flags & DISPATCH_WAKEUP_FLUSH))) { + // either not runnable, or was not for the first item (26700358) + // so we should not try to lock and handle overrides instead + } else if (_dq_state_has_pending_barrier(old_state) || + new_state + pending_barrier_width < + DISPATCH_QUEUE_WIDTH_FULL_BIT) { + // see _dispatch_queue_drain_try_lock + new_state &= DISPATCH_QUEUE_DRAIN_PRESERVED_BITS_MASK; + new_state ^= xor_owner_and_set_full_width_and_in_barrier; + } else { + new_state |= DISPATCH_QUEUE_ENQUEUED; } }); if ((old_state ^ new_state) & DISPATCH_QUEUE_IN_BARRIER) { @@ -5400,7 +5450,7 @@ _dispatch_root_queue_drain_deferred_item(dispatch_queue_t dq, pp = _dispatch_priority_inherit_from_root_queue(pp, dq); _dispatch_queue_set_current(dq); - _dispatch_root_queue_identity_assume(&di, pp, DISPATCH_IGNORE_UNBIND); + _dispatch_root_queue_identity_assume(&di, pp); #if DISPATCH_COCOA_COMPAT void *pool = _dispatch_last_resort_autorelease_pool_push(); #endif // DISPATCH_COCOA_COMPAT diff --git a/src/shims/lock.h b/src/shims/lock.h index 5c2dfc502..246c80738 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -497,12 +497,8 @@ _dispatch_gate_tryenter(dispatch_gate_t l) DLOCK_GATE_UNLOCKED, tid_self, acquire)); } -DISPATCH_ALWAYS_INLINE -static inline void -_dispatch_gate_wait(dispatch_gate_t l, dispatch_lock_options_t flags) -{ - _dispatch_gate_wait_slow(l, DLOCK_GATE_UNLOCKED, flags); -} +#define _dispatch_gate_wait(l, flags) \ + _dispatch_gate_wait_slow(l, DLOCK_GATE_UNLOCKED, flags) DISPATCH_ALWAYS_INLINE static inline void @@ -523,13 +519,9 @@ _dispatch_once_gate_tryenter(dispatch_once_gate_t l) DLOCK_ONCE_UNLOCKED, tid_self, acquire)); } -DISPATCH_ALWAYS_INLINE -static inline void -_dispatch_once_gate_wait(dispatch_once_gate_t l) -{ - _dispatch_gate_wait_slow(&l->dgo_gate, (dispatch_lock)DLOCK_ONCE_DONE, - DLOCK_LOCK_NONE); -} +#define _dispatch_once_gate_wait(l) \ + _dispatch_gate_wait_slow(&(l)->dgo_gate, (dispatch_lock)DLOCK_ONCE_DONE, \ + DLOCK_LOCK_NONE) DISPATCH_ALWAYS_INLINE static inline void diff --git a/src/source.c b/src/source.c index b01e9b2aa..a5a2c94a2 100644 --- a/src/source.c +++ b/src/source.c @@ -2433,7 +2433,7 @@ _dispatch_timers_calendar_change(void) _dispatch_timer_expired = true; for (qos = 0; qos < DISPATCH_TIMER_QOS_COUNT; qos++) { _dispatch_timers_mask |= - 1 << DISPATCH_TIMER_INDEX(DISPATCH_TIMER_WALL_CLOCK, qos); + 1 << DISPATCH_TIMER_INDEX(DISPATCH_TIMER_KIND_WALL, qos); } } #endif @@ -4566,6 +4566,9 @@ _dispatch_mach_msg_recv(dispatch_mach_t dm, dispatch_mach_reply_refs_t dmr, DISPATCH_MACH_MSG_DESTRUCTOR_DEFAULT : DISPATCH_MACH_MSG_DESTRUCTOR_FREE; dmsg = dispatch_mach_msg_create(hdr, siz, destructor, NULL); + if (hdr == _dispatch_kevent_mach_msg_buf(ke)) { + _dispatch_ktrace2(DISPATCH_MACH_MSG_hdr_move, (uint64_t)hdr, (uint64_t)dmsg->dmsg_buf); + } dmsg->dmsg_voucher = voucher; dmsg->dmsg_priority = priority; dmsg->do_ctxt = ctxt; @@ -4585,6 +4588,7 @@ _dispatch_mach_msg_reply_recv(dispatch_mach_t dm, } void *ctxt = dmr->dmr_ctxt; mach_msg_header_t *hdr, *hdr2 = NULL; + void *hdr_copyout_addr; mach_msg_size_t siz, msgsiz = 0; mach_msg_return_t kr; mach_msg_option_t options; @@ -4602,6 +4606,7 @@ _dispatch_mach_msg_reply_recv(dispatch_mach_t dm, (options & MACH_RCV_TIMEOUT) ? "poll" : "wait"); kr = mach_msg(hdr, options, 0, siz, reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + hdr_copyout_addr = hdr; _dispatch_debug_machport(reply_port); _dispatch_debug("machport[0x%08x]: MACH_RCV_MSG (size %u, opts 0x%x) " "returned: %s - 0x%x", reply_port, siz, options, @@ -4652,18 +4657,20 @@ _dispatch_mach_msg_reply_recv(dispatch_mach_t dm, dispatch_assume_zero(kr); break; } - if (slowpath(dm->dq_atomic_flags & DSF_CANCELED)) { + _dispatch_mach_msg_reply_received(dm, dmr, hdr->msgh_local_port); + hdr->msgh_local_port = MACH_PORT_NULL; + if (slowpath((dm->dq_atomic_flags & DSF_CANCELED) || kr)) { if (!kr) mach_msg_destroy(hdr); goto out; } - _dispatch_mach_msg_reply_received(dm, dmr, hdr->msgh_local_port); - hdr->msgh_local_port = MACH_PORT_NULL; - if (kr) goto out; dispatch_mach_msg_t dmsg; dispatch_mach_msg_destructor_t destructor = (!hdr2) ? DISPATCH_MACH_MSG_DESTRUCTOR_DEFAULT : DISPATCH_MACH_MSG_DESTRUCTOR_FREE; dmsg = dispatch_mach_msg_create(hdr, siz, destructor, NULL); + if (!hdr2 || hdr != hdr_copyout_addr) { + _dispatch_ktrace2(DISPATCH_MACH_MSG_hdr_move, (uint64_t)hdr_copyout_addr, (uint64_t)_dispatch_mach_msg_get_msg(dmsg)); + } dmsg->do_ctxt = ctxt; return dmsg; out: @@ -5902,8 +5909,12 @@ _dispatch_mach_install(dispatch_mach_t dm, pthread_priority_t pp) } if (dm->ds_is_direct_kevent) { pp &= (~_PTHREAD_PRIORITY_FLAGS_MASK | + _PTHREAD_PRIORITY_DEFAULTQUEUE_FLAG | _PTHREAD_PRIORITY_OVERCOMMIT_FLAG); // _dispatch_mach_reply_kevent_register assumes this has been done + // which is unlike regular sources or queues, the DEFAULTQUEUE flag + // is used so that the priority of that channel doesn't act as a floor + // QoS for incoming messages (26761457) dm->dq_priority = (dispatch_priority_t)pp; } dm->ds_is_installed = true; From fa5d032f0225701df3855039e7bf9b2889c1ec79 Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 15 Jul 2016 12:34:58 -0400 Subject: [PATCH 36/67] define SWIFT_CC(swift) macro for DispatchStubs resolve FIXME left in initial Swift3 port to Linux by replicating definition of SWIFT_CC(swift) from swift/include/Runtime/Config.h. Signed-off-by: Daniel A. Steffen --- src/swift/DispatchStubs.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/swift/DispatchStubs.cc b/src/swift/DispatchStubs.cc index 1e5ec74f7..ae8229928 100644 --- a/src/swift/DispatchStubs.cc +++ b/src/swift/DispatchStubs.cc @@ -51,10 +51,16 @@ static void _dispatch_overlay_constructor() { #endif /* USE_OBJC */ -#if 0 /* FIXME -- adding directory to include path may need build-script plumbing to do properly... */ -#include "swift/Runtime/Config.h" + +// Replicate the SWIFT_CC(swift) calling convention macro from +// swift/include/swift/Runtime/Config.h because it is +// quite awkward to include Config.h and its recursive includes +// in dispatch. This define must be manually kept in synch +#define SWIFT_CC(CC) SWIFT_CC_##CC +#if SWIFT_USE_SWIFTCALL +#define SWIFT_CC_swift __attribute__((swiftcall)) #else -#define SWIFT_CC(x) /* FIXME!! */ +#define SWIFT_CC_swift #endif SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE From d871b975c78a84c1e4ea641e746fef4408918d68 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Fri, 15 Jul 2016 10:37:49 -0700 Subject: [PATCH 37/67] Merge pull request #106 from dgrove-oss/dispatch-stubs-fixme define SWIFT_CC(swift) macro for DispatchStubs Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 28f7c5248..6b573f2d3 100644 --- a/PATCHES +++ b/PATCHES @@ -253,3 +253,4 @@ github commits starting with 29bdc2f from [2dbf83c] APPLIED rdar://27303844 [78b9e82] APPLIED rdar://27303844 [2c0e5ee] APPLIED rdar://27303844 +[5ee237f] APPLIED rdar://27600964 From c16870e5f41c2600259c4a71c4f7af7d017503d7 Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 15 Jul 2016 12:56:09 -0400 Subject: [PATCH 38/67] cleanup: remove LINUX_PORT_HDD remnants from initial porting work Signed-off-by: Daniel A. Steffen --- src/shims/linux_stubs.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/shims/linux_stubs.h b/src/shims/linux_stubs.h index 6a70c0b11..fea3d502b 100644 --- a/src/shims/linux_stubs.h +++ b/src/shims/linux_stubs.h @@ -16,9 +16,6 @@ #ifndef __DISPATCH__STUBS__INTERNAL #define __DISPATCH__STUBS__INTERNAL -// marker for hacks we have made to make progress -#define __LINUX_PORT_HDD__ 1 - /* * Stub out defines for some mach types and related macros */ From 2cfc71e8fa318a9808bf3eb36b4c6b2ffed5334a Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Fri, 15 Jul 2016 10:38:31 -0700 Subject: [PATCH 39/67] Merge pull request #107 from dgrove-oss/cleanup-hdd-remnants cleanup: remove LINUX_PORT_HDD remnants from initial porting work Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 6b573f2d3..79d5b5a75 100644 --- a/PATCHES +++ b/PATCHES @@ -254,3 +254,4 @@ github commits starting with 29bdc2f from [78b9e82] APPLIED rdar://27303844 [2c0e5ee] APPLIED rdar://27303844 [5ee237f] APPLIED rdar://27600964 +[77299ec] APPLIED rdar://27600964 From 9b63963e73db03fd0bceba286fb0c1a61e2916b4 Mon Sep 17 00:00:00 2001 From: David Grove Date: Tue, 19 Jul 2016 14:00:47 -0400 Subject: [PATCH 40/67] autoconf support for selecting build variant Add a command line option to allow selecting a build variant (debug, release, releaseassert, releasedebuginfo). If no variant is selected, default to release. Also two small fixes to compilation errors in code guarded by DISPATCH_DEBUG to allow the debug and releaseassert variants to build successfully. Signed-off-by: Daniel A. Steffen --- configure.ac | 40 ++++++++++++++++++++++++++++++++++++++++ src/Makefile.am | 6 ++++++ src/internal.h | 4 ++++ 3 files changed, 50 insertions(+) diff --git a/configure.ac b/configure.ac index e5c7c5ed7..675f7ff47 100644 --- a/configure.ac +++ b/configure.ac @@ -11,6 +11,46 @@ AC_CONFIG_MACRO_DIR([m4]) ac_clean_files=a.out.dSYM AM_MAINTAINER_MODE +# +# Command line argument to specify build variant (default to release). +# Impacts default value of CFLAGS et al. so must come before AC_PROG_CC +# +AC_ARG_WITH([build-variant], + [AS_HELP_STRING([--with-build-variant=release|debug|releaseassert|releasedebuginfo], [Specify build variant [default=release]])], + [dispatch_build_variant=${withval}], + [dispatch_build_variant=release] +) +AS_CASE([$dispatch_build_variant], + [debug], [ + default_compiler_flags="-g -O0" + dispatch_enable_asserts=true + dispatch_enable_optimization=false + ], + [release], [ + default_compiler_flags="-O2" + dispatch_enable_asserts=false + dispatch_enable_optimization=true + ], + [releaseassert], [ + default_compiler_flags="-O2" + dispatch_enable_asserts=true + dispatch_enable_optimization=true + ], + [releasedebuginfo], [ + default_compiler_flags="-g -O2" + dispatch_enable_asserts=false + dispatch_enable_optimization=true + ], + [AC_MSG_ERROR("invalid build-variant $dispatch_build_variant")] +) +AM_CONDITIONAL(DISPATCH_ENABLE_ASSERTS, $dispatch_enable_asserts) +AM_CONDITIONAL(DISPATCH_ENABLE_OPTIMIZATION, $dispatch_enable_optimization) + +: ${CFLAGS=$default_compiler_flags} +: ${CXXFLAGS=$default_compiler_flags} +: ${OBJCFLAGS=$default_compiler_flags} +: ${OBJCXXFLAGS=$default_compiler_flags} + AC_PROG_CC([clang gcc cc]) AC_PROG_CXX([clang++ g++ c++]) AC_PROG_OBJC([clang gcc cc]) diff --git a/src/Makefile.am b/src/Makefile.am index c417aec97..2c0127bf7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -61,6 +61,9 @@ AM_CPPFLAGS=-I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/private DISPATCH_CFLAGS=-Wall $(VISIBILITY_FLAGS) $(OMIT_LEAF_FP_FLAGS) \ $(MARCH_FLAGS) $(KQUEUE_CFLAGS) $(BSD_OVERLAY_CFLAGS) +if DISPATCH_ENABLE_ASSERTS +DISPATCH_CFLAGS+=-DDISPATCH_DEBUG=1 +endif AM_CFLAGS= $(PTHREAD_WORKQUEUE_CFLAGS) $(DISPATCH_CFLAGS) $(CBLOCKS_FLAGS) AM_OBJCFLAGS=$(DISPATCH_CFLAGS) $(CBLOCKS_FLAGS) AM_CXXFLAGS=$(PTHREAD_WORKQUEUE_CFLAGS) $(DISPATCH_CFLAGS) $(CXXBLOCKS_FLAGS) @@ -150,6 +153,9 @@ SWIFT_GEN_FILES= \ $(SWIFT_OBJ_FILES:%=%.~partial.swiftdeps) SWIFTC_FLAGS = -Xcc -fmodule-map-file=$(abs_top_srcdir)/dispatch/module.map -I$(abs_top_srcdir) -Xcc -fblocks +if DISPATCH_ENABLE_OPTIMIZATION +SWIFTC_FLAGS+=-O +endif $(abs_builddir)/swift/%.o: $(abs_srcdir)/swift/%.swift $(SWIFTC) -frontend -c $(SWIFT_ABS_SRC_FILES) -primary-file $< \ diff --git a/src/internal.h b/src/internal.h index a9aee1123..4408d9672 100644 --- a/src/internal.h +++ b/src/internal.h @@ -352,8 +352,12 @@ DISPATCH_EXPORT DISPATCH_NOTHROW void dispatch_atfork_child(void); #if DISPATCH_DEBUG // sys/queue.h debugging +#if defined(__linux__) +#define QUEUE_MACRO_DEBUG 1 +#else #undef TRASHIT #define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#endif #endif // DISPATCH_DEBUG #define _TAILQ_TRASH_ENTRY(elm, field) do { \ TRASHIT((elm)->field.tqe_next); \ From 927f39470c79630257f6baebdc1735777ac1ed6c Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Tue, 19 Jul 2016 14:45:33 -0700 Subject: [PATCH 41/67] Merge pull request #110 from dgrove-oss/build-variants autoconf support for selecting build variant Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 79d5b5a75..439473c54 100644 --- a/PATCHES +++ b/PATCHES @@ -255,3 +255,4 @@ github commits starting with 29bdc2f from [2c0e5ee] APPLIED rdar://27303844 [5ee237f] APPLIED rdar://27600964 [77299ec] APPLIED rdar://27600964 +[57c5c28] APPLIED rdar://27600964 From b1bdd358ac7de3c764b84087f3c3e2806b974a5f Mon Sep 17 00:00:00 2001 From: seabaylea Date: Wed, 20 Jul 2016 08:21:41 +0100 Subject: [PATCH 42/67] Add libkqueue as a git submodule to pick up kqueue fixes Signed-off-by: Daniel A. Steffen --- .gitmodules | 3 +++ Makefile.am | 31 +++++++++++++++---------------- configure.ac | 16 +++++++++++----- libkqueue | 1 + src/Makefile.am | 11 ++++++++--- 5 files changed, 38 insertions(+), 24 deletions(-) create mode 160000 libkqueue diff --git a/.gitmodules b/.gitmodules index e6068b432..009b5fbf1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "libpwq"] path = libpwq url = https://github.com/mheily/libpwq.git +[submodule "libkqueue"] + path = libkqueue + url = https://github.com/mheily/libkqueue.git diff --git a/Makefile.am b/Makefile.am index cc01c7c27..cdc642f4d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,24 +5,23 @@ ACLOCAL_AMFLAGS = -I m4 if BUILD_OWN_PTHREAD_WORKQUEUES -SUBDIRS= \ - dispatch \ - libpwq \ - man \ - os \ - private \ - src \ - tests -else -SUBDIRS= \ - dispatch \ - man \ - os \ - private \ - src \ - tests + MAYBE_PTHREAD_WORKQUEUES = libpwq +endif + +if BUILD_OWN_KQUEUES + MAYBE_KQUEUES = libkqueue endif +SUBDIRS= \ + dispatch \ + $(MAYBE_PTHREAD_WORKQUEUES) \ + $(MAYBE_KQUEUES) \ + man \ + os \ + private \ + src \ + tests + EXTRA_DIST= \ README.md \ LICENSE \ diff --git a/configure.ac b/configure.ac index 675f7ff47..a279ab6ab 100644 --- a/configure.ac +++ b/configure.ac @@ -223,12 +223,18 @@ esac AC_SEARCH_LIBS(clock_gettime, rt) AC_SEARCH_LIBS(pthread_create, pthread) -# -# Prefer native kqueue(2); otherwise use libkqueue if present. -# -AC_CHECK_HEADER(sys/event.h, [], - [PKG_CHECK_MODULES(KQUEUE, libkqueue)] +AS_IF([test -f $srcdir/libkqueue/configure.ac], + [AC_DEFINE(BUILD_OWN_KQUEUES, 1, [Define if building libkqueue from source]) + ac_configure_args="--disable-libkqueue-install $ac_configure_args" + AC_CONFIG_SUBDIRS([libkqueue]) + build_own_kqueues=true], + [build_own_kqueues=false + AC_CHECK_HEADER(sys/event.h, [], + [PKG_CHECK_MODULES(KQUEUE, libkqueue)] + ) + ] ) +AM_CONDITIONAL(BUILD_OWN_KQUEUES, $build_own_kqueues) AC_CHECK_FUNCS([strlcpy getprogname], [], [PKG_CHECK_MODULES(BSD_OVERLAY, libbsd-overlay,[ diff --git a/libkqueue b/libkqueue new file mode 160000 index 000000000..f4f39d6b3 --- /dev/null +++ b/libkqueue @@ -0,0 +1 @@ +Subproject commit f4f39d6b3079c54b1c7728226e57b7ecddfecf8b diff --git a/src/Makefile.am b/src/Makefile.am index 2c0127bf7..5be905dc4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,15 +60,20 @@ EXTRA_libdispatch_la_DEPENDENCIES= AM_CPPFLAGS=-I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/private DISPATCH_CFLAGS=-Wall $(VISIBILITY_FLAGS) $(OMIT_LEAF_FP_FLAGS) \ - $(MARCH_FLAGS) $(KQUEUE_CFLAGS) $(BSD_OVERLAY_CFLAGS) + $(MARCH_FLAGS) $(BSD_OVERLAY_CFLAGS) if DISPATCH_ENABLE_ASSERTS DISPATCH_CFLAGS+=-DDISPATCH_DEBUG=1 endif -AM_CFLAGS= $(PTHREAD_WORKQUEUE_CFLAGS) $(DISPATCH_CFLAGS) $(CBLOCKS_FLAGS) +AM_CFLAGS= $(KQUEUE_CFLAGS) $(PTHREAD_WORKQUEUE_CFLAGS) $(DISPATCH_CFLAGS) $(CBLOCKS_FLAGS) AM_OBJCFLAGS=$(DISPATCH_CFLAGS) $(CBLOCKS_FLAGS) -AM_CXXFLAGS=$(PTHREAD_WORKQUEUE_CFLAGS) $(DISPATCH_CFLAGS) $(CXXBLOCKS_FLAGS) +AM_CXXFLAGS=$(KQUEUE_CFLAGS) $(PTHREAD_WORKQUEUE_CFLAGS) $(DISPATCH_CFLAGS) $(CXXBLOCKS_FLAGS) AM_OBJCXXFLAGS=$(DISPATCH_CFLAGS) $(CXXBLOCKS_FLAGS) +if BUILD_OWN_KQUEUES + KQUEUE_LIBS+=$(top_builddir)/libkqueue/libkqueue.la + KQUEUE_CFLAGS+=-I$(top_srcdir)/libkqueue/include +endif + if BUILD_OWN_PTHREAD_WORKQUEUES PTHREAD_WORKQUEUE_LIBS=$(top_builddir)/libpwq/libpthread_workqueue.la PTHREAD_WORKQUEUE_CFLAGS=-I$(top_srcdir)/libpwq/include From 9128fb2f84a25b9e0f3ed6efdb8cfbf2a9a2dd2a Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 20 Jul 2016 02:17:54 -0700 Subject: [PATCH 43/67] Merge pull request #109 from seabaylea/kqueue Add libkqueue as a git submodule Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 439473c54..fc1812d50 100644 --- a/PATCHES +++ b/PATCHES @@ -256,3 +256,4 @@ github commits starting with 29bdc2f from [5ee237f] APPLIED rdar://27600964 [77299ec] APPLIED rdar://27600964 [57c5c28] APPLIED rdar://27600964 +[f8423ec] APPLIED rdar://27600964 From 3088ec5f624321a0d2c7d22074934bdf312f0609 Mon Sep 17 00:00:00 2001 From: David Grove Date: Wed, 20 Jul 2016 10:22:28 -0400 Subject: [PATCH 44/67] update libkqueue version to include PR-14 (kevent64 timer resolution support) Signed-off-by: Daniel A. Steffen --- libkqueue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libkqueue b/libkqueue index f4f39d6b3..b9e015210 160000 --- a/libkqueue +++ b/libkqueue @@ -1 +1 @@ -Subproject commit f4f39d6b3079c54b1c7728226e57b7ecddfecf8b +Subproject commit b9e015210bb3e432f44afd054b24a8ceb99eb8e7 From 34df16397b79c95218b1d98cbb0d338c3c99a2ad Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 20 Jul 2016 08:35:02 -0700 Subject: [PATCH 45/67] Merge pull request #112 from dgrove-oss/refresh-kqueue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update libkqueue version to include PR-14 (kevent64 timer resolution … Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index fc1812d50..d76d664cc 100644 --- a/PATCHES +++ b/PATCHES @@ -257,3 +257,4 @@ github commits starting with 29bdc2f from [77299ec] APPLIED rdar://27600964 [57c5c28] APPLIED rdar://27600964 [f8423ec] APPLIED rdar://27600964 +[325f73d] APPLIED rdar://27600964 From 196c268eae9798cb50b09d7e99e424308ab9ee03 Mon Sep 17 00:00:00 2001 From: Hubertus Franke Date: Wed, 20 Jul 2016 14:47:03 -0400 Subject: [PATCH 46/67] leverage of new kevent timer granularity functionality Signed-off-by: Daniel A. Steffen --- src/shims/linux_stubs.h | 3 +++ src/source.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/shims/linux_stubs.h b/src/shims/linux_stubs.h index fea3d502b..e13304906 100644 --- a/src/shims/linux_stubs.h +++ b/src/shims/linux_stubs.h @@ -82,10 +82,13 @@ typedef void (*dispatch_mach_msg_destructor_t)(void*); #define IGNORE_KEVENT64_EXT /* will force the kevent64_s.ext[] to not be used -> leeway ignored */ +#ifndef NOTE_SECONDS #define NOTE_SECONDS 0x01 #define NOTE_USECONDS 0x02 #define NOTE_NSECONDS 0x04 #define NOTE_ABSOLUTE 0x08 +#define KEVENT_NSEC_NOT_SUPPORTED +#endif #define NOTE_CRITICAL 0x10 #define NOTE_BACKGROUND 0x20 #define NOTE_LEEWAY 0x40 diff --git a/src/source.c b/src/source.c index a5a2c94a2..0693a712a 100644 --- a/src/source.c +++ b/src/source.c @@ -2339,11 +2339,15 @@ _dispatch_kevent_timer_set_delay(_dispatch_kevent_qos_s *ke, uint64_t delay, { // call to update nows[] _dispatch_source_timer_now(nows, DISPATCH_TIMER_KIND_WALL); +#if KEVENT_NSEC_NOT_SUPPORTED // adjust nsec based delay to msec based and ignore leeway delay /= 1000000L; if ((int64_t)(delay) <= 0) { delay = 1; // if value <= 0 the dispatch will stop } +#else + ke->fflags |= NOTE_NSECONDS; +#endif ke->data = (int64_t)delay; } From afbcf855368b042486d445c2c06adc1757d22706 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 20 Jul 2016 11:55:42 -0700 Subject: [PATCH 47/67] Merge pull request #113 from frankeh/kevent_nsecs leverage of new kevent timer granularity functionality Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index d76d664cc..ee38d38a7 100644 --- a/PATCHES +++ b/PATCHES @@ -258,3 +258,4 @@ github commits starting with 29bdc2f from [57c5c28] APPLIED rdar://27600964 [f8423ec] APPLIED rdar://27600964 [325f73d] APPLIED rdar://27600964 +[b84e87e] APPLIED rdar://27600964 From 191a607d73fc71ccf708d71a1bab3779f9c9797e Mon Sep 17 00:00:00 2001 From: SpringsUp Date: Wed, 20 Jul 2016 07:16:44 +0200 Subject: [PATCH 48/67] [Data] fix crash when creating iterator of empty DispatchData Signed-off-by: Daniel A. Steffen --- src/swift/Data.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index 0d21e27c0..ebec5e5a4 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -238,14 +238,15 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { var ptr: UnsafePointer? self._count = 0 self._data = CDispatch.dispatch_data_create_map(_data.__wrapped, &ptr, &self._count) - self._ptr = UnsafePointer(ptr!) + self._ptr = UnsafePointer(ptr) self._position = _data.startIndex + + // The only time we expect a 'nil' pointer is when the data is empty. + assert(self._ptr != nil || self._count == self._position) } /// Advance to the next element and return it, or `nil` if no next /// element exists. - /// - /// - Precondition: No preceding call to `self.next()` has returned `nil`. public mutating func next() -> DispatchData._Element? { if _position == _count { return nil } let element = _ptr[_position]; @@ -254,7 +255,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { } internal let _data: dispatch_data_t - internal var _ptr: UnsafePointer + internal var _ptr: UnsafePointer! internal var _count: Int internal var _position: DispatchData.Index } From 9e7cb391f9faad25be59fce34b03c058b949e619 Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Wed, 20 Jul 2016 16:46:53 -0700 Subject: [PATCH 49/67] Merge pull request #111 from karwa/master [Data] fix crash when creating iterator of empty DispatchData Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index ee38d38a7..2118aa253 100644 --- a/PATCHES +++ b/PATCHES @@ -259,3 +259,4 @@ github commits starting with 29bdc2f from [f8423ec] APPLIED rdar://27600964 [325f73d] APPLIED rdar://27600964 [b84e87e] APPLIED rdar://27600964 +[ae71a91] APPLIED rdar://27600964 From 4fd82524d67cdd80c457c576cd1064f5640b0b71 Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 15 Jul 2016 16:46:42 -0400 Subject: [PATCH 50/67] deallocation support for DispatchData on Linux Deallocation / reference counting support for DispatchData in the wrapping overlay consisting of two main pieces. First, since DispatchData is a struct and dispatch_data_t is a COpaquePointer, we need an intermediate class __DispatchData on which to perform the reference counting operations to enable the backing _dispatch_data_t to be deallocated when they are no longer reachable. I overlooked the mapping of _dispatch_data_t to OS_dispatch_data in Dispatch.apinotes in my initial pull request for the wrapping overlay and as a result all the dispatch_data_t instances were not being reference counted. Second, enable the DispatchData.Deallocator portion of the API. After some experimentation, found a way to have the desired API without getting a reference to _TMBO in the generated code. Left a FIXME because the current approach is sub-optimal in where it converts from Swift blocks to @convention(block) blocks. Signed-off-by: Daniel A. Steffen --- src/swift/Data.swift | 52 ++++++++++++++++++++++------------------- src/swift/IO.swift | 4 ++-- src/swift/Wrapper.swift | 22 ++++++++++++++--- 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index ebec5e5a4..9d68ad3ad 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -19,7 +19,6 @@ public struct DispatchData : RandomAccessCollection { public static let empty: DispatchData = DispatchData(data: _swift_dispatch_data_empty()) -#if false /* FIXME: dragging in _TMBO (Objective-C) */ public enum Deallocator { /// Use `free` case free @@ -28,7 +27,13 @@ public struct DispatchData : RandomAccessCollection { case unmap /// A custom deallocator - case custom(DispatchQueue?, @convention(block) () -> Void) + // FIXME: Want @convention(block) here to minimize the overhead of + // doing the conversion (once per custom enum instance instead + // of once per call to DispatchData.init using the enum instance). + // However, adding the annotation here results in Data.o containing + // a reference to _TMBO (opaque metadata for Builtin.UnknownObject) + // which is only made available on platforms with Objective-C. + case custom(DispatchQueue?, () -> Void) private var _deallocator: (DispatchQueue?, @convention(block) () -> Void) { switch self { @@ -38,35 +43,34 @@ public struct DispatchData : RandomAccessCollection { } } } -#endif - internal var __wrapped: dispatch_data_t + + internal var __wrapped: __DispatchData /// Initialize a `Data` with copied memory content. /// /// - parameter bytes: A pointer to the memory. It will be copied. /// - parameter count: The number of bytes to copy. public init(bytes buffer: UnsafeBufferPointer) { - __wrapped = dispatch_data_create( - buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default()) + let d = dispatch_data_create(buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default()) + self.init(data: d) } -#if false /* FIXME: dragging in _TMBO (Objective-C) */ + /// Initialize a `Data` without copying the bytes. /// - /// - parameter bytes: A pointer to the bytes. - /// - parameter count: The size of the bytes. + /// - parameter bytes: A buffer pointer containing the data. /// - parameter deallocator: Specifies the mechanism to free the indicated buffer. public init(bytesNoCopy bytes: UnsafeBufferPointer, deallocator: Deallocator = .free) { let (q, b) = deallocator._deallocator - - __wrapped = dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b) + let d = dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b) + self.init(data: d) } -#endif + internal init(data: dispatch_data_t) { - __wrapped = data + __wrapped = __DispatchData(data: data) } public var count: Int { - return CDispatch.dispatch_data_get_size(__wrapped) + return CDispatch.dispatch_data_get_size(__wrapped.__wrapped) } public func withUnsafeBytes( @@ -74,7 +78,7 @@ public struct DispatchData : RandomAccessCollection { { var ptr: UnsafePointer? = nil var size = 0; - let data = CDispatch.dispatch_data_create_map(__wrapped, &ptr, &size) + let data = CDispatch.dispatch_data_create_map(__wrapped.__wrapped, &ptr, &size) defer { _fixLifetime(data) } return try body(UnsafePointer(ptr!)) } @@ -82,7 +86,7 @@ public struct DispatchData : RandomAccessCollection { public func enumerateBytes( block: @noescape (buffer: UnsafeBufferPointer, byteIndex: Int, stop: inout Bool) -> Void) { - _swift_dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in + _swift_dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in let bp = UnsafeBufferPointer(start: UnsafePointer(ptr), count: size) var stop = false block(buffer: bp, byteIndex: offset, stop: &stop) @@ -103,8 +107,8 @@ public struct DispatchData : RandomAccessCollection { /// /// - parameter data: The data to append to this data. public mutating func append(_ other: DispatchData) { - let data = CDispatch.dispatch_data_create_concat(__wrapped, other.__wrapped) - __wrapped = data + let data = CDispatch.dispatch_data_create_concat(__wrapped.__wrapped, other.__wrapped.__wrapped) + __wrapped = __DispatchData(data: data) } /// Append a buffer of bytes to the data. @@ -116,7 +120,7 @@ public struct DispatchData : RandomAccessCollection { private func _copyBytesHelper(to pointer: UnsafeMutablePointer, from range: CountableRange) { var copiedCount = 0 - _ = CDispatch.dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in + _ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in let limit = Swift.min((range.endIndex - range.startIndex) - copiedCount, size) memcpy(pointer + copiedCount, ptr, limit) copiedCount += limit @@ -177,7 +181,7 @@ public struct DispatchData : RandomAccessCollection { /// Sets or returns the byte at the specified index. public subscript(index: Index) -> UInt8 { var offset = 0 - let subdata = CDispatch.dispatch_data_copy_region(__wrapped, index, &offset) + let subdata = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, index, &offset) var ptr: UnsafePointer? = nil var size = 0 @@ -197,13 +201,13 @@ public struct DispatchData : RandomAccessCollection { /// - parameter range: The range to copy. public func subdata(in range: CountableRange) -> DispatchData { let subrange = CDispatch.dispatch_data_create_subrange( - __wrapped, range.startIndex, range.endIndex - range.startIndex) + __wrapped.__wrapped, range.startIndex, range.endIndex - range.startIndex) return DispatchData(data: subrange) } public func region(location: Int) -> (data: DispatchData, offset: Int) { var offset: Int = 0 - let data = CDispatch.dispatch_data_copy_region(__wrapped, location, &offset) + let data = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, location, &offset) return (DispatchData(data: data), offset) } @@ -237,7 +241,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { public init(_data: DispatchData) { var ptr: UnsafePointer? self._count = 0 - self._data = CDispatch.dispatch_data_create_map(_data.__wrapped, &ptr, &self._count) + self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count)) self._ptr = UnsafePointer(ptr) self._position = _data.startIndex @@ -254,7 +258,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { return element } - internal let _data: dispatch_data_t + internal let _data: __DispatchData internal var _ptr: UnsafePointer! internal var _count: Int internal var _position: DispatchData.Index diff --git a/src/swift/IO.swift b/src/swift/IO.swift index 6e6b6692e..1b8d7b006 100644 --- a/src/swift/IO.swift +++ b/src/swift/IO.swift @@ -41,7 +41,7 @@ public extension DispatchIO { } public class func write(fromFileDescriptor: Int32, data: DispatchData, runningHandlerOn queue: DispatchQueue, handler: (data: DispatchData?, error: Int32) -> Void) { - dispatch_write(fromFileDescriptor, data.__wrapped, queue.__wrapped) { (data: dispatch_data_t?, error: Int32) in + dispatch_write(fromFileDescriptor, data.__wrapped.__wrapped, queue.__wrapped) { (data: dispatch_data_t?, error: Int32) in handler(data: data.flatMap { DispatchData(data: $0) }, error: error) } } @@ -82,7 +82,7 @@ public extension DispatchIO { } public func write(offset: off_t, data: DispatchData, queue: DispatchQueue, ioHandler: (done: Bool, data: DispatchData?, error: Int32) -> Void) { - dispatch_io_write(self.__wrapped, offset, data.__wrapped, queue.__wrapped) { (done: Bool, data: dispatch_data_t?, error: Int32) in + dispatch_io_write(self.__wrapped, offset, data.__wrapped.__wrapped, queue.__wrapped) { (done: Bool, data: dispatch_data_t?, error: Int32) in ioHandler(done: done, data: data.flatMap { DispatchData(data: $0) }, error: error) } } diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index d38bb9358..c7ffa0c02 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -186,6 +186,22 @@ extension DispatchSource : DispatchSourceProcess, } #endif +internal class __DispatchData : DispatchObject { + internal let __wrapped:dispatch_data_t + + final internal override func wrapped() -> dispatch_object_t { + return unsafeBitCast(__wrapped, to: dispatch_object_t.self) + } + + internal init(data:dispatch_data_t) { + __wrapped = data + } + + deinit { + _swift_dispatch_release(wrapped()) + } +} + public typealias DispatchSourceHandler = @convention(block) () -> Void public protocol DispatchSourceType { @@ -307,9 +323,9 @@ internal enum _OSQoSClass : UInt32 { case 0x21: self = .QOS_CLASS_USER_INTERACTIVE case 0x19: self = .QOS_CLASS_USER_INITIATED case 0x15: self = .QOS_CLASS_DEFAULT - case 0x11: self = QOS_CLASS_UTILITY - case 0x09: self = QOS_CLASS_BACKGROUND - case 0x00: self = QOS_CLASS_UNSPECIFIED + case 0x11: self = .QOS_CLASS_UTILITY + case 0x09: self = .QOS_CLASS_BACKGROUND + case 0x00: self = .QOS_CLASS_UNSPECIFIED default: return nil } } From b31c4647e19d29ae9390c1e57336d5712bcddbdd Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Thu, 21 Jul 2016 07:25:13 -0700 Subject: [PATCH 51/67] Merge pull request #108 from dgrove-oss/data-destructor deallocation support for DispatchData on Linux Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 2118aa253..e299a55cf 100644 --- a/PATCHES +++ b/PATCHES @@ -260,3 +260,4 @@ github commits starting with 29bdc2f from [325f73d] APPLIED rdar://27600964 [b84e87e] APPLIED rdar://27600964 [ae71a91] APPLIED rdar://27600964 +[8669dea] APPLIED rdar://27600964 From 5c303da359703ce237c62cdcbfa0b0ec8135603c Mon Sep 17 00:00:00 2001 From: David Grove Date: Mon, 11 Jul 2016 13:19:09 -0400 Subject: [PATCH 52/67] add dispatchMain to wrapping overlay dispatch_main is meant to be made available via the global function dispatchMain(). Signed-off-by: Daniel A. Steffen --- src/swift/Wrapper.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index c7ffa0c02..8f841f13d 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -15,6 +15,10 @@ import CDispatch // This file contains declarations that are provided by the // importer via Dispatch.apinote when the platform has Objective-C support +@noreturn public func dispatchMain() { + CDispatch.dispatch_main() +} + public class DispatchObject { internal func wrapped() -> dispatch_object_t { From 89c4fe1d93603232a83b435e252df79652855ef5 Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Thu, 21 Jul 2016 07:26:55 -0700 Subject: [PATCH 53/67] Merge pull request #102 from dgrove-oss/missing-dispatchMain add dispatchMain to wrapping overlay Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index e299a55cf..8386f617d 100644 --- a/PATCHES +++ b/PATCHES @@ -261,3 +261,4 @@ github commits starting with 29bdc2f from [b84e87e] APPLIED rdar://27600964 [ae71a91] APPLIED rdar://27600964 [8669dea] APPLIED rdar://27600964 +[a8d0327] APPLIED rdar://27600964 From 12bdffa3235244e2f353603d92939a4c703cde76 Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 21 Jul 2016 08:34:32 -0400 Subject: [PATCH 54/67] fix compilation error when building against old libkqueue Should have used an ifdef instead of an if to guard this block of code. Fixes compilation on linux when using an older version of libkqueue that doesn't include the nsec kevent support. Signed-off-by: Daniel A. Steffen --- src/source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source.c b/src/source.c index 0693a712a..afb811c40 100644 --- a/src/source.c +++ b/src/source.c @@ -2339,7 +2339,7 @@ _dispatch_kevent_timer_set_delay(_dispatch_kevent_qos_s *ke, uint64_t delay, { // call to update nows[] _dispatch_source_timer_now(nows, DISPATCH_TIMER_KIND_WALL); -#if KEVENT_NSEC_NOT_SUPPORTED +#ifdef KEVENT_NSEC_NOT_SUPPORTED // adjust nsec based delay to msec based and ignore leeway delay /= 1000000L; if ((int64_t)(delay) <= 0) { From 6a376810b0447014d498bf1be8113e953ecc0f0e Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Thu, 21 Jul 2016 10:53:23 -0700 Subject: [PATCH 55/67] Merge pull request #114 from dgrove-oss/kevent-nsec-tweak fix compilation error when building against old libkqueue Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 8386f617d..526c0671a 100644 --- a/PATCHES +++ b/PATCHES @@ -262,3 +262,4 @@ github commits starting with 29bdc2f from [ae71a91] APPLIED rdar://27600964 [8669dea] APPLIED rdar://27600964 [a8d0327] APPLIED rdar://27600964 +[2e4e6af] APPLIED rdar://27600964 From 3776c2e070a4120847b644d6bdbc05e4ed468c95 Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 21 Jul 2016 11:25:19 -0400 Subject: [PATCH 56/67] refresh libpwq submodule to include libpwq PR#14 Update libpwq version to latest. This picks up the code in libpwq PR#14 which changes the default number of libpwq worker threads from 2 to the number of cores in the system. This avoids very slow initial rampups in high core count systems. Signed-off-by: Daniel A. Steffen --- libpwq | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpwq b/libpwq index 9faa79ae3..616417f93 160000 --- a/libpwq +++ b/libpwq @@ -1 +1 @@ -Subproject commit 9faa79ae3ee90cdbe217c3dedb2ad6fc50267f7f +Subproject commit 616417f934686c14300e34b9835df624d8693d5a From 6c617c251cb3d8b6667710881d2141451bc5a261 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 21 Jul 2016 12:09:31 -0700 Subject: [PATCH 57/67] Merge pull request #115 from dgrove-oss/refresh-libpwq refresh libpwq submodule to include libpwq PR#14 Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 526c0671a..91992a926 100644 --- a/PATCHES +++ b/PATCHES @@ -263,3 +263,4 @@ github commits starting with 29bdc2f from [8669dea] APPLIED rdar://27600964 [a8d0327] APPLIED rdar://27600964 [2e4e6af] APPLIED rdar://27600964 +[2457fb2] APPLIED rdar://27600964 From e6f5827be7cbdd5e190d96e2f46787c260b7c432 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Mon, 25 Jul 2016 18:01:40 -0700 Subject: [PATCH 58/67] Update for SE-0107: Migrate Void->Raw. Unsafe[Mutable]Pointer is replaced by Unsafe[Mutable]RawPointer. Migrating often means simply removing casts to/from UnsafePointer and working directly with UnsafeRawPointer instead. Unfortunately some API's, like NSData still want UnsafePointer, which requires "binding" memory to UInt8 before passing it to the API. Signed-off-by: Daniel A. Steffen --- src/swift/Data.swift | 12 ++++++------ src/swift/Private.swift | 12 ++++++------ src/swift/Queue.swift | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index 9d68ad3ad..b8271f63e 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -76,7 +76,7 @@ public struct DispatchData : RandomAccessCollection { public func withUnsafeBytes( body: @noescape (UnsafePointer) throws -> Result) rethrows -> Result { - var ptr: UnsafePointer? = nil + var ptr: UnsafeRawPointer? = nil var size = 0; let data = CDispatch.dispatch_data_create_map(__wrapped.__wrapped, &ptr, &size) defer { _fixLifetime(data) } @@ -86,7 +86,7 @@ public struct DispatchData : RandomAccessCollection { public func enumerateBytes( block: @noescape (buffer: UnsafeBufferPointer, byteIndex: Int, stop: inout Bool) -> Void) { - _swift_dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in + _swift_dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafeRawPointer, size: Int) in let bp = UnsafeBufferPointer(start: UnsafePointer(ptr), count: size) var stop = false block(buffer: bp, byteIndex: offset, stop: &stop) @@ -120,7 +120,7 @@ public struct DispatchData : RandomAccessCollection { private func _copyBytesHelper(to pointer: UnsafeMutablePointer, from range: CountableRange) { var copiedCount = 0 - _ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer, size: Int) in + _ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafeRawPointer, size: Int) in let limit = Swift.min((range.endIndex - range.startIndex) - copiedCount, size) memcpy(pointer + copiedCount, ptr, limit) copiedCount += limit @@ -183,7 +183,7 @@ public struct DispatchData : RandomAccessCollection { var offset = 0 let subdata = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, index, &offset) - var ptr: UnsafePointer? = nil + var ptr: UnsafeRawPointer? = nil var size = 0 let map = CDispatch.dispatch_data_create_map(subdata, &ptr, &size) defer { _fixLifetime(map) } @@ -239,7 +239,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { /// Create an iterator over the given DisaptchData public init(_data: DispatchData) { - var ptr: UnsafePointer? + var ptr: UnsafeRawPointer? self._count = 0 self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count)) self._ptr = UnsafePointer(ptr) @@ -264,7 +264,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { internal var _position: DispatchData.Index } -typealias _swift_data_applier = @convention(block) @noescape (dispatch_data_t, Int, UnsafePointer, Int) -> Bool +typealias _swift_data_applier = @convention(block) @noescape (dispatch_data_t, Int, UnsafeRawPointer, Int) -> Bool @_silgen_name("_swift_dispatch_data_apply") internal func _swift_dispatch_data_apply(_ data: dispatch_data_t, _ block: _swift_data_applier) diff --git a/src/swift/Private.swift b/src/swift/Private.swift index e38f72861..0d177d0ae 100644 --- a/src/swift/Private.swift +++ b/src/swift/Private.swift @@ -69,7 +69,7 @@ func dispatch_write(_ fd: Int32, _ data: dispatch_data_t, _ queue: DispatchQueue } @available(*, unavailable, renamed:"DispatchData.init(bytes:)") -public func dispatch_data_create(_ buffer: UnsafePointer, _ size: Int, _ queue: DispatchQueue?, _ destructor: (() -> Void)?) -> dispatch_data_t +public func dispatch_data_create(_ buffer: UnsafeRawPointer, _ size: Int, _ queue: DispatchQueue?, _ destructor: (() -> Void)?) -> dispatch_data_t { fatalError() } @@ -81,7 +81,7 @@ public func dispatch_data_get_size(_ data: dispatch_data_t) -> Int } @available(*, unavailable, renamed:"DispatchData.withUnsafeBytes(self:body:)") -public func dispatch_data_create_map(_ data: dispatch_data_t, _ buffer_ptr: UnsafeMutablePointer?>?, _ size_ptr: UnsafeMutablePointer?) -> dispatch_data_t +public func dispatch_data_create_map(_ data: dispatch_data_t, _ buffer_ptr: UnsafeMutablePointer?, _ size_ptr: UnsafeMutablePointer?) -> dispatch_data_t { fatalError() } @@ -99,7 +99,7 @@ public func dispatch_data_create_subrange(_ data: dispatch_data_t, _ offset: Int } @available(*, unavailable, renamed:"DispatchData.enumerateBytes(self:block:)") -public func dispatch_data_apply(_ data: dispatch_data_t, _ applier: (dispatch_data_t, Int, UnsafePointer, Int) -> Bool) -> Bool +public func dispatch_data_apply(_ data: dispatch_data_t, _ applier: (dispatch_data_t, Int, UnsafeRawPointer, Int) -> Bool) -> Bool { fatalError() } @@ -213,19 +213,19 @@ public func dispatch_barrier_sync(_ queue: DispatchQueue, _ block: @noescape () } @available(*, unavailable, renamed:"DispatchQueue.setSpecific(self:key:value:)") -public func dispatch_queue_set_specific(_ queue: DispatchQueue, _ key: UnsafePointer, _ context: UnsafeMutablePointer?, _ destructor: (@convention(c) (UnsafeMutablePointer?) -> Void)?) +public func dispatch_queue_set_specific(_ queue: DispatchQueue, _ key: UnsafeRawPointer, _ context: UnsafeMutableRawPointer?, _ destructor: (@convention(c) (UnsafeMutableRawPointer?) -> Void)?) { fatalError() } @available(*, unavailable, renamed:"DispatchQueue.getSpecific(self:key:)") -public func dispatch_queue_get_specific(_ queue: DispatchQueue, _ key: UnsafePointer) -> UnsafeMutablePointer? +public func dispatch_queue_get_specific(_ queue: DispatchQueue, _ key: UnsafeRawPointer) -> UnsafeMutableRawPointer? { fatalError() } @available(*, unavailable, renamed:"DispatchQueue.getSpecific(key:)") -public func dispatch_get_specific(_ key: UnsafePointer) -> UnsafeMutablePointer? +public func dispatch_get_specific(_ key: UnsafeRawPointer) -> UnsafeMutableRawPointer? { fatalError() } diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 5a45fdcd1..5650362a0 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -402,7 +402,7 @@ extension DispatchQueue { } } -private func _destructDispatchSpecificValue(ptr: UnsafeMutablePointer?) { +private func _destructDispatchSpecificValue(ptr: UnsafeMutableRawPointer?) { if let p = ptr { Unmanaged.fromOpaque(p).release() } From 0939cb096d3c9d426d59c805d5080ea19809ae16 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Tue, 26 Jul 2016 02:18:25 -0700 Subject: [PATCH 59/67] Merge pull request #120 from atrick/rawptr-void Update for SE-0107: Migrate Void->Raw. Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 91992a926..7a943ad04 100644 --- a/PATCHES +++ b/PATCHES @@ -264,3 +264,4 @@ github commits starting with 29bdc2f from [a8d0327] APPLIED rdar://27600964 [2e4e6af] APPLIED rdar://27600964 [2457fb2] APPLIED rdar://27600964 +[4d58038] APPLIED rdar://27600964 From 632ade41ae801fe9306ee56ea3c30680d55f438c Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Thu, 21 Jul 2016 10:37:27 -0700 Subject: [PATCH 60/67] [overlay-syncup] sync overlay changes to Linux Sync up recent Swift overlay changes into swift-corelibs-dispatch and get them building for Linux. Signed-off-by: Daniel A. Steffen --- src/swift/Block.swift | 35 ++-- src/swift/Dispatch.swift | 48 ++---- src/swift/IO.swift | 36 +--- src/swift/Queue.swift | 363 ++++++++++++++++++--------------------- src/swift/Source.swift | 72 ++------ src/swift/Time.swift | 42 ++++- src/swift/Wrapper.swift | 46 +++-- 7 files changed, 270 insertions(+), 372 deletions(-) diff --git a/src/swift/Block.swift b/src/swift/Block.swift index c1266cea1..130eb4e0a 100644 --- a/src/swift/Block.swift +++ b/src/swift/Block.swift @@ -39,7 +39,14 @@ public class DispatchWorkItem { internal var _block: _DispatchBlock internal var _group: DispatchGroup? - public init(group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], block: @convention(block) () -> ()) { + // Temporary for swift-corelibs-foundation + @available(*, deprecated, renamed: "DispatchWorkItem(qos:flags:block:)") + public convenience init(group: DispatchGroup, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], block: @convention(block) () -> ()) { + self.init(qos: qos, flags: flags, block: block) + + } + + public init(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], block: @convention(block) () -> ()) { _block = dispatch_block_create_with_qos_class(dispatch_block_flags_t(flags.rawValue), qos.qosClass.rawValue.rawValue, Int32(qos.relativePriority), block) } @@ -51,10 +58,6 @@ public class DispatchWorkItem { } public func perform() { - if let g = _group { - g.enter() - defer { g.leave() } - } _block() } @@ -63,14 +66,19 @@ public class DispatchWorkItem { } public func wait(timeout: DispatchTime) -> DispatchTimeoutResult { - return dispatch_block_wait(_block, timeout.rawValue) == 0 ? .Success : .TimedOut + return dispatch_block_wait(_block, timeout.rawValue) == 0 ? .success : .timedOut } public func wait(wallTimeout: DispatchWallTime) -> DispatchTimeoutResult { - return dispatch_block_wait(_block, wallTimeout.rawValue) == 0 ? .Success : .TimedOut + return dispatch_block_wait(_block, wallTimeout.rawValue) == 0 ? .success : .timedOut } - public func notify(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], queue: DispatchQueue, execute: @convention(block) () -> Void) { + public func notify( + qos: DispatchQoS = .unspecified, + flags: DispatchWorkItemFlags = [], + queue: DispatchQueue, + execute: @convention(block) () -> Void) + { if qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: execute) dispatch_block_notify(_block, queue.__wrapped, item._block) @@ -92,17 +100,6 @@ public class DispatchWorkItem { } } -@available(OSX 10.10, iOS 8.0, *) -public extension DispatchWorkItem { - @available(*, deprecated, renamed: "DispatchWorkItem.wait(self:wallTimeout:)") - public func wait(timeout: DispatchWallTime) -> Int { - switch wait(wallTimeout: timeout) { - case .Success: return 0 - case .TimedOut: return DispatchTimeoutResult.KERN_OPERATION_TIMED_OUT - } - } -} - /// The dispatch_block_t typealias is different from usual closures in that it /// uses @convention(block). This is to avoid unnecessary bridging between /// C blocks and Swift closures, which interferes with dispatch APIs that depend diff --git a/src/swift/Dispatch.swift b/src/swift/Dispatch.swift index 2b9cb2164..ac9aa5f22 100644 --- a/src/swift/Dispatch.swift +++ b/src/swift/Dispatch.swift @@ -59,11 +59,6 @@ public struct DispatchQoS : Equatable { @available(OSX 10.10, iOS 8.0, *) public static let `default` = DispatchQoS(qosClass: .default, relativePriority: 0) - @available(OSX, introduced: 10.10, deprecated: 10.10, renamed: "DispatchQoS.default") - @available(iOS, introduced: 8.0, deprecated: 8.0, renamed: "DispatchQoS.default") - @available(*, deprecated, renamed: "DispatchQoS.default") - public static let defaultQoS = DispatchQoS.default - @available(OSX 10.10, iOS 8.0, *) public static let userInitiated = DispatchQoS(qosClass: .userInitiated, relativePriority: 0) @@ -82,11 +77,6 @@ public struct DispatchQoS : Equatable { @available(OSX 10.10, iOS 8.0, *) case `default` - @available(OSX, introduced: 10.10, deprecated: 10.10, renamed: "QoSClass.default") - @available(iOS, introduced: 8.0, deprecated: 8.0, renamed: "QoSClass.default") - @available(*, deprecated, renamed: "QoSClass.default") - static let defaultQoS = QoSClass.default - @available(OSX 10.10, iOS 8.0, *) case userInitiated @@ -95,9 +85,11 @@ public struct DispatchQoS : Equatable { case unspecified + // _OSQoSClass is internal on Linux, so this initialiser has to + // remain as an internal init. @available(OSX 10.10, iOS 8.0, *) - internal init?(qosClass: _OSQoSClass) { - switch qosClass { + internal init?(rawValue: _OSQoSClass) { + switch rawValue { case .QOS_CLASS_BACKGROUND: self = .background case .QOS_CLASS_UTILITY: self = .utility case .QOS_CLASS_DEFAULT: self = .default @@ -135,8 +127,8 @@ public func ==(a: DispatchQoS, b: DispatchQoS) -> Bool { public enum DispatchTimeoutResult { static let KERN_OPERATION_TIMED_OUT:Int = 49 - case Success - case TimedOut + case success + case timedOut } /// dispatch_group @@ -161,21 +153,11 @@ public extension DispatchGroup { } public func wait(timeout: DispatchTime) -> DispatchTimeoutResult { - return dispatch_group_wait(self.__wrapped, timeout.rawValue) == 0 ? .Success : .TimedOut + return dispatch_group_wait(self.__wrapped, timeout.rawValue) == 0 ? .success : .timedOut } public func wait(wallTimeout timeout: DispatchWallTime) -> DispatchTimeoutResult { - return dispatch_group_wait(self.__wrapped, timeout.rawValue) == 0 ? .Success : .TimedOut - } -} - -public extension DispatchGroup { - @available(*, deprecated, renamed: "DispatchGroup.wait(self:wallTimeout:)") - public func wait(walltime timeout: DispatchWallTime) -> Int { - switch wait(wallTimeout: timeout) { - case .Success: return 0 - case .TimedOut: return DispatchTimeoutResult.KERN_OPERATION_TIMED_OUT - } + return dispatch_group_wait(self.__wrapped, timeout.rawValue) == 0 ? .success : .timedOut } } @@ -192,20 +174,10 @@ public extension DispatchSemaphore { } public func wait(timeout: DispatchTime) -> DispatchTimeoutResult { - return dispatch_semaphore_wait(self.__wrapped, timeout.rawValue) == 0 ? .Success : .TimedOut + return dispatch_semaphore_wait(self.__wrapped, timeout.rawValue) == 0 ? .success : .timedOut } public func wait(wallTimeout: DispatchWallTime) -> DispatchTimeoutResult { - return dispatch_semaphore_wait(self.__wrapped, wallTimeout.rawValue) == 0 ? .Success : .TimedOut - } -} - -public extension DispatchSemaphore { - @available(*, deprecated, renamed: "DispatchSemaphore.wait(self:wallTimeout:)") - public func wait(walltime timeout: DispatchWalltime) -> Int { - switch wait(wallTimeout: timeout) { - case .Success: return 0 - case .TimedOut: return DispatchTimeoutResult.KERN_OPERATION_TIMED_OUT - } + return dispatch_semaphore_wait(self.__wrapped, wallTimeout.rawValue) == 0 ? .success : .timedOut } } diff --git a/src/swift/IO.swift b/src/swift/IO.swift index 1b8d7b006..02805e633 100644 --- a/src/swift/IO.swift +++ b/src/swift/IO.swift @@ -40,8 +40,8 @@ public extension DispatchIO { } } - public class func write(fromFileDescriptor: Int32, data: DispatchData, runningHandlerOn queue: DispatchQueue, handler: (data: DispatchData?, error: Int32) -> Void) { - dispatch_write(fromFileDescriptor, data.__wrapped.__wrapped, queue.__wrapped) { (data: dispatch_data_t?, error: Int32) in + public class func write(toFileDescriptor: Int32, data: DispatchData, runningHandlerOn queue: DispatchQueue, handler: (data: DispatchData?, error: Int32) -> Void) { + dispatch_write(toFileDescriptor, data.__wrapped.__wrapped, queue.__wrapped) { (data: dispatch_data_t?, error: Int32) in handler(data: data.flatMap { DispatchData(data: $0) }, error: error) } } @@ -95,35 +95,3 @@ public extension DispatchIO { dispatch_io_close(self.__wrapped, flags.rawValue) } } - -extension DispatchIO { - @available(*, deprecated, renamed: "DispatchIO.read(fromFileDescriptor:maxLength:runningHandlerOn:handler:)") - public class func read(fd: Int32, length: Int, queue: DispatchQueue, handler: (DispatchData, Int32) -> Void) { - DispatchIO.read(fromFileDescriptor: fd, maxLength: length, runningHandlerOn: queue, handler: handler) - } - - @available(*, deprecated, renamed: "DispatchIO.write(fromFileDescriptor:data:runningHandlerOn:handler:)") - public class func write(fd: Int32, data: DispatchData, queue: DispatchQueue, handler: (DispatchData?, Int32) -> Void) { - DispatchIO.write(fromFileDescriptor: fd, data: data, runningHandlerOn: queue, handler: handler) - } - - @available(*, deprecated, renamed: "DispatchIO.barrier(self:execute:)") - public func withBarrier(barrier work: () -> ()) { - barrier(execute: work) - } - - @available(*, deprecated, renamed: "DispatchIO.setLimit(self:highWater:)") - public func setHighWater(highWater: Int) { - setLimit(highWater: highWater) - } - - @available(*, deprecated, renamed: "DispatchIO.setLimit(self:lowWater:)") - public func setLowWater(lowWater: Int) { - setLimit(lowWater: lowWater) - } - - @available(*, deprecated, renamed: "DispatchIO.setInterval(self:interval:flags:)") - public func setInterval(interval: UInt64, flags: IntervalFlags) { - setInterval(interval: .nanoseconds(Int(interval)), flags: flags) - } -} diff --git a/src/swift/Queue.swift b/src/swift/Queue.swift index 5650362a0..677d0f50c 100644 --- a/src/swift/Queue.swift +++ b/src/swift/Queue.swift @@ -14,82 +14,6 @@ import CDispatch -public struct DispatchQueueAttributes : OptionSet { - public let rawValue: UInt64 - public init(rawValue: UInt64) { self.rawValue = rawValue } - - public static let serial = DispatchQueueAttributes(rawValue: 0<<0) - public static let concurrent = DispatchQueueAttributes(rawValue: 1<<1) - - @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) - public static let initiallyInactive = DispatchQueueAttributes(rawValue: 1<<2) - - @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) - public static let autoreleaseInherit = DispatchQueueAttributes(rawValue: 1<<3) - - @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) - public static let autoreleaseWorkItem = DispatchQueueAttributes(rawValue: 1<<4) - - @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) - public static let autoreleaseNever = DispatchQueueAttributes(rawValue: 1<<5) - - @available(OSX 10.10, iOS 8.0, *) - public static let qosUserInteractive = DispatchQueueAttributes(rawValue: 1<<6) - - @available(OSX 10.10, iOS 8.0, *) - public static let qosUserInitiated = DispatchQueueAttributes(rawValue: 1<<7) - - @available(OSX 10.10, iOS 8.0, *) - public static let qosDefault = DispatchQueueAttributes(rawValue: 1<<8) - - @available(OSX 10.10, iOS 8.0, *) - public static let qosUtility = DispatchQueueAttributes(rawValue: 1<<9) - - @available(OSX 10.10, iOS 8.0, *) - public static let qosBackground = DispatchQueueAttributes(rawValue: 1<<10) - - @available(*, deprecated, message: ".noQoS has no effect, it should not be used") - public static let noQoS = DispatchQueueAttributes(rawValue: 1<<11) - - private var attr: dispatch_queue_attr_t? { - var attr: dispatch_queue_attr_t? - - if self.contains(.concurrent) { - attr = _swift_dispatch_queue_concurrent() - } - if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) { - if self.contains(.initiallyInactive) { - attr = CDispatch.dispatch_queue_attr_make_initially_inactive(attr) - } - if self.contains(.autoreleaseWorkItem) { - // DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM - attr = CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(1)) - } else if self.contains(.autoreleaseInherit) { - // DISPATCH_AUTORELEASE_FREQUENCY_INHERIT - attr = CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(0)) - } else if self.contains(.autoreleaseNever) { - // DISPATCH_AUTORELEASE_FREQUENCY_NEVER - attr = CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(2)) - } - } - if #available(OSX 10.10, iOS 8.0, *) { - if self.contains(.qosUserInteractive) { - attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_USER_INTERACTIVE.rawValue, 0) - } else if self.contains(.qosUserInitiated) { - attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_USER_INITIATED.rawValue, 0) - } else if self.contains(.qosDefault) { - attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_DEFAULT.rawValue, 0) - } else if self.contains(.qosUtility) { - attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_UTILITY.rawValue, 0) - } else if self.contains(.qosBackground) { - attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, _OSQoSClass.QOS_CLASS_BACKGROUND.rawValue, 0) - } - } - return attr - } -} - - public final class DispatchSpecificKey { public init() {} } @@ -99,63 +23,110 @@ internal class _DispatchSpecificValue { internal init(value: T) { self.value = value } } -public extension DispatchQueue { +// Temporary for swift-corelibs-foundation +@available(*, deprecated, renamed: "DispatchQueue.Attributes") +public struct DispatchQueueAttributes : OptionSet { + public let rawValue: UInt64 + public init(rawValue: UInt64) { self.rawValue = rawValue } - public struct GlobalAttributes : OptionSet { - public let rawValue: UInt64 - public init(rawValue: UInt64) { self.rawValue = rawValue } + public static let serial = DispatchQueueAttributes(rawValue: 1<<0) + public static let concurrent = DispatchQueueAttributes(rawValue: 1<<1) - @available(OSX 10.10, iOS 8.0, *) - public static let qosUserInteractive = GlobalAttributes(rawValue: 1<<0) + private var _translatedValue: DispatchQueue.Attributes { + if self.contains(.concurrent) { return .concurrent } + return [] + } +} - @available(OSX 10.10, iOS 8.0, *) - public static let qosUserInitiated = GlobalAttributes(rawValue: 1<<1) +public extension DispatchQueue { + public struct Attributes : OptionSet { + public let rawValue: UInt64 + public init(rawValue: UInt64) { self.rawValue = rawValue } - @available(OSX 10.10, iOS 8.0, *) - public static let qosDefault = GlobalAttributes(rawValue: 1<<2) + public static let concurrent = Attributes(rawValue: 1<<1) - @available(OSX 10.10, iOS 8.0, *) - public static let qosUtility = GlobalAttributes(rawValue: 1<<3) + @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) + public static let initiallyInactive = Attributes(rawValue: 1<<2) - @available(OSX 10.10, iOS 8.0, *) - public static let qosBackground = GlobalAttributes(rawValue: 1<<4) + private func _attr() -> dispatch_queue_attr_t? { + var attr: dispatch_queue_attr_t? = nil - // Avoid using our own deprecated constants here by declaring - // non-deprecated constants and then basing the public ones on those. - internal static let _priorityHigh = GlobalAttributes(rawValue: 1<<5) - internal static let _priorityDefault = GlobalAttributes(rawValue: 1<<6) - internal static let _priorityLow = GlobalAttributes(rawValue: 1<<7) - internal static let _priorityBackground = GlobalAttributes(rawValue: 1<<8) + if self.contains(.concurrent) { + attr = _swift_dispatch_queue_concurrent() + } + if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) { + if self.contains(.initiallyInactive) { + attr = CDispatch.dispatch_queue_attr_make_initially_inactive(attr) + } + } + return attr + } + } + public enum GlobalQueuePriority { @available(OSX, deprecated: 10.10, message: "Use qos attributes instead") @available(*, deprecated: 8.0, message: "Use qos attributes instead") - public static let priorityHigh = _priorityHigh + case high @available(OSX, deprecated: 10.10, message: "Use qos attributes instead") @available(*, deprecated: 8.0, message: "Use qos attributes instead") - public static let priorityDefault = _priorityDefault + case `default` @available(OSX, deprecated: 10.10, message: "Use qos attributes instead") @available(*, deprecated: 8.0, message: "Use qos attributes instead") - public static let priorityLow = _priorityLow + case low @available(OSX, deprecated: 10.10, message: "Use qos attributes instead") @available(*, deprecated: 8.0, message: "Use qos attributes instead") - public static let priorityBackground = _priorityBackground + case background internal var _translatedValue: Int { - if #available(OSX 10.10, iOS 8.0, *) { - if self.contains(.qosUserInteractive) { return Int(_OSQoSClass.QOS_CLASS_USER_INTERACTIVE.rawValue) } - else if self.contains(.qosUserInitiated) { return Int(_OSQoSClass.QOS_CLASS_USER_INITIATED.rawValue) } - else if self.contains(.qosDefault) { return Int(_OSQoSClass.QOS_CLASS_DEFAULT.rawValue) } - else if self.contains(.qosUtility) { return Int(_OSQoSClass.QOS_CLASS_UTILITY.rawValue) } - else { return Int(_OSQoSClass.QOS_CLASS_BACKGROUND.rawValue) } + switch self { + case .high: return 2 // DISPATCH_QUEUE_PRIORITY_HIGH + case .default: return 0 // DISPATCH_QUEUE_PRIORITY_DEFAULT + case .low: return -2 // DISPATCH_QUEUE_PRIORITY_LOW + case .background: return Int(Int16.min) // DISPATCH_QUEUE_PRIORITY_BACKGROUND + } + } + } + + // Temporary for swift-corelibs-foundation + @available(*, deprecated, renamed: "DispatchQoS") + public enum GlobalQueueDeprecatedPriority { + case qosBackground + + private var _translatedValue: DispatchQoS.QoSClass { + switch self { + case .qosBackground: return .background + } + } + } + + public enum AutoreleaseFrequency { + case inherit + + @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) + case workItem + + @available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) + case never + + internal func _attr(attr: dispatch_queue_attr_t?) -> dispatch_queue_attr_t? { + if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) { + switch self { + case .inherit: + // DISPATCH_AUTORELEASE_FREQUENCY_INHERIT + return CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(0)) + case .workItem: + // DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM + return CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(1)) + case .never: + // DISPATCH_AUTORELEASE_FREQUENCY_NEVER + return CDispatch.dispatch_queue_attr_make_with_autorelease_frequency(attr, dispatch_autorelease_frequency_t(2)) + } + } else { + return attr } - if self.contains(._priorityHigh) { return 2 } // DISPATCH_QUEUE_PRIORITY_HIGH - else if self.contains(._priorityDefault) { return 0 } // DISPATCH_QUEUE_PRIORITY_DEFAULT - else if self.contains(._priorityLow) { return -2 } // // DISPATCH_QUEUE_PRIORITY_LOW - else if self.contains(._priorityBackground) { return Int(Int16.min) } // // DISPATCH_QUEUE_PRIORITY_BACKGROUND - return 0 } } @@ -167,9 +138,21 @@ public extension DispatchQueue { return DispatchQueue(queue: _swift_dispatch_get_main_queue()) } - public class func global(attributes: GlobalAttributes = []) -> DispatchQueue { - // SubOptimal? Should we be caching these global DispatchQueue objects? - return DispatchQueue(queue:dispatch_get_global_queue(attributes._translatedValue, 0)) + @available(OSX, deprecated: 10.10, message: "") + @available(*, deprecated: 8.0, message: "") + public class func global(priority: GlobalQueuePriority) -> DispatchQueue { + return DispatchQueue(queue: CDispatch.dispatch_get_global_queue(priority._translatedValue, 0)) + } + + // Temporary for swift-corelibs-foundation + @available(*, deprecated, renamed: "DispatchQueue.global(qos:)") + public class func global(attributes: GlobalQueueDeprecatedPriority) -> DispatchQueue { + return global(qos: attributes._translatedValue) + } + + @available(OSX 10.10, iOS 8.0, *) + public class func global(qos: DispatchQoS.QoSClass = .default) -> DispatchQueue { + return DispatchQueue(queue: CDispatch.dispatch_get_global_queue(Int(qos.rawValue.rawValue), 0)) } public class func getSpecific(key: DispatchSpecificKey) -> T? { @@ -183,15 +166,34 @@ public extension DispatchQueue { return nil } + // Temporary for swift-corelibs-foundation + @available(*, deprecated, renamed: "DispatchQueue(label:attributes:)") + public convenience init( + label: String, + attributes: DispatchQueueAttributes) + { + self.init(label: label, attributes: attributes._translatedValue) + } + public convenience init( label: String, - attributes: DispatchQueueAttributes = .serial, + qos: DispatchQoS = .unspecified, + attributes: Attributes = [], + autoreleaseFrequency: AutoreleaseFrequency = .inherit, target: DispatchQueue? = nil) { + var attr = attributes._attr() + if autoreleaseFrequency != .inherit { + attr = autoreleaseFrequency._attr(attr: attr) + } + if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified { + attr = CDispatch.dispatch_queue_attr_make_with_qos_class(attr, qos.qosClass.rawValue.rawValue, Int32(qos.relativePriority)) + } + if #available(OSX 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) { - self.init(__label: label, attr: attributes.attr, queue: target) + self.init(__label: label, attr: attr, queue: target) } else { - self.init(__label: label, attr: attributes.attr) + self.init(__label: label, attr: attr) if let tq = target { self.setTarget(queue: tq) } } } @@ -202,45 +204,46 @@ public extension DispatchQueue { @available(OSX 10.10, iOS 8.0, *) public func sync(execute workItem: DispatchWorkItem) { - dispatch_sync(self.__wrapped, workItem._block) + CDispatch.dispatch_sync(self.__wrapped, workItem._block) } @available(OSX 10.10, iOS 8.0, *) public func async(execute workItem: DispatchWorkItem) { - // _swift_dispatch_{group,}_async preserves the @convention(block) - // for work item blocks. - if let g = workItem._group { - dispatch_group_async(g.__wrapped, self.__wrapped, workItem._block) - } else { - dispatch_async(self.__wrapped, workItem._block) - } + CDispatch.dispatch_async(self.__wrapped, workItem._block) } - public func async(group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { + @available(OSX 10.10, iOS 8.0, *) + public func async(group: DispatchGroup, execute workItem: DispatchWorkItem) { + CDispatch.dispatch_group_async(group.__wrapped, self.__wrapped, workItem._block) + } + + public func async( + group: DispatchGroup? = nil, + qos: DispatchQoS = .unspecified, + flags: DispatchWorkItemFlags = [], + execute work: @convention(block) () -> Void) + { if group == nil && qos == .unspecified && flags.isEmpty { // Fast-path route for the most common API usage - dispatch_async(self.__wrapped, work) + CDispatch.dispatch_async(self.__wrapped, work) return } + var block: @convention(block) () -> Void = work if #available(OSX 10.10, iOS 8.0, *), (qos != .unspecified || !flags.isEmpty) { let workItem = DispatchWorkItem(qos: qos, flags: flags, block: work) - if let g = group { - dispatch_group_async(g.__wrapped, self.__wrapped, workItem._block) - } else { - dispatch_async(self.__wrapped, workItem._block) - } + block = workItem._block + } + + if let g = group { + CDispatch.dispatch_group_async(g.__wrapped, self.__wrapped, block) } else { - if let g = group { - dispatch_group_async(g.__wrapped, self.__wrapped, work) - } else { - dispatch_async(self.__wrapped, work) - } + CDispatch.dispatch_async(self.__wrapped, block) } } private func _syncBarrier(block: @noescape () -> ()) { - dispatch_barrier_sync(self.__wrapped, block) + CDispatch.dispatch_barrier_sync(self.__wrapped, block) } private func _syncHelper( @@ -302,38 +305,48 @@ public extension DispatchQueue { } } - public func after(when: DispatchTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { + public func asyncAfter( + deadline: DispatchTime, + qos: DispatchQoS = .unspecified, + flags: DispatchWorkItemFlags = [], + execute work: @convention(block) () -> Void) + { if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: work) - dispatch_after(when.rawValue, self.__wrapped, item._block) + CDispatch.dispatch_after(deadline.rawValue, self.__wrapped, item._block) } else { - dispatch_after(when.rawValue, self.__wrapped, work) + CDispatch.dispatch_after(deadline.rawValue, self.__wrapped, work) } } - @available(OSX 10.10, iOS 8.0, *) - public func after(when: DispatchTime, execute: DispatchWorkItem) { - dispatch_after(when.rawValue, self.__wrapped, execute._block) - } - - public func after(walltime when: DispatchWallTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { + public func asyncAfter( + wallDeadline: DispatchWallTime, + qos: DispatchQoS = .unspecified, + flags: DispatchWorkItemFlags = [], + execute work: @convention(block) () -> Void) + { if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: work) - dispatch_after(when.rawValue, self.__wrapped, item._block) + CDispatch.dispatch_after(wallDeadline.rawValue, self.__wrapped, item._block) } else { - dispatch_after(when.rawValue, self.__wrapped, work) + CDispatch.dispatch_after(wallDeadline.rawValue, self.__wrapped, work) } } @available(OSX 10.10, iOS 8.0, *) - public func after(walltime when: DispatchWallTime, execute: DispatchWorkItem) { - dispatch_after(when.rawValue, self.__wrapped, execute._block) + public func asyncAfter(deadline: DispatchTime, execute: DispatchWorkItem) { + CDispatch.dispatch_after(deadline.rawValue, self.__wrapped, execute._block) + } + + @available(OSX 10.10, iOS 8.0, *) + public func asyncAfter(wallDeadline: DispatchWallTime, execute: DispatchWorkItem) { + CDispatch.dispatch_after(wallDeadline.rawValue, self.__wrapped, execute._block) } @available(OSX 10.10, iOS 8.0, *) public var qos: DispatchQoS { var relPri: Int32 = 0 - let cls = DispatchQoS.QoSClass(qosClass: _OSQoSClass(qosClass: dispatch_queue_get_qos_class(self.__wrapped, &relPri))!)! + let cls = DispatchQoS.QoSClass(rawValue: _OSQoSClass(qosClass: dispatch_queue_get_qos_class(self.__wrapped, &relPri))!)! return DispatchQoS(qosClass: cls, relativePriority: Int(relPri)) } @@ -356,52 +369,6 @@ public extension DispatchQueue { } } -extension DispatchQueue { - @available(*, deprecated, renamed: "DispatchQueue.sync(self:execute:)") - public func synchronously(execute work: @noescape () -> ()) { - sync(execute: work) - } - - @available(OSX, introduced: 10.10, deprecated: 10.12, renamed: "DispatchQueue.sync(self:execute:)") - @available(iOS, introduced: 8.0, deprecated: 10.0, renamed: "DispatchQueue.sync(self:execute:)") - @available(*, deprecated, renamed: "DispatchQueue.sync(self:execute:)") - public func synchronously(execute workItem: DispatchWorkItem) { - sync(execute: workItem) - } - - @available(OSX, introduced: 10.10, deprecated: 10.12, renamed: "DispatchQueue.async(self:execute:)") - @available(iOS, introduced: 8.0, deprecated: 10.0, renamed: "DispatchQueue.async(self:execute:)") - @available(*, deprecated, renamed: "DispatchQueue.async(self:execute:)") - public func asynchronously(execute workItem: DispatchWorkItem) { - async(execute: workItem) - } - - @available(*, deprecated, renamed: "DispatchQueue.async(self:group:qos:flags:execute:)") - public func asynchronously(group: DispatchGroup? = nil, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void) { - async(group: group, qos: qos, flags: flags, execute: work) - } - - @available(*, deprecated, renamed: "DispatchQueue.sync(self:execute:)") - public func synchronously(execute work: @noescape () throws -> T) rethrows -> T { - return try sync(execute: work) - } - - @available(*, deprecated, renamed: "DispatchQueue.sync(self:flags:execute:)") - public func synchronously(flags: DispatchWorkItemFlags, execute work: @noescape () throws -> T) rethrows -> T { - return try sync(flags: flags, execute: work) - } - - @available(*, deprecated, renamed: "DispatchQueue.concurrentPerform(iterations:execute:)") - public func apply(applier iterations: Int, execute block: @noescape (Int) -> Void) { - DispatchQueue.concurrentPerform(iterations: iterations, execute: block) - } - - @available(*, deprecated, renamed: "DispatchQueue.setTarget(self:queue:)") - public func setTargetQueue(queue: DispatchQueue) { - self.setTarget(queue: queue) - } -} - private func _destructDispatchSpecificValue(ptr: UnsafeMutableRawPointer?) { if let p = ptr { Unmanaged.fromOpaque(p).release() diff --git a/src/swift/Source.swift b/src/swift/Source.swift index 2830f010e..6591d075d 100644 --- a/src/swift/Source.swift +++ b/src/swift/Source.swift @@ -12,10 +12,10 @@ import CDispatch -public extension DispatchSourceType { +public extension DispatchSourceProtocol { public func setEventHandler(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], handler: DispatchSourceHandler?) { - if #available(OSX 10.10, iOS 8.0, *), let h = handler where qos != .unspecified || !flags.isEmpty { + if #available(OSX 10.10, iOS 8.0, *), let h = handler, qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: h) CDispatch.dispatch_source_set_event_handler((self as! DispatchSource).__wrapped, item._block) } else { @@ -29,7 +29,7 @@ public extension DispatchSourceType { } public func setCancelHandler(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], handler: DispatchSourceHandler?) { - if #available(OSX 10.10, iOS 8.0, *), let h = handler where qos != .unspecified || !flags.isEmpty { + if #available(OSX 10.10, iOS 8.0, *), let h = handler, qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: h) CDispatch.dispatch_source_set_cancel_handler((self as! DispatchSource).__wrapped, item._block) } else { @@ -43,7 +43,7 @@ public extension DispatchSourceType { } public func setRegistrationHandler(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], handler: DispatchSourceHandler?) { - if #available(OSX 10.10, iOS 8.0, *), let h = handler where qos != .unspecified || !flags.isEmpty { + if #available(OSX 10.10, iOS 8.0, *), let h = handler, qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: h) CDispatch.dispatch_source_set_registration_handler((self as! DispatchSource).__wrapped, item._block) } else { @@ -150,66 +150,66 @@ public extension DispatchSource { } #if HAVE_MACH - public class func machSend(port: mach_port_t, eventMask: MachSendEvent, queue: DispatchQueue? = nil) -> DispatchSourceMachSend { + public class func makeMachSendSource(port: mach_port_t, eventMask: MachSendEvent, queue: DispatchQueue? = nil) -> DispatchSourceMachSend { let source = dispatch_source_create(_swift_dispatch_source_type_mach_send(), UInt(port), eventMask.rawValue, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceMachSend } #endif #if HAVE_MACH - public class func machReceive(port: mach_port_t, queue: DispatchQueue? = nil) -> DispatchSourceMachReceive { + public class func makeMachReceiveSource(port: mach_port_t, queue: DispatchQueue? = nil) -> DispatchSourceMachReceive { let source = dispatch_source_create(_swift_dispatch_source_type_mach_recv(), UInt(port), 0, queue?.__wrapped) return DispatchSource(source) as DispatchSourceMachReceive } #endif #if HAVE_MACH - public class func memoryPressure(eventMask: MemoryPressureEvent, queue: DispatchQueue? = nil) -> DispatchSourceMemoryPressure { + public class func makeMemoryPressureSource(eventMask: MemoryPressureEvent, queue: DispatchQueue? = nil) -> DispatchSourceMemoryPressure { let source = dispatch_source_create(_swift_dispatch_source_type_memorypressure(), 0, eventMask.rawValue, queue.__wrapped) return DispatchSourceMemoryPressure(source) } #endif #if !os(Linux) - public class func process(identifier: pid_t, eventMask: ProcessEvent, queue: DispatchQueue? = nil) -> DispatchSourceProcess { + public class func makeProcessSource(identifier: pid_t, eventMask: ProcessEvent, queue: DispatchQueue? = nil) -> DispatchSourceProcess { let source = dispatch_source_create(_swift_dispatch_source_type_proc(), UInt(identifier), eventMask.rawValue, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceProcess } #endif - public class func read(fileDescriptor: Int32, queue: DispatchQueue? = nil) -> DispatchSourceRead { + public class func makeReadSource(fileDescriptor: Int32, queue: DispatchQueue? = nil) -> DispatchSourceRead { let source = dispatch_source_create(_swift_dispatch_source_type_read(), UInt(fileDescriptor), 0, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceRead } - public class func signal(signal: Int32, queue: DispatchQueue? = nil) -> DispatchSourceSignal { + public class func makeSignalSource(signal: Int32, queue: DispatchQueue? = nil) -> DispatchSourceSignal { let source = dispatch_source_create(_swift_dispatch_source_type_signal(), UInt(signal), 0, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceSignal } - public class func timer(flags: TimerFlags = [], queue: DispatchQueue? = nil) -> DispatchSourceTimer { + public class func makeTimerSource(flags: TimerFlags = [], queue: DispatchQueue? = nil) -> DispatchSourceTimer { let source = dispatch_source_create(_swift_dispatch_source_type_timer(), 0, flags.rawValue, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceTimer } - public class func userDataAdd(queue: DispatchQueue? = nil) -> DispatchSourceUserDataAdd { + public class func makeUserDataAddSource(queue: DispatchQueue? = nil) -> DispatchSourceUserDataAdd { let source = dispatch_source_create(_swift_dispatch_source_type_data_add(), 0, 0, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceUserDataAdd } - public class func userDataOr(queue: DispatchQueue? = nil) -> DispatchSourceUserDataOr { + public class func makeUserDataOrSource(queue: DispatchQueue? = nil) -> DispatchSourceUserDataOr { let source = dispatch_source_create(_swift_dispatch_source_type_data_or(), 0, 0, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceUserDataOr } #if !os(Linux) - public class func fileSystemObject(fileDescriptor: Int32, eventMask: FileSystemEvent, queue: DispatchQueue? = nil) -> DispatchSourceFileSystemObject { + public class func makeFileSystemObjectSource(fileDescriptor: Int32, eventMask: FileSystemEvent, queue: DispatchQueue? = nil) -> DispatchSourceFileSystemObject { let source = dispatch_source_create(_swift_dispatch_source_type_vnode(), UInt(fileDescriptor), eventMask.rawValue, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceFileSystemObject } #endif - public class func write(fileDescriptor: Int32, queue: DispatchQueue? = nil) -> DispatchSourceWrite { + public class func makeWriteSource(fileDescriptor: Int32, queue: DispatchQueue? = nil) -> DispatchSourceWrite { let source = dispatch_source_create(_swift_dispatch_source_type_write(), UInt(fileDescriptor), 0, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceWrite } @@ -299,38 +299,6 @@ public extension DispatchSourceTimer { } } -public extension DispatchSourceTimer { - @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleOneshot(self:deadline:leeway:)") - public func setTimer(start: DispatchTime, leeway: DispatchTimeInterval = .nanoseconds(0)) { - scheduleOneshot(deadline: start, leeway: leeway) - } - - @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleOneshot(self:wallDeadline:leeway:)") - public func setTimer(walltime start: DispatchWallTime, leeway: DispatchTimeInterval = .nanoseconds(0)) { - scheduleOneshot(wallDeadline: start, leeway: leeway) - } - - @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleRepeating(self:deadline:interval:leeway:)") - public func setTimer(start: DispatchTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .nanoseconds(0)) { - scheduleRepeating(deadline: start, interval: interval, leeway: leeway) - } - - @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleRepeating(self:deadline:interval:leeway:)") - public func setTimer(start: DispatchTime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { - scheduleRepeating(deadline: start, interval: interval, leeway: leeway) - } - - @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleRepeating(self:wallDeadline:interval:leeway:)") - public func setTimer(walltime start: DispatchWallTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .nanoseconds(0)) { - scheduleRepeating(wallDeadline: start, interval: interval, leeway: leeway) - } - - @available(*, deprecated, renamed: "DispatchSourceTimer.scheduleRepeating(self:wallDeadline:interval:leeway:)") - public func setTimer(walltime start: DispatchWallTime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { - scheduleRepeating(wallDeadline: start, interval: interval, leeway: leeway) - } -} - #if !os(Linux) public extension DispatchSourceFileSystemObject { public var handle: Int32 { @@ -361,13 +329,12 @@ public extension DispatchSourceUserDataAdd { /// The value to coalesce with the pending data using a logical OR or an ADD /// as specified by the dispatch source type. A value of zero has no effect /// and will not result in the submission of the event handler block. - public func mergeData(value: UInt) { - dispatch_source_merge_data((self as! DispatchSource).__wrapped, value) + public func add(data: UInt) { + dispatch_source_merge_data((self as! DispatchSource).__wrapped, data) } } public extension DispatchSourceUserDataOr { -#if false /*FIXME: clashes with UserDataAdd?? */ /// @function mergeData /// /// @abstract @@ -379,10 +346,9 @@ public extension DispatchSourceUserDataOr { /// The value to coalesce with the pending data using a logical OR or an ADD /// as specified by the dispatch source type. A value of zero has no effect /// and will not result in the submission of the event handler block. - public func mergeData(value: UInt) { - dispatch_source_merge_data((self as! DispatchSource).__wrapped, value) + public func or(data: UInt) { + dispatch_source_merge_data((self as! DispatchSource).__wrapped, data) } -#endif } @_silgen_name("_swift_dispatch_source_type_DATA_ADD") diff --git a/src/swift/Time.swift b/src/swift/Time.swift index 76a6979eb..70842dd0d 100644 --- a/src/swift/Time.swift +++ b/src/swift/Time.swift @@ -16,7 +16,7 @@ import CDispatch -public struct DispatchTime { +public struct DispatchTime : Comparable { public let rawValue: dispatch_time_t public static func now() -> DispatchTime { @@ -29,9 +29,33 @@ public struct DispatchTime { private init(rawValue: dispatch_time_t) { self.rawValue = rawValue } + + /// Creates a `DispatchTime` relative to the system clock that + /// ticks since boot. + /// + /// - Parameters: + /// - uptimeNanoseconds: The number of nanoseconds since boot, excluding + /// time the system spent asleep + /// - Returns: A new `DispatchTime` + public init(uptimeNanoseconds: UInt64) { + self.rawValue = dispatch_time_t(uptimeNanoseconds) + } + + public var uptimeNanoseconds: UInt64 { + return UInt64(self.rawValue) + } +} + +public func <(a: DispatchTime, b: DispatchTime) -> Bool { + if a.rawValue == ~0 || b.rawValue == ~0 { return false } + return a.rawValue < b.rawValue } -public struct DispatchWallTime { +public func ==(a: DispatchTime, b: DispatchTime) -> Bool { + return a.rawValue == b.rawValue +} + +public struct DispatchWallTime : Comparable { public let rawValue: dispatch_time_t public static func now() -> DispatchWallTime { @@ -44,14 +68,20 @@ public struct DispatchWallTime { self.rawValue = rawValue } - public init(time: timespec) { - var t = time + public init(timespec: timespec) { + var t = timespec self.rawValue = CDispatch.dispatch_walltime(&t, 0) } } -@available(*, deprecated, renamed: "DispatchWallTime") -public typealias DispatchWalltime = DispatchWallTime +public func <(a: DispatchWallTime, b: DispatchWallTime) -> Bool { + if a.rawValue == ~0 || b.rawValue == ~0 { return false } + return -Int64(a.rawValue) < -Int64(b.rawValue) +} + +public func ==(a: DispatchWallTime, b: DispatchWallTime) -> Bool { + return a.rawValue == b.rawValue +} public enum DispatchTimeInterval { case seconds(Int) diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index 8f841f13d..41293e126 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -15,7 +15,7 @@ import CDispatch // This file contains declarations that are provided by the // importer via Dispatch.apinote when the platform has Objective-C support -@noreturn public func dispatchMain() { +public func dispatchMain() -> Never { CDispatch.dispatch_main() } @@ -159,7 +159,7 @@ public class DispatchQueue : DispatchObject { } public class DispatchSource : DispatchObject, - DispatchSourceType, DispatchSourceRead, + DispatchSourceProtocol, DispatchSourceRead, DispatchSourceSignal, DispatchSourceTimer, DispatchSourceUserDataAdd, DispatchSourceUserDataOr, DispatchSourceWrite { @@ -208,7 +208,7 @@ internal class __DispatchData : DispatchObject { public typealias DispatchSourceHandler = @convention(block) () -> Void -public protocol DispatchSourceType { +public protocol DispatchSourceProtocol { func setEventHandler(qos: DispatchQoS, flags: DispatchWorkItemFlags, handler: DispatchSourceHandler?) func setEventHandler(handler: DispatchWorkItem) @@ -236,18 +236,16 @@ public protocol DispatchSourceType { var isCancelled: Bool { get } } -public protocol DispatchSourceUserDataAdd : DispatchSourceType { - func mergeData(value: UInt) +public protocol DispatchSourceUserDataAdd : DispatchSourceProtocol { + func add(data: UInt) } -public protocol DispatchSourceUserDataOr { -#if false /*FIXME: clashes with UserDataAdd?? */ - func mergeData(value: UInt) -#endif +public protocol DispatchSourceUserDataOr : DispatchSourceProtocol { + func or(data: UInt) } #if HAVE_MACH -public protocol DispatchSourceMachSend : DispatchSourceType { +public protocol DispatchSourceMachSend : DispatchSourceProtocol { public var handle: mach_port_t { get } public var data: DispatchSource.MachSendEvent { get } @@ -257,13 +255,13 @@ public protocol DispatchSourceMachSend : DispatchSourceType { #endif #if HAVE_MACH -public protocol DispatchSourceMachReceive : DispatchSourceType { +public protocol DispatchSourceMachReceive : DispatchSourceProtocol { var handle: mach_port_t { get } } #endif #if HAVE_MACH -public protocol DispatchSourceMemoryPressure : DispatchSourceType { +public protocol DispatchSourceMemoryPressure : DispatchSourceProtocol { public var data: DispatchSource.MemoryPressureEvent { get } public var mask: DispatchSource.MemoryPressureEvent { get } @@ -271,7 +269,7 @@ public protocol DispatchSourceMemoryPressure : DispatchSourceType { #endif #if !os(Linux) -public protocol DispatchSourceProcess : DispatchSourceType { +public protocol DispatchSourceProcess : DispatchSourceProtocol { var handle: pid_t { get } var data: DispatchSource.ProcessEvent { get } @@ -280,28 +278,28 @@ public protocol DispatchSourceProcess : DispatchSourceType { } #endif -public protocol DispatchSourceRead : DispatchSourceType { +public protocol DispatchSourceRead : DispatchSourceProtocol { } -public protocol DispatchSourceSignal : DispatchSourceType { +public protocol DispatchSourceSignal : DispatchSourceProtocol { } -public protocol DispatchSourceTimer : DispatchSourceType { - func setTimer(start: DispatchTime, leeway: DispatchTimeInterval) +public protocol DispatchSourceTimer : DispatchSourceProtocol { + func scheduleOneshot(deadline: DispatchTime, leeway: DispatchTimeInterval) - func setTimer(walltime start: DispatchWallTime, leeway: DispatchTimeInterval) + func scheduleOneshot(wallDeadline: DispatchWallTime, leeway: DispatchTimeInterval) - func setTimer(start: DispatchTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval) + func scheduleRepeating(deadline: DispatchTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval) - func setTimer(start: DispatchTime, interval: Double, leeway: DispatchTimeInterval) + func scheduleRepeating(deadline: DispatchTime, interval: Double, leeway: DispatchTimeInterval) - func setTimer(walltime start: DispatchWallTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval) + func scheduleRepeating(wallDeadline: DispatchWallTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval) - func setTimer(walltime start: DispatchWallTime, interval: Double, leeway: DispatchTimeInterval) + func scheduleRepeating(wallDeadline: DispatchWallTime, interval: Double, leeway: DispatchTimeInterval) } #if !os(Linux) -public protocol DispatchSourceFileSystemObject : DispatchSourceType { +public protocol DispatchSourceFileSystemObject : DispatchSourceProtocol { var handle: Int32 { get } var data: DispatchSource.FileSystemEvent { get } @@ -310,7 +308,7 @@ public protocol DispatchSourceFileSystemObject : DispatchSourceType { } #endif -public protocol DispatchSourceWrite : DispatchSourceType { +public protocol DispatchSourceWrite : DispatchSourceProtocol { } From 8a167040f04da9dc0515b993a246a45908c9aabf Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Wed, 27 Jul 2016 15:00:04 -0700 Subject: [PATCH 61/67] UnsafeRawPointer fixes. Signed-off-by: Daniel A. Steffen --- src/swift/Data.swift | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index b8271f63e..8c1154d3e 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -77,17 +77,20 @@ public struct DispatchData : RandomAccessCollection { body: @noescape (UnsafePointer) throws -> Result) rethrows -> Result { var ptr: UnsafeRawPointer? = nil - var size = 0; + var size = 0 let data = CDispatch.dispatch_data_create_map(__wrapped.__wrapped, &ptr, &size) + let contentPtr = ptr!.bindMemory( + to: ContentType.self, capacity: size / strideof(ContentType.self)) defer { _fixLifetime(data) } - return try body(UnsafePointer(ptr!)) + return try body(contentPtr) } public func enumerateBytes( block: @noescape (buffer: UnsafeBufferPointer, byteIndex: Int, stop: inout Bool) -> Void) { _swift_dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafeRawPointer, size: Int) in - let bp = UnsafeBufferPointer(start: UnsafePointer(ptr), count: size) + let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: size) + let bp = UnsafeBufferPointer(start: bytePtr, count: size) var stop = false block(buffer: bp, byteIndex: offset, stop: &stop) return !stop @@ -188,8 +191,7 @@ public struct DispatchData : RandomAccessCollection { let map = CDispatch.dispatch_data_create_map(subdata, &ptr, &size) defer { _fixLifetime(map) } - let pptr = UnsafePointer(ptr!) - return pptr[index - offset] + return ptr!.load(fromByteOffset: index - offset, as: UInt8.self) } public subscript(bounds: Range) -> RandomAccessSlice { @@ -242,7 +244,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { var ptr: UnsafeRawPointer? self._count = 0 self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count)) - self._ptr = UnsafePointer(ptr) + self._ptr = ptr self._position = _data.startIndex // The only time we expect a 'nil' pointer is when the data is empty. @@ -253,13 +255,13 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { /// element exists. public mutating func next() -> DispatchData._Element? { if _position == _count { return nil } - let element = _ptr[_position]; + let element = _ptr.load(fromByteOffset: _position, as: UInt8.self) _position = _position + 1 return element } internal let _data: __DispatchData - internal var _ptr: UnsafePointer! + internal var _ptr: UnsafeRawPointer! internal var _count: Int internal var _position: DispatchData.Index } From 1493f940f7cb7535ee785ceac4714c96d739e813 Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Thu, 28 Jul 2016 10:09:23 -0700 Subject: [PATCH 62/67] Merge pull request #116 from mwwa/overlay-syncup [overlay-syncup] sync overlay changes to Linux Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 7a943ad04..ae1a5c66d 100644 --- a/PATCHES +++ b/PATCHES @@ -265,3 +265,4 @@ github commits starting with 29bdc2f from [2e4e6af] APPLIED rdar://27600964 [2457fb2] APPLIED rdar://27600964 [4d58038] APPLIED rdar://27600964 +[98d0a05] APPLIED rdar://27600964 From 2aed5c6c854082586245f372ebe5537bcc18ec2f Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 28 Jul 2016 16:53:10 -0400 Subject: [PATCH 63/67] Update INSTALL instructions Add description for building libdispatch with Swift API either as part of building a Swift toolchain from source using utils/build-script or using a pre-built Swift toolchain. Update Linux-specific instructions to try to avoid some common problems people have been reporting. Signed-off-by: Daniel A. Steffen --- INSTALL | 71 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/INSTALL b/INSTALL index 9113e4a8f..8a09c3a44 100644 --- a/INSTALL +++ b/INSTALL @@ -4,21 +4,45 @@ GCD is a concurrent programming framework first shipped with Mac OS X Snow Leopard. This package is an open source bundling of libdispatch, the core user space library implementing GCD. At the time of writing, support for the BSD kqueue API, and specifically extensions introduced in Mac OS X Snow -Leopard and FreeBSD 9-CURRENT, are required to use libdispatch. Support -for Linux is a work in progress (see Linux notes below). Other systems are -currently unsupported. +Leopard and FreeBSD 9-CURRENT, are required to use libdispatch. Linux is +supported, but requires specific packages to be installed (see Linux +section at the end of the file). Other systems are currently unsupported. - Configuring and installing libdispatch +I. Configuring and installing libdispatch (general comments) GCD is built using autoconf, automake, and libtool, and has a number of compile-time configuration options that should be reviewed before starting. -An uncustomized install requires: +An uncustomized install of the C-API to libdispatch requires: sh autogen.sh ./configure make make install +libdispatch can be optionally built to include a Swift API. This requires a +Swift toolchain to compile the Swift code in libdispatch and can be done +in two possible scenarios. + +If you are building your own Swift toolchain from source, then you should build +libdispatch simply by giving additional arguments to swift/utils/build-script: + + ./swift/utils/build-script --libdispatch -- --install-libdispatch + +To build libdispatch using a pre-built Swift toolchain and install libdispatch +into that toolchain (to allow that toolchain to compile Swift code containing +"import Dispatch") requires: + + sh autogen.sh + ./configure --with-swift-toolchain= --prefix= + make + make install + +Note that once libdispatch is installed into a Swift toolchain, that +toolchain cannot be used to compile libdispatch again (you must 'make uninstall' +libdispatch from the toolchain before using it to rebuild libdispatch). + +II. Building and installing on OS X + The following configure options may be of general interest: --with-apple-libpthread-source @@ -88,6 +112,8 @@ libdispatch for /usr/lib/system on OS X El Capitan: --with-apple-objc4-source=/path/to/10.11.0/objc4-680 make check +III. Building and installing for FreeBSD + Typical configuration line for FreeBSD 8.x and 9.x to build libdispatch with clang and blocks support: @@ -95,26 +121,33 @@ clang and blocks support: ./configure CC=clang --with-blocks-runtime=/usr/local/lib make check -Instructions for building on Linux. Initial focus is on ubuntu 15.04. -Prepare your system - 1. Install compiler, autotools - sudo apt-get install clang - sudo apt-get install autoconf libtool pkg-config - 2. Install dtrace (to generate provider.h) +IV. Building and installing for Linux + +Note that libdispatch development and testing is done only +on Ubuntu; currently supported versions are 14.04, 15.10 and 16.04. + +(1) The first thing to do is install required packages: + 1a. Install build tools and clang compiler. + sudo apt-get install autoconf libtool pkg-config clang + 1b. Install dtrace (to generate provider.h) sudo apt-get install systemtap-sdt-dev - 3. Install libdispatch pre-reqs + 1c. Install additional libdispatch dependencies sudo apt-get install libblocksruntime-dev libkqueue-dev libbsd-dev -Initialize git submodules: - We are using git submodules to incorporate a specific revision of the - upstream pthread_workqueue library into the build. +Note: compiling libdispatch requires clang 3.8 or better and +the gold linker. If the default clang on your Ubuntu version is +too old, see http://apt.llvm.org/ to install a newer version. +On older Ubuntu releases, you may need to install binutils-gold +to get the gold linker. + +(2) Initialize git submodules. + We are using git submodules to incorporate specific revisions of the + upstream pthread_workqueue and libkqueue projects into the build. git submodule init git submodule update -Build: +(3) Build (as in the general instructions above) sh autogen.sh ./configure make - -Note: the build currently fails building tests, but libdispatch.so should - build successfully. + make install From cf8aae4d7163e88d882e6a5b61d6040efbb9b910 Mon Sep 17 00:00:00 2001 From: Tony Parker Date: Thu, 28 Jul 2016 14:13:04 -0700 Subject: [PATCH 64/67] Merge pull request #123 from dgrove-oss/update-build-instructions Update INSTALL instructions Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index ae1a5c66d..6b62acb39 100644 --- a/PATCHES +++ b/PATCHES @@ -266,3 +266,4 @@ github commits starting with 29bdc2f from [2457fb2] APPLIED rdar://27600964 [4d58038] APPLIED rdar://27600964 [98d0a05] APPLIED rdar://27600964 +[8976101] APPLIED rdar://27600964 From adc577574f3d8697833d2e6ec3ce2c8915607e46 Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 12 Aug 2016 11:41:45 -0400 Subject: [PATCH 65/67] fixes for compilation/linking problems on linux --- src/Makefile.am | 3 ++- src/init.c | 2 +- src/queue.c | 4 ++++ src/shims/linux_stubs.h | 2 -- src/voucher.c | 2 ++ src/voucher_internal.h | 2 ++ 6 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 31e8c5080..670178fcf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -87,10 +87,11 @@ if BUILD_OWN_BLOCKS_RUNTIME libdispatch_la_SOURCES+= BlocksRuntime/data.c BlocksRuntime/runtime.c CBLOCKS_FLAGS+= -I$(top_srcdir)/src/BlocksRuntime CXXBLOCKS_FLAGS+= -I$(top_srcdir)/src/BlocksRuntime +BLOCKS_RUNTIME_LIBS=-ldl endif libdispatch_la_LDFLAGS=-avoid-version -libdispatch_la_LIBADD=$(KQUEUE_LIBS) $(PTHREAD_WORKQUEUE_LIBS) $(BSD_OVERLAY_LIBS) +libdispatch_la_LIBADD=$(KQUEUE_LIBS) $(PTHREAD_WORKQUEUE_LIBS) $(BSD_OVERLAY_LIBS) $(BLOCKS_RUNTIME_LIBS) if HAVE_DARWIN_LD libdispatch_la_LDFLAGS+=-Wl,-compatibility_version,1 \ diff --git a/src/init.c b/src/init.c index 45cbff3bf..87be596f2 100644 --- a/src/init.c +++ b/src/init.c @@ -1197,7 +1197,7 @@ dispatch_source_type_readwrite_init(dispatch_source_t ds, dispatch_queue_t q DISPATCH_UNUSED) { ds->ds_is_level = true; -#ifdef HAVE_DECL_NOTE_LOWAT +#if HAVE_DECL_NOTE_LOWAT // bypass kernel check for device kqueue support rdar://19004921 ds->ds_dkev->dk_kevent.fflags = NOTE_LOWAT; #endif diff --git a/src/queue.c b/src/queue.c index 58c545b17..5d79b2c6c 100644 --- a/src/queue.c +++ b/src/queue.c @@ -2734,12 +2734,16 @@ _dispatch_block_create_with_voucher_and_priority(dispatch_block_flags_t flags, bool assign = (flags & DISPATCH_BLOCK_ASSIGN_CURRENT); if (assign && !(flags & DISPATCH_BLOCK_HAS_VOUCHER)) { +#if OS_VOUCHER_ACTIVITY_SPI voucher = VOUCHER_CURRENT; +#endif flags |= DISPATCH_BLOCK_HAS_VOUCHER; } +#if OS_VOUCHER_ACTIVITY_SPI if (voucher == VOUCHER_CURRENT) { voucher = _voucher_get(); } +#endif if (assign && !(flags & DISPATCH_BLOCK_HAS_PRIORITY)) { pri = _dispatch_priority_propagate(); flags |= DISPATCH_BLOCK_HAS_PRIORITY; diff --git a/src/shims/linux_stubs.h b/src/shims/linux_stubs.h index e13304906..0c12e8272 100644 --- a/src/shims/linux_stubs.h +++ b/src/shims/linux_stubs.h @@ -47,8 +47,6 @@ typedef uint32_t voucher_activity_trace_id_t; typedef uint32_t voucher_activity_id_t; -typedef uint32_t _voucher_activity_buffer_hook_t;; - typedef uint32_t voucher_activity_flag_t; typedef struct { } mach_msg_header_t; diff --git a/src/voucher.c b/src/voucher.c index 94a293427..ee04e3b19 100644 --- a/src/voucher.c +++ b/src/voucher.c @@ -1560,6 +1560,7 @@ _voucher_init(void) { } +#if OS_VOUCHER_ACTIVITY_SPI void* voucher_activity_get_metadata_buffer(size_t *length) { @@ -1631,6 +1632,7 @@ voucher_activity_initialize_4libtrace(voucher_activity_hooks_t hooks) { (void)hooks; } +#endif // OS_VOUCHER_ACTIVITY_SPI size_t _voucher_debug(voucher_t v, char* buf, size_t bufsiz) diff --git a/src/voucher_internal.h b/src/voucher_internal.h index 3aa1a6579..b34ad4643 100644 --- a/src/voucher_internal.h +++ b/src/voucher_internal.h @@ -90,8 +90,10 @@ voucher_get_mach_voucher(voucher_t voucher); void _voucher_init(void); void _voucher_atfork_child(void); void _voucher_activity_debug_channel_init(void); +#if OS_VOUCHER_ACTIVITY_SPI void _voucher_activity_swap(firehose_activity_id_t old_id, firehose_activity_id_t new_id); +#endif void _voucher_xref_dispose(voucher_t voucher); void _voucher_dispose(voucher_t voucher); size_t _voucher_debug(voucher_t v, char* buf, size_t bufsiz); From 2c9f19e08bec5121a7711cde28c3361b1ad07ec6 Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 12 Aug 2016 16:46:22 -0400 Subject: [PATCH 66/67] xcode / autoconf plumbing to select module.modulemap file --- .gitignore | 2 ++ configure.ac | 16 +++++++++++++++- dispatch/Makefile.am | 2 +- dispatch/{ => darwin}/module.modulemap | 0 .../{module.map => generic/module.modulemap} | 0 libdispatch.xcodeproj/project.pbxproj | 4 ++-- private/{ => darwin}/module.modulemap | 0 private/generic/module.modulemap | 11 +++++++++++ src/Makefile.am | 2 +- 9 files changed, 32 insertions(+), 5 deletions(-) rename dispatch/{ => darwin}/module.modulemap (100%) rename dispatch/{module.map => generic/module.modulemap} (100%) rename private/{ => darwin}/module.modulemap (100%) create mode 100644 private/generic/module.modulemap diff --git a/.gitignore b/.gitignore index 1bf54ca69..aa26514c9 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,5 @@ config configure libtool .dirstamp +/dispatch/module.modulemap +/private/module.modulemap diff --git a/configure.ac b/configure.ac index e3e06ce5b..461659ec5 100644 --- a/configure.ac +++ b/configure.ac @@ -432,6 +432,20 @@ AS_IF([test "x$have_mach" = "xtrue"], [ ]) AM_CONDITIONAL(HAVE_DARWIN_LD, [test "x$dispatch_cv_ld_darwin" == "xyes"]) +# +# symlink platform-specific module.modulemap files +# +AS_CASE([$target_os], + [darwin*], [ dispatch_module_map_os=darwin ], + [ dispatch_module_map_os=generic ] +) +AC_CONFIG_COMMANDS([modulemaps], [ + ln -fs $dispatch_module_map_os/module.modulemap $ac_top_srcdir/dispatch/module.modulemap + ln -fs $dispatch_module_map_os/module.modulemap $ac_top_srcdir/private/module.modulemap + ], + [dispatch_module_map_os="$dispatch_module_map_os"] +) + # # Temporary: some versions of clang do not mark __builtin_trap() as # __attribute__((__noreturn__)). Detect and add if required. @@ -449,6 +463,6 @@ AC_CONFIG_FILES([Makefile dispatch/Makefile man/Makefile os/Makefile private/Mak # # Generate testsuite links # -AC_CONFIG_LINKS([tests/dispatch:$top_srcdir/private tests/leaks-wrapper:tests/leaks-wrapper.sh]) +AC_CONFIG_LINKS([tests/dispatch:$ac_top_srcdir/private tests/leaks-wrapper:tests/leaks-wrapper.sh]) AC_OUTPUT diff --git a/dispatch/Makefile.am b/dispatch/Makefile.am index 53ea5986c..89fd3daf0 100644 --- a/dispatch/Makefile.am +++ b/dispatch/Makefile.am @@ -24,5 +24,5 @@ dispatch_HEADERS= \ time.h if HAVE_SWIFT -dispatch_HEADERS+=module.map +dispatch_HEADERS+=module.modulemap endif diff --git a/dispatch/module.modulemap b/dispatch/darwin/module.modulemap similarity index 100% rename from dispatch/module.modulemap rename to dispatch/darwin/module.modulemap diff --git a/dispatch/module.map b/dispatch/generic/module.modulemap similarity index 100% rename from dispatch/module.map rename to dispatch/generic/module.modulemap diff --git a/libdispatch.xcodeproj/project.pbxproj b/libdispatch.xcodeproj/project.pbxproj index c40d08155..9fe06aa92 100644 --- a/libdispatch.xcodeproj/project.pbxproj +++ b/libdispatch.xcodeproj/project.pbxproj @@ -662,8 +662,8 @@ C01866BD1C5973210040FC07 /* libdispatch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdispatch.a; sourceTree = BUILT_PRODUCTS_DIR; }; C01866BE1C59735B0040FC07 /* libdispatch-mp-static.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "libdispatch-mp-static.xcconfig"; sourceTree = ""; }; C01866BF1C5976C90040FC07 /* run-on-install.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "run-on-install.sh"; sourceTree = ""; }; - C901445E1C73A7FE002638FC /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; - C90144641C73A845002638FC /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; + C901445E1C73A7FE002638FC /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = darwin/module.modulemap; sourceTree = ""; }; + C90144641C73A845002638FC /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = darwin/module.modulemap; sourceTree = ""; }; C913AC0E143BD34800B78976 /* data_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = data_private.h; sourceTree = ""; tabWidth = 8; }; C927F35F10FD7F1000C5AB8B /* ddt.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ddt.xcodeproj; path = tools/ddt/ddt.xcodeproj; sourceTree = ""; }; C96CE17A1CEB851600F4B8E6 /* dispatch_objc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = dispatch_objc.m; sourceTree = ""; }; diff --git a/private/module.modulemap b/private/darwin/module.modulemap similarity index 100% rename from private/module.modulemap rename to private/darwin/module.modulemap diff --git a/private/generic/module.modulemap b/private/generic/module.modulemap new file mode 100644 index 000000000..62975a59b --- /dev/null +++ b/private/generic/module.modulemap @@ -0,0 +1,11 @@ +module DispatchPrivate [system] [extern_c] { + umbrella header "private.h" + exclude header "mach_private.h" + module * { export * } + export * +} + +module DispatchIntrospectionPrivate [system] [extern_c] { + header "introspection_private.h" + export * +} diff --git a/src/Makefile.am b/src/Makefile.am index 670178fcf..98d36160a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -164,7 +164,7 @@ SWIFT_GEN_FILES= \ $(SWIFT_OBJ_FILES:%=%.~partial.swiftdoc) \ $(SWIFT_OBJ_FILES:%=%.~partial.swiftdeps) -SWIFTC_FLAGS = -Xcc -fmodule-map-file=$(abs_top_srcdir)/dispatch/module.map -I$(abs_top_srcdir) -Xcc -fblocks +SWIFTC_FLAGS = -Xcc -fmodule-map-file=$(abs_top_srcdir)/dispatch/module.modulemap -I$(abs_top_srcdir) -Xcc -fblocks if DISPATCH_ENABLE_OPTIMIZATION SWIFTC_FLAGS+=-O endif From a23ea8cd93cd7eb83acaf695106fa936d842432d Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 12 Aug 2016 21:38:44 -0400 Subject: [PATCH 67/67] ensure root_queues are initialized before main thread exits --- src/queue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/queue.c b/src/queue.c index 5d79b2c6c..0c058be55 100644 --- a/src/queue.c +++ b/src/queue.c @@ -5844,6 +5844,9 @@ _dispatch_main_queue_callback_4CF( void dispatch_main(void) { + dispatch_once_f(&_dispatch_root_queues_pred, NULL, + _dispatch_root_queues_init_once); + #if HAVE_PTHREAD_MAIN_NP if (pthread_main_np()) { #endif