From d051a8bcdc24f59a126abbc55ac9a675b6165bbb Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 18 May 2017 17:19:13 -0700 Subject: [PATCH 01/48] missing hunk from 95875d7 Signed-off-by: Daniel A. Steffen --- src/swift/Data.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index ae168d3e8..ac5b6950b 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -92,7 +92,7 @@ public struct DispatchData : RandomAccessCollection { } public func enumerateBytes( - block: @noescape (_ buffer: UnsafeBufferPointer, _ byteIndex: Int, _ stop: inout Bool) -> Void) + block: (_ buffer: UnsafeBufferPointer, _ byteIndex: Int, _ stop: inout Bool) -> Void) { // we know that capturing block in the closure being created/passed to dispatch_data_apply // does not cause block to escape because dispatch_data_apply does not allow its From ae657d72fe32a412ef8b40c70b9092b4720e42a6 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 18 May 2017 17:24:12 -0700 Subject: [PATCH 02/48] missing hunk from 5464492 Signed-off-by: Daniel A. Steffen --- src/swift/Data.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index ac5b6950b..69004ef82 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -130,7 +130,7 @@ public struct DispatchData : RandomAccessCollection { /// /// - parameter buffer: The buffer of bytes to append. The size is calculated from `SourceType` and `buffer.count`. public mutating func append(_ buffer : UnsafeBufferPointer) { - let count = buffer.count * sizeof(SourceType.self) + let count = buffer.count * MemoryLayout.stride; buffer.baseAddress?.withMemoryRebound(to: UInt8.self, capacity: count) { self.append($0, count: count) } From d0e53b5f15cca50e06f03a429b17dde5e3bc50d2 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 18 May 2017 17:25:59 -0700 Subject: [PATCH 03/48] missing hunk from 24f49a2 Signed-off-by: Daniel A. Steffen --- src/swift/Data.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index 69004ef82..e0b7263c9 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -196,10 +196,7 @@ public struct DispatchData : RandomAccessCollection { guard !copyRange.isEmpty else { return 0 } - let bufferCapacity = buffer.count * sizeof(DestinationType.self) - buffer.baseAddress?.withMemoryRebound(to: UInt8.self, capacity: bufferCapacity) { - _copyBytesHelper(to: $0, from: copyRange) - } + _copyBytesHelper(to: buffer.baseAddress!, from: copyRange) return copyRange.count } From 6b3862bbb7d85e0d29a0c1c4537a734f4da7bf95 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 18 May 2017 17:27:59 -0700 Subject: [PATCH 04/48] missing hunk from b5e37c8 Signed-off-by: Daniel A. Steffen --- src/swift/Private.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swift/Private.swift b/src/swift/Private.swift index 5917f77de..9a5179738 100644 --- a/src/swift/Private.swift +++ b/src/swift/Private.swift @@ -140,7 +140,7 @@ public func dispatch_io_set_interval(_ channel: DispatchIO, _ interval: UInt64, fatalError() } -@available(*, unavailable, renamed:"DispatchQueue.apply(attributes:iterations:execute:)") +@available(*, unavailable, renamed:"DispatchQueue.concurrentPerform(iterations:execute:)") public func dispatch_apply(_ iterations: Int, _ queue: DispatchQueue, _ block: (Int) -> Void) { fatalError() From 4ac2139011c8abe12aca639959aba8233a02499a Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 18 May 2017 17:30:57 -0700 Subject: [PATCH 05/48] missing hunk from 709964f Signed-off-by: Daniel A. Steffen --- src/swift/Private.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swift/Private.swift b/src/swift/Private.swift index 9a5179738..df6a7b336 100644 --- a/src/swift/Private.swift +++ b/src/swift/Private.swift @@ -158,7 +158,7 @@ public func dispatch_get_global_queue(_ identifier: Int, _ flags: UInt) -> Dispa fatalError() } -@available(*, unavailable, renamed: "DispatchQueue.main") +@available(*, unavailable, renamed: "getter:DispatchQueue.main()") public func dispatch_get_main_queue() -> DispatchQueue { fatalError() From 919c0f80f18339d01f1a8a07f4c940fcaa8fe434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Wei=C3=9F?= Date: Mon, 6 Feb 2017 17:30:25 +0000 Subject: [PATCH 06/48] fix libdispatch.a The static version (`libdispatch.a`) that can be compiled using `./configure --enable static=yes` was missing all the Swift overlay symbols (everything in `swift_overlay.o`). The reason for that is that the linker is invoked through libtool which wants `.lo` files but the Swift overlay got passed as a `.o` file. This first of all leads to this warning: *** Warning: Linking the shared library libdispatch.la against the non-libtool *** objects [...]/swift_overlay.o is not portable! And the result is that libtool doesn't include `swift_overlay.o` when putting together the static library `libdispatch.a`. This patch fixes this problem is a pretty crude way. The real problem is that libtool doesn't understand Swift. So it can't be used when compiling `swift_overlay.o`. In order to still get a `.lo` file this patch tricks libtool into generating one from the `swift_overlay.o` generated by `swiftc`. It's very hacky but I'm not sure what else to do. 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 6517b7418..a2cbe9e5f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -157,12 +157,22 @@ SWIFT_SRC_FILES=\ SWIFT_ABS_SRC_FILES = $(SWIFT_SRC_FILES:%=$(abs_srcdir)/%) SWIFT_OBJ_FILES = $(abs_builddir)/swift/swift_overlay.o +SWIFT_LIBTOOL_OBJ_FILES = $(abs_builddir)/swift/swift_overlay.lo 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 +# this saves the object file, then tricks libtool into generating a .lo file and +# then moves the object file back in the places libtool expects them to be for +# the PIC and non-PIC case. +$(abs_builddir)/swift/swift_overlay.lo: $(abs_builddir)/swift/swift_overlay.o + mv $(abs_builddir)/swift/swift_overlay.o $(abs_builddir)/swift/.libs/swift_overlay.o.save + $(LIBTOOL) --mode=compile --tag=CC true -o $< -c /dev/null + cp $(abs_builddir)/swift/.libs/swift_overlay.o.save $(abs_builddir)/swift/.libs/swift_overlay.o + mv $(abs_builddir)/swift/.libs/swift_overlay.o.save $(abs_builddir)/swift/swift_overlay.o + $(abs_builddir)/swift/swift_overlay.o: $(SWIFT_ABS_SRC_FILES) $(SWIFTC) @rm -f $@ $(SWIFTC) -whole-module-optimization -emit-library -c $(SWIFT_ABS_SRC_FILES) \ @@ -172,8 +182,8 @@ $(abs_builddir)/swift/swift_overlay.o: $(SWIFT_ABS_SRC_FILES) $(SWIFTC) 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) +EXTRA_libdispatch_la_DEPENDENCIES+=$(SWIFT_OBJ_FILES) $(SWIFT_LIBTOOL_OBJ_FILES) $(abs_builddir)/swift/Dispatch.swiftmodule +libdispatch_la_LIBADD+=$(SWIFT_LIBTOOL_OBJ_FILES) SWIFT_GEN_FILES= \ $(abs_builddir)/swift/Dispatch.swiftmodule \ From 84b4018bf88128f557ca1bb40f6a5ac4295b4a8d Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Mon, 20 Feb 2017 09:09:29 -0800 Subject: [PATCH 07/48] Merge pull request #209 from weissi/jw-fix-libdispatch.a fix libdispatch.a to include Swift overlay symbols Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 9fecb8398..ff022631e 100644 --- a/PATCHES +++ b/PATCHES @@ -312,3 +312,4 @@ github commits starting with 29bdc2f from [787dd92] APPLIED rdar://30568673 [ba4cac5] APPLIED rdar://30568673 [7974138] APPLIED rdar://30568673 +[cd12dcb] APPLIED rdar://32283666 From 924222995febc1fedcdc2b3726c5f509392f8db4 Mon Sep 17 00:00:00 2001 From: David Grove Date: Tue, 21 Feb 2017 20:58:00 -0500 Subject: [PATCH 08/48] Linux fixes for dispatch-806 merge Collection of small fixes to dispatch-806 merge to allow code to compile/link/run on Linux. Signed-off-by: Daniel A. Steffen --- Makefile.am | 5 ---- os/linux_base.h | 10 ++++++++ src/Makefile.am | 5 ---- src/event/event_config.h | 1 - src/event/event_epoll.c | 49 +++++++++++++++++++++++++++------------- src/object.c | 2 ++ src/shims.h | 2 +- src/shims/atomic.h | 8 +++---- src/shims/priority.h | 1 + src/shims/time.h | 4 ++-- src/shims/tsd.h | 2 +- src/source.c | 4 ++-- 12 files changed, 56 insertions(+), 37 deletions(-) diff --git a/Makefile.am b/Makefile.am index 63c8b17aa..ffc82df29 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,10 +8,6 @@ if BUILD_OWN_PTHREAD_WORKQUEUES MAYBE_PTHREAD_WORKQUEUES = libpwq endif -if BUILD_OWN_KQUEUES - MAYBE_KQUEUES = libkqueue -endif - if BUILD_TESTS MAYBE_TESTS = tests endif @@ -19,7 +15,6 @@ endif SUBDIRS= \ dispatch \ $(MAYBE_PTHREAD_WORKQUEUES) \ - $(MAYBE_KQUEUES) \ man \ os \ private \ diff --git a/os/linux_base.h b/os/linux_base.h index 8173e12bf..d0048d615 100644 --- a/os/linux_base.h +++ b/os/linux_base.h @@ -17,8 +17,10 @@ #if __GNUC__ #define OS_EXPECT(x, v) __builtin_expect((x), (v)) +#define OS_UNUSED __attribute__((__unused__)) #else #define OS_EXPECT(x, v) (x) +#define OS_UNUSED #endif #ifndef os_likely @@ -67,6 +69,14 @@ #define __OS_CONCAT(x, y) x ## y #define OS_CONCAT(x, y) __OS_CONCAT(x, y) +#if __has_feature(objc_fixed_enum) || __has_extension(cxx_strong_enums) +#define OS_ENUM(_name, _type, ...) \ +typedef enum : _type { __VA_ARGS__ } _name##_t +#else +#define OS_ENUM(_name, _type, ...) \ +enum { __VA_ARGS__ }; typedef _type _name##_t +#endif + /* * Stub out misc linking and compilation attributes */ diff --git a/src/Makefile.am b/src/Makefile.am index a2cbe9e5f..a0ddbc98b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,11 +77,6 @@ AM_OBJCFLAGS=$(DISPATCH_CFLAGS) $(CBLOCKS_FLAGS) AM_CXXFLAGS=$(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 diff --git a/src/event/event_config.h b/src/event/event_config.h index 889fa9005..7f7761c32 100644 --- a/src/event/event_config.h +++ b/src/event/event_config.h @@ -133,7 +133,6 @@ # define EV_ONESHOT 0x0010 # define EV_CLEAR 0x0020 # define EV_DISPATCH 0x0080 -# define EV_UDATA_SPECIFIC 0x0100 # define EVFILT_READ (-1) # define EVFILT_WRITE (-2) diff --git a/src/event/event_epoll.c b/src/event/event_epoll.c index 53aff72c2..2788b1008 100644 --- a/src/event/event_epoll.c +++ b/src/event/event_epoll.c @@ -35,6 +35,8 @@ #error unsupported configuration #endif +#define DISPATCH_EPOLL_MAX_EVENT_COUNT 16 + enum { DISPATCH_EPOLL_EVENTFD = 0x0001, DISPATCH_EPOLL_CLOCK_WALL = 0x0002, @@ -47,8 +49,8 @@ typedef struct dispatch_muxnote_s { TAILQ_HEAD(, dispatch_unote_linkage_s) dmn_writers_head; int dmn_fd; int dmn_ident; + uint32_t dmn_events; int16_t dmn_filter; - int16_t dmn_events; bool dmn_socket_listener; } *dispatch_muxnote_t; @@ -60,6 +62,10 @@ typedef struct dispatch_epoll_timeout_s { } *dispatch_epoll_timeout_t; static int _dispatch_epfd, _dispatch_eventfd; + +static dispatch_once_t epoll_init_pred; +static void _dispatch_epoll_init(void *); + DISPATCH_CACHELINE_ALIGN static TAILQ_HEAD(dispatch_muxnote_bucket_s, dispatch_muxnote_s) _dispatch_sources[DSL_HASH_SIZE]; @@ -112,7 +118,7 @@ _dispatch_muxnote_dispose(dispatch_muxnote_t dmn) } static dispatch_muxnote_t -_dispatch_muxnote_create(dispatch_unote_t du, int16_t events) +_dispatch_muxnote_create(dispatch_unote_t du, uint32_t events) { dispatch_muxnote_t dmn; struct stat sb; @@ -173,6 +179,7 @@ _dispatch_muxnote_create(dispatch_unote_t du, int16_t events) static int _dispatch_epoll_update(dispatch_muxnote_t dmn, int op) { + dispatch_once_f(&epoll_init_pred, NULL, _dispatch_epoll_init); struct epoll_event ev = { .events = dmn->dmn_events, .data = { .ptr = dmn }, @@ -181,11 +188,12 @@ _dispatch_epoll_update(dispatch_muxnote_t dmn, int op) } bool -_dispatch_unote_register(dispatch_unote_t du, dispatch_priority_t pri) +_dispatch_unote_register(dispatch_unote_t du, dispatch_wlh_t wlh, + dispatch_priority_t pri) { struct dispatch_muxnote_bucket_s *dmb; dispatch_muxnote_t dmn; - int16_t events = EPOLLFREE; + uint32_t events = EPOLLFREE; dispatch_assert(!_dispatch_unote_registered(du)); du._du->du_priority = pri; @@ -194,7 +202,7 @@ _dispatch_unote_register(dispatch_unote_t du, dispatch_priority_t pri) case DISPATCH_EVFILT_CUSTOM_ADD: case DISPATCH_EVFILT_CUSTOM_OR: case DISPATCH_EVFILT_CUSTOM_REPLACE: - du._du->du_wlh = DISPATCH_WLH_GLOBAL; + du._du->du_wlh = wlh; return true; case EVFILT_WRITE: events |= EPOLLOUT; @@ -264,7 +272,7 @@ _dispatch_unote_unregister(dispatch_unote_t du, uint32_t flags) if (_dispatch_unote_registered(du)) { dispatch_unote_linkage_t dul = _dispatch_unote_get_linkage(du); dispatch_muxnote_t dmn = dul->du_muxnote; - int16_t events = dmn->dmn_events; + uint32_t events = dmn->dmn_events; if (du._du->du_filter == EVFILT_WRITE) { TAILQ_REMOVE(&dmn->dmn_writers_head, dul, du_link); @@ -300,8 +308,6 @@ _dispatch_unote_unregister(dispatch_unote_t du, uint32_t flags) static void _dispatch_event_merge_timer(dispatch_clock_t clock) { - int qos; - _dispatch_timers_expired = true; _dispatch_timers_processing_mask |= 1 << DISPATCH_TIMER_INDEX(clock, 0); #if DISPATCH_USE_DTRACE @@ -314,7 +320,6 @@ _dispatch_event_merge_timer(dispatch_clock_t clock) static void _dispatch_timeout_program(uint32_t tidx, uint64_t target, uint64_t leeway) { - uint32_t qos = DISPATCH_TIMER_QOS(tidx); dispatch_clock_t clock = DISPATCH_TIMER_CLOCK(tidx); dispatch_epoll_timeout_t timer = &_dispatch_epoll_timeout[clock]; struct epoll_event ev = { @@ -371,7 +376,7 @@ _dispatch_event_loop_timer_arm(uint32_t tidx, dispatch_timer_delay_s range, dispatch_clock_now_cache_t nows) { uint64_t target = range.delay; - target += _dispatch_time_cached_now(nows, DISPATCH_TIMER_CLOCK(tidx)); + target += _dispatch_time_now_cached(DISPATCH_TIMER_CLOCK(tidx), nows); _dispatch_timers_heap[tidx].dth_flags |= DTH_ARMED; _dispatch_timeout_program(tidx, target, range.leeway); } @@ -393,6 +398,13 @@ _dispatch_event_loop_atfork_child(void) void _dispatch_event_loop_init(void) { +} + +static void +_dispatch_epoll_init(void *context DISPATCH_UNUSED) +{ + _dispatch_fork_becomes_unsafe(); + unsigned int i; for (i = 0; i < DSL_HASH_SIZE; i++) { TAILQ_INIT(&_dispatch_sources[i]); @@ -413,15 +425,20 @@ _dispatch_event_loop_init(void) .data = { .u32 = DISPATCH_EPOLL_EVENTFD, }, }; unsigned long op = EPOLL_CTL_ADD; - if (epoll_ctl(_dispatch_eventfd, op, _dispatch_eventfd, &ev) < 0) { + if (epoll_ctl(_dispatch_epfd, op, _dispatch_eventfd, &ev) < 0) { DISPATCH_INTERNAL_CRASH(errno, "epoll_ctl() failed"); } + +#if DISPATCH_USE_MGR_THREAD + dx_push(_dispatch_mgr_q.do_targetq, &_dispatch_mgr_q, 0); +#endif } void _dispatch_event_loop_poke(dispatch_wlh_t wlh DISPATCH_UNUSED, dispatch_priority_t pri DISPATCH_UNUSED, uint32_t flags DISPATCH_UNUSED) { + dispatch_once_f(&epoll_init_pred, NULL, _dispatch_epoll_init); dispatch_assume_zero(eventfd_write(_dispatch_eventfd, 1)); } @@ -435,7 +452,7 @@ _dispatch_event_merge_signal(dispatch_muxnote_t dmn) TAILQ_FOREACH_SAFE(dul, &dmn->dmn_readers_head, du_link, dul_next) { dispatch_unote_t du = _dispatch_unote_linkage_get_unote(dul); - dux_merge_evt(du._du, EV_ADD|EV_ENABLE|EV_CLEAR, 1, 0); + dux_merge_evt(du._du, EV_ADD|EV_ENABLE|EV_CLEAR, 1, 0, 0); } } @@ -458,7 +475,7 @@ _dispatch_get_buffer_size(dispatch_muxnote_t dmn, bool writer) } static void -_dispatch_event_merge_fd(dispatch_muxnote_t dmn, int16_t events) +_dispatch_event_merge_fd(dispatch_muxnote_t dmn, uint32_t events) { dispatch_unote_linkage_t dul, dul_next; uintptr_t data; @@ -467,7 +484,7 @@ _dispatch_event_merge_fd(dispatch_muxnote_t dmn, int16_t events) data = _dispatch_get_buffer_size(dmn, false); TAILQ_FOREACH_SAFE(dul, &dmn->dmn_readers_head, du_link, dul_next) { dispatch_unote_t du = _dispatch_unote_linkage_get_unote(dul); - dux_merge_evt(du._du, EV_ADD|EV_ENABLE|EV_DISPATCH, ~data, 0); + dux_merge_evt(du._du, EV_ADD|EV_ENABLE|EV_DISPATCH, ~data, 0, 0); } } @@ -475,7 +492,7 @@ _dispatch_event_merge_fd(dispatch_muxnote_t dmn, int16_t events) data = _dispatch_get_buffer_size(dmn, true); TAILQ_FOREACH_SAFE(dul, &dmn->dmn_writers_head, du_link, dul_next) { dispatch_unote_t du = _dispatch_unote_linkage_get_unote(dul); - dux_merge_evt(du._du, EV_ADD|EV_ENABLE|EV_DISPATCH, ~data, 0); + dux_merge_evt(du._du, EV_ADD|EV_ENABLE|EV_DISPATCH, ~data, 0, 0); } } } @@ -484,7 +501,7 @@ DISPATCH_NOINLINE void _dispatch_event_loop_drain(uint32_t flags) { - struct epoll_event ev[DISPATCH_DEFERRED_ITEMS_EVENT_COUNT]; + struct epoll_event ev[DISPATCH_EPOLL_MAX_EVENT_COUNT]; int i, r; int timeout = (flags & KEVENT_FLAG_IMMEDIATE) ? 0 : -1; diff --git a/src/object.c b/src/object.c index c5c333b40..1ca41bc73 100644 --- a/src/object.c +++ b/src/object.c @@ -179,8 +179,10 @@ _dispatch_xref_dispose(dispatch_object_t dou) } if (dx_type(dou._do) == DISPATCH_SOURCE_KEVENT_TYPE) { _dispatch_source_xref_dispose(dou._ds); +#if HAVE_MACH } else if (dx_type(dou._do) == DISPATCH_MACH_CHANNEL_TYPE) { _dispatch_mach_xref_dispose(dou._dm); +#endif } else if (dx_type(dou._do) == DISPATCH_QUEUE_RUNLOOP_TYPE) { _dispatch_runloop_queue_xref_dispose(dou._dq); } diff --git a/src/shims.h b/src/shims.h index 8a79acac6..8434341ec 100644 --- a/src/shims.h +++ b/src/shims.h @@ -135,7 +135,7 @@ _pthread_qos_override_end_direct(mach_port_t thread, void *resource) #endif #if PTHREAD_WORKQUEUE_SPI_VERSION < 20160427 -bool +static inline bool _pthread_workqueue_should_narrow(pthread_priority_t priority) { (void)priority; diff --git a/src/shims/atomic.h b/src/shims/atomic.h index fae05b760..64af8b272 100644 --- a/src/shims/atomic.h +++ b/src/shims/atomic.h @@ -43,14 +43,14 @@ // This removes the _Atomic and volatile qualifiers on the type of *p #define _os_atomic_basetypeof(p) \ - typeof(atomic_load(_os_atomic_c11_atomic(p), memory_order_relaxed)) + typeof(atomic_load_explicit(_os_atomic_c11_atomic(p), memory_order_relaxed)) #define os_atomic_load(p, m) \ atomic_load_explicit(_os_atomic_c11_atomic(p), memory_order_##m) #define os_atomic_store(p, v, m) \ - atomic_store_explicit(_os_atomic_c11_atomic(p), _v, memory_order_##m) + atomic_store_explicit(_os_atomic_c11_atomic(p), v, memory_order_##m) #define os_atomic_xchg(p, v, m) \ - atomic_exchange_explicit(_os_atomic_c11_atomic(p), _v, memory_order_##m) + atomic_exchange_explicit(_os_atomic_c11_atomic(p), v, memory_order_##m) #define os_atomic_cmpxchg(p, e, v, m) \ ({ _os_atomic_basetypeof(p) _r = (e); \ atomic_compare_exchange_strong_explicit(_os_atomic_c11_atomic(p), \ @@ -69,7 +69,7 @@ atomic_fetch_##o##_explicit(_os_atomic_c11_atomic(p), _v, \ memory_order_##m); (typeof(*(p)))(_r op _v); }) #define _os_atomic_c11_op_orig(p, v, m, o, op) \ - atomic_fetch_##o##_explicit(_os_atomic_c11_atomic(p), _v, \ + atomic_fetch_##o##_explicit(_os_atomic_c11_atomic(p), v, \ memory_order_##m) #define os_atomic_add(p, v, m) \ _os_atomic_c11_op((p), (v), m, add, +) diff --git a/src/shims/priority.h b/src/shims/priority.h index 897d518ab..948e4c7af 100644 --- a/src/shims/priority.h +++ b/src/shims/priority.h @@ -66,6 +66,7 @@ typedef unsigned long pthread_priority_t; #define _PTHREAD_PRIORITY_DEFAULTQUEUE_FLAG 0x04000000 #define _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG 0x02000000 #define _PTHREAD_PRIORITY_NEEDS_UNBIND_FLAG 0x01000000 +#define _PTHREAD_PRIORITY_ENFORCE_FLAG 0x10000000 #endif // HAVE_PTHREAD_QOS_H diff --git a/src/shims/time.h b/src/shims/time.h index 761f33167..3010f08da 100644 --- a/src/shims/time.h +++ b/src/shims/time.h @@ -172,11 +172,11 @@ _dispatch_approximate_time(void) #if HAVE_MACH_APPROXIMATE_TIME return mach_approximate_time(); #elif HAVE_DECL_CLOCK_UPTIME_FAST && !defined(__linux__) - struct timesmec ts; + struct timespec ts; dispatch_assume_zero(clock_gettime(CLOCK_UPTIME_FAST, &ts)); return _dispatch_timespec_to_nano(ts); #elif defined(__linux__) - struct timesmec ts; + struct timespec ts; dispatch_assume_zero(clock_gettime(CLOCK_REALTIME_COARSE, &ts)); return _dispatch_timespec_to_nano(ts); #else diff --git a/src/shims/tsd.h b/src/shims/tsd.h index 91c675a62..f3d3cea5f 100644 --- a/src/shims/tsd.h +++ b/src/shims/tsd.h @@ -118,7 +118,7 @@ struct dispatch_tsd { #endif void *dispatch_priority_key; void *dispatch_r2k_key; - void *dispatch_wlh_key + void *dispatch_wlh_key; void *dispatch_voucher_key; void *dispatch_deferred_items_key; }; diff --git a/src/source.c b/src/source.c index 1e17fb8f7..c2020462c 100644 --- a/src/source.c +++ b/src/source.c @@ -134,8 +134,8 @@ dispatch_source_get_handle(dispatch_source_t ds) unsigned long dispatch_source_get_data(dispatch_source_t ds) { - dispatch_source_refs_t dr = ds->ds_refs; #if DISPATCH_USE_MEMORYSTATUS + dispatch_source_refs_t dr = ds->ds_refs; if (dr->du_vmpressure_override) { return NOTE_VM_PRESSURE; } @@ -2300,7 +2300,7 @@ _dispatch_mgr_invoke(void) #if DISPATCH_EVENT_BACKEND_KEVENT ddi.ddi_nevents = 0; #endif - _dispatch_set_wlh(DISPATCH_WLH_GLOBAL); + dispatch_assert(_dispatch_get_wlh() == DISPATCH_WLH_GLOBAL); _dispatch_deferred_items_set(&ddi); for (;;) { From 155406d34c481737a7286d62de9b14898cb1c846 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Tue, 21 Feb 2017 19:34:05 -0800 Subject: [PATCH 09/48] Merge pull request #216 from dgrove-oss/das-darwin-libdispatch-806-merge-master-linux-fixes Linux fixes for dispatch-806 merge Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index ff022631e..a0ceca7eb 100644 --- a/PATCHES +++ b/PATCHES @@ -313,3 +313,4 @@ github commits starting with 29bdc2f from [ba4cac5] APPLIED rdar://30568673 [7974138] APPLIED rdar://30568673 [cd12dcb] APPLIED rdar://32283666 +[ff05109] APPLIED rdar://32283666 From 1263468f06beb4dc6700d9e7ef66a74b2aff39c9 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 22 Feb 2017 10:06:49 -0800 Subject: [PATCH 10/48] provide fallback definitions for all API_* macros Signed-off-by: Daniel A. Steffen --- dispatch/dispatch.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index 52cd3e707..585940cc0 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -24,14 +24,20 @@ #ifdef __APPLE__ #include #include -#endif - +#else #ifndef API_AVAILABLE #define API_AVAILABLE(...) +#endif +#ifndef API_DEPRECATED #define API_DEPRECATED(...) +#endif +#ifndef API_UNAVAILABLE #define API_UNAVAILABLE(...) +#endif +#ifndef API_DEPRECATED_WITH_REPLACEMENT #define API_DEPRECATED_WITH_REPLACEMENT(...) -#endif // !API_AVAILABLE +#endif +#endif // __APPLE__ #include #include From 27c57a9e8ddd9aedd31a11c28de311b6f7fffa0d Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 22 Feb 2017 10:10:53 -0800 Subject: [PATCH 11/48] Merge pull request #218 from apple/das-api-availability-build-fix provide fallback definitions for all API_* macros Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index a0ceca7eb..4b5588784 100644 --- a/PATCHES +++ b/PATCHES @@ -314,3 +314,4 @@ github commits starting with 29bdc2f from [7974138] APPLIED rdar://30568673 [cd12dcb] APPLIED rdar://32283666 [ff05109] APPLIED rdar://32283666 +[73315ee] APPLIED rdar://32283666 From 430623fd40c45e7149b271a18356b78d69b66698 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 22 Feb 2017 12:33:57 -0800 Subject: [PATCH 12/48] remove unused dependency on linux/membarrier.h for intel to fix CI build add dependency on linux-libc-dev to INSTALL.md for other architectures Signed-off-by: Daniel A. Steffen --- INSTALL.md | 9 +-------- src/shims/lock.h | 2 ++ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 410aefa9b..3ab606bd1 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -152,14 +152,7 @@ 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` - - 1c. Install additional libdispatch dependencies - `sudo apt-get install libblocksruntime-dev libbsd-dev` + `sudo apt-get install autoconf libtool pkg-config clang systemtap-sdt-dev libbsd-dev linux-libc-dev` Note: compiling libdispatch requires clang 3.8 or better and the gold linker. If the default clang on your Ubuntu version is diff --git a/src/shims/lock.h b/src/shims/lock.h index 22382cff6..a22517e6e 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -89,7 +89,9 @@ _dispatch_lock_has_failed_trylock(dispatch_lock lock_value) #elif defined(__linux__) #include +#if !defined(__x86_64__) && !defined(__i386__) #include +#endif #include #include /* For SYS_xxx definitions */ From 65840901404ae3b29ba603dc98cec990f66f7e46 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 22 Feb 2017 12:38:57 -0800 Subject: [PATCH 13/48] Merge pull request #221 from apple/das-disable-linux-membarrier-include remove unused dependency on linux/membarrier.h for intel to fix CI build Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 4b5588784..e0b08e530 100644 --- a/PATCHES +++ b/PATCHES @@ -315,3 +315,4 @@ github commits starting with 29bdc2f from [cd12dcb] APPLIED rdar://32283666 [ff05109] APPLIED rdar://32283666 [73315ee] APPLIED rdar://32283666 +[fcc1924] APPLIED rdar://32283666 From 1b5bc31d6b82c5bbbbfcc0385543c8e46ecc6ee5 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 23 Feb 2017 13:02:18 -0800 Subject: [PATCH 14/48] queue_specific_queue is missing its do_push vtable entry Also reorder all vtable entries to be in the same order (push, invoke, wakeup). Reenable dispatch_context_for_key. SR: SR-4039 Signed-off-by: Daniel A. Steffen --- src/init.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/init.c b/src/init.c index 29d8c4e97..a04daeb96 100644 --- a/src/init.c +++ b/src/init.c @@ -398,6 +398,7 @@ DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_root, queue, .do_kind = "global-queue", .do_dispose = _dispatch_pthread_root_queue_dispose, .do_push = _dispatch_root_queue_push, + .do_invoke = NULL, .do_wakeup = _dispatch_root_queue_wakeup, .do_debug = dispatch_queue_debug, ); @@ -406,8 +407,8 @@ DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_main, queue, .do_type = DISPATCH_QUEUE_SERIAL_TYPE, .do_kind = "main-queue", .do_dispose = _dispatch_queue_dispose, - .do_invoke = _dispatch_queue_invoke, .do_push = _dispatch_queue_push, + .do_invoke = _dispatch_queue_invoke, .do_wakeup = _dispatch_main_queue_wakeup, .do_debug = dispatch_queue_debug, ); @@ -416,8 +417,8 @@ DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_runloop, queue, .do_type = DISPATCH_QUEUE_RUNLOOP_TYPE, .do_kind = "runloop-queue", .do_dispose = _dispatch_runloop_queue_dispose, - .do_invoke = _dispatch_queue_invoke, .do_push = _dispatch_queue_push, + .do_invoke = _dispatch_queue_invoke, .do_wakeup = _dispatch_runloop_queue_wakeup, .do_debug = dispatch_queue_debug, ); @@ -425,8 +426,8 @@ DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_runloop, queue, DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_mgr, queue, .do_type = DISPATCH_QUEUE_MGR_TYPE, .do_kind = "mgr-queue", - .do_invoke = _dispatch_mgr_thread, .do_push = _dispatch_queue_push, + .do_invoke = _dispatch_mgr_thread, .do_wakeup = _dispatch_mgr_queue_wakeup, .do_debug = dispatch_queue_debug, ); @@ -435,6 +436,7 @@ DISPATCH_VTABLE_INSTANCE(queue_specific_queue, .do_type = DISPATCH_QUEUE_SPECIFIC_TYPE, .do_kind = "queue-context", .do_dispose = _dispatch_queue_specific_queue_dispose, + .do_push = (void *)_dispatch_queue_push, .do_invoke = (void *)_dispatch_queue_invoke, .do_wakeup = (void *)_dispatch_queue_wakeup, .do_debug = (void *)dispatch_queue_debug, From ab9652e42521908d035230162d1cc2b6c5f65ea7 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 23 Feb 2017 18:24:43 -0800 Subject: [PATCH 15/48] Merge pull request #223 from apple/eng/PR-SR-4039 queue_specific_queue is missing its do_push vtable entry Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index e0b08e530..17c99d3ea 100644 --- a/PATCHES +++ b/PATCHES @@ -316,3 +316,4 @@ github commits starting with 29bdc2f from [ff05109] APPLIED rdar://32283666 [73315ee] APPLIED rdar://32283666 [fcc1924] APPLIED rdar://32283666 +[272e818] APPLIED rdar://32283666 From afa3ac5507fffe858ed5fee5692f50ad42070aae Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 24 Feb 2017 13:20:59 -0500 Subject: [PATCH 16/48] fixes for compiler warnings Collection of small fixes to eliminate compiler warnings when building libdispatch and its tests. Signed-off-by: Daniel A. Steffen --- src/BlocksRuntime/data.c | 2 +- src/BlocksRuntime/runtime.c | 6 ++++++ src/source.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/BlocksRuntime/data.c b/src/BlocksRuntime/data.c index 083717648..dd36051d9 100644 --- a/src/BlocksRuntime/data.c +++ b/src/BlocksRuntime/data.c @@ -14,7 +14,7 @@ We allocate space and export a symbol to be used as the Class for the on-stack a We keep these in a separate file so that we can include the runtime code in test subprojects but not include the data so that compiled code that sees the data in libSystem doesn't get confused by a second copy. Somehow these don't get unified in a common block. **********************/ -#define BLOCK_EXPORT extern __attribute__((visibility("default"))) +#define BLOCK_EXPORT __attribute__((visibility("default"))) BLOCK_EXPORT void * _NSConcreteStackBlock[32] = { 0 }; BLOCK_EXPORT void * _NSConcreteMallocBlock[32] = { 0 }; diff --git a/src/BlocksRuntime/runtime.c b/src/BlocksRuntime/runtime.c index 164fe6ef6..8ec64cdc2 100644 --- a/src/BlocksRuntime/runtime.c +++ b/src/BlocksRuntime/runtime.c @@ -53,9 +53,11 @@ static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile Globals ************************/ +#if HAVE_OBJC static void *_Block_copy_class = _NSConcreteMallocBlock; static void *_Block_copy_finalizing_class = _NSConcreteMallocBlock; static int _Block_copy_flag = BLOCK_NEEDS_FREE; +#endif static int _Byref_flag_initial_value = BLOCK_BYREF_NEEDS_FREE | 4; // logical 2 static bool isGC = false; @@ -156,7 +158,9 @@ static void _Block_assign_default(void *value, void **destptr) { static void _Block_setHasRefcount_default(const void *ptr, const bool hasRefcount) { } +#if HAVE_OBJC static void _Block_do_nothing(const void *aBlock) { } +#endif static void _Block_retain_object_default(const void *ptr) { } @@ -176,6 +180,7 @@ static void _Block_memmove_default(void *dst, void *src, unsigned long size) { memmove(dst, src, (size_t)size); } +#if HAVE_OBJC static void _Block_memmove_gc_broken(void *dest, void *src, unsigned long size) { void **destp = (void **)dest; void **srcp = (void **)src; @@ -186,6 +191,7 @@ static void _Block_memmove_gc_broken(void *dest, void *src, unsigned long size) size -= sizeof(void *); } } +#endif static void _Block_destructInstance_default(const void *aBlock) {} diff --git a/src/source.c b/src/source.c index c2020462c..7c85c74bf 100644 --- a/src/source.c +++ b/src/source.c @@ -2515,7 +2515,7 @@ _dispatch_source_debug_attr(dispatch_source_t ds, char* buf, size_t bufsiz) "mask = 0x%x, pending_data = 0x%llx, registered = %d, " "armed = %d, deleted = %d%s, canceled = %d, ", target && target->dq_label ? target->dq_label : "", target, - dr->du_ident, dr->du_fflags, ds->ds_pending_data, + dr->du_ident, dr->du_fflags, (unsigned long long)ds->ds_pending_data, ds->ds_is_installed, (bool)(ds->dq_atomic_flags & DSF_ARMED), (bool)(ds->dq_atomic_flags & DSF_DELETED), (ds->dq_atomic_flags & DSF_DEFERRED_DELETE) ? " (pending)" : "", From 69118be11ea308b88abb2977c57850bfcd8837ec Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sat, 25 Feb 2017 23:19:59 -0800 Subject: [PATCH 17/48] Merge pull request #226 from dgrove-oss/fix-compiler-warnings fixes for compiler warnings Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 17c99d3ea..f315daeaa 100644 --- a/PATCHES +++ b/PATCHES @@ -317,3 +317,4 @@ github commits starting with 29bdc2f from [73315ee] APPLIED rdar://32283666 [fcc1924] APPLIED rdar://32283666 [272e818] APPLIED rdar://32283666 +[b6f8908] APPLIED rdar://32283666 From 2590ec70a5f89bb5c464d32b3ad3b5cac8e01834 Mon Sep 17 00:00:00 2001 From: Kim Topley Date: Tue, 28 Feb 2017 10:48:23 -0800 Subject: [PATCH 18/48] Adding DISPATCH_SOURCE_TYPE_DATA_REPLACE to the Swift overlay (Radar rdar://problem/30518517) Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + src/swift/Dispatch.apinotes | 2 ++ src/swift/DispatchStubs.cc | 3 +++ src/swift/Source.swift | 48 +++++++++++++++++++++---------------- src/swift/Wrapper.swift | 6 ++++- 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/PATCHES b/PATCHES index f315daeaa..9b728f1c2 100644 --- a/PATCHES +++ b/PATCHES @@ -318,3 +318,4 @@ github commits starting with 29bdc2f from [fcc1924] APPLIED rdar://32283666 [272e818] APPLIED rdar://32283666 [b6f8908] APPLIED rdar://32283666 +[a6c16d0] APPLIED rdar://32283666 diff --git a/src/swift/Dispatch.apinotes b/src/swift/Dispatch.apinotes index 6e804515a..d40bb68a4 100644 --- a/src/swift/Dispatch.apinotes +++ b/src/swift/Dispatch.apinotes @@ -91,6 +91,8 @@ Protocols: SwiftName: DispatchSourceUserDataOr - Name: OS_dispatch_source_data_add SwiftName: DispatchSourceUserDataAdd +- Name: OS_dispatch_source_data_replace + SwiftName: DispatchSourceUserDataReplace - Name: OS_dispatch_source_vnode SwiftName: DispatchSourceFileSystemObject - Name: OS_dispatch_source_write diff --git a/src/swift/DispatchStubs.cc b/src/swift/DispatchStubs.cc index c81768ab8..2c76b7b47 100644 --- a/src/swift/DispatchStubs.cc +++ b/src/swift/DispatchStubs.cc @@ -26,6 +26,7 @@ @protocol OS_dispatch_source_timer; @protocol OS_dispatch_source_data_add; @protocol OS_dispatch_source_data_or; +@protocol OS_dispatch_source_data_replace; @protocol OS_dispatch_source_vnode; @protocol OS_dispatch_source_write; @@ -44,6 +45,7 @@ static void _dispatch_overlay_constructor() { 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_data_replace)); class_addProtocol(source, @protocol(OS_dispatch_source_vnode)); class_addProtocol(source, @protocol(OS_dispatch_source_write)); } @@ -186,6 +188,7 @@ _swift_dispatch_retain(dispatch_object_t obj) { SOURCE(DATA_ADD) SOURCE(DATA_OR) +SOURCE(DATA_REPLACE) #if HAVE_MACH SOURCE(MACH_SEND) SOURCE(MACH_RECV) diff --git a/src/swift/Source.swift b/src/swift/Source.swift index 801ae71e3..a3a7e7903 100644 --- a/src/swift/Source.swift +++ b/src/swift/Source.swift @@ -201,6 +201,11 @@ public extension DispatchSource { let source = dispatch_source_create(_swift_dispatch_source_type_data_or(), 0, 0, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceUserDataOr } + + public class func makeUserDataReplaceSource(queue: DispatchQueue? = nil) -> DispatchSourceUserDataReplace { + let source = dispatch_source_create(_swift_dispatch_source_type_data_replace(), 0, 0, queue?.__wrapped) + return DispatchSource(source: source) as DispatchSourceUserDataReplace + } #if !os(Linux) && !os(Android) public class func makeFileSystemObjectSource(fileDescriptor: Int32, eventMask: FileSystemEvent, queue: DispatchQueue? = nil) -> DispatchSourceFileSystemObject { @@ -318,45 +323,48 @@ public extension DispatchSourceFileSystemObject { #endif 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. + /// Merges data into a dispatch source of type `DISPATCH_SOURCE_TYPE_DATA_ADD` + /// 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. + /// - parameter data: the value to add to the current pending data. A value of zero + /// has no effect and will not result in the submission of the event handler block. public func add(data: UInt) { dispatch_source_merge_data((self as! DispatchSource).__wrapped, data) } } 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. + /// Merges data into a dispatch source of type `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. + /// - parameter data: The value to OR into the current pending data. A value of zero + /// has no effect and will not result in the submission of the event handler block. public func or(data: UInt) { dispatch_source_merge_data((self as! DispatchSource).__wrapped, data) } } +public extension DispatchSourceUserDataReplace { + /// Merges data into a dispatch source of type `DISPATCH_SOURCE_TYPE_DATA_REPLACE` + /// and submits its event handler block to its target queue. + /// + /// - parameter data: The value that will replace the current pending data. + /// A value of zero will be stored but will not result in the submission of the event + /// handler block. + public func replace(data: UInt) { + dispatch_source_merge_data((self as! DispatchSource).__wrapped, data) + } +} + @_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_DATA_REPLACE") +internal func _swift_dispatch_source_type_data_replace() -> 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 diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index ece006d6b..5a551dfba 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -158,7 +158,7 @@ public class DispatchSource : DispatchObject, DispatchSourceProtocol, DispatchSourceRead, DispatchSourceSignal, DispatchSourceTimer, DispatchSourceUserDataAdd, DispatchSourceUserDataOr, - DispatchSourceWrite { + DispatchSourceUserDataReplace, DispatchSourceWrite { internal let __wrapped:dispatch_source_t final internal override func wrapped() -> dispatch_object_t { @@ -243,6 +243,10 @@ public protocol DispatchSourceUserDataOr : DispatchSourceProtocol { func or(data: UInt) } +public protocol DispatchSourceUserDataReplace : DispatchSourceProtocol { + func replace(data: UInt) +} + #if HAVE_MACH public protocol DispatchSourceMachSend : DispatchSourceProtocol { public var handle: mach_port_t { get } From 426c007572a9e4226871e53146c516e690921fa3 Mon Sep 17 00:00:00 2001 From: Kim Topley Date: Wed, 8 Mar 2017 16:50:53 -0800 Subject: [PATCH 19/48] Add support for UnsafeRawBufferPointer to DispatchData (Radar 30699743) Signed-off-by: Daniel A. Steffen --- src/swift/Data.swift | 59 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index e0b7263c9..afd8b4d0a 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -49,6 +49,7 @@ public struct DispatchData : RandomAccessCollection { /// Initialize a `Data` with copied memory content. /// /// - parameter bytes: A pointer to the memory. It will be copied. + @available(swift, deprecated: 4, message: "Use init(bytes: UnsafeRawBufferPointer) instead") public init(bytes buffer: UnsafeBufferPointer) { let d = buffer.baseAddress == nil ? _swift_dispatch_data_empty() : dispatch_data_create(buffer.baseAddress!, buffer.count, nil, @@ -56,10 +57,22 @@ public struct DispatchData : RandomAccessCollection { self.init(data: d) } + /// 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: UnsafeRawBufferPointer) { + let d = buffer.baseAddress == nil ? _swift_dispatch_data_empty() + : dispatch_data_create(buffer.baseAddress!, buffer.count, nil, + _dispatch_data_destructor_default()) + self.init(data: d) + } + /// Initialize a `Data` without copying the bytes. /// /// - parameter bytes: A buffer pointer containing the data. /// - parameter deallocator: Specifies the mechanism to free the indicated buffer. + @available(swift, deprecated: 4, message: "Use init(bytes: UnsafeRawBufferPointer, deallocater: Deallocator) instead") public init(bytesNoCopy bytes: UnsafeBufferPointer, deallocator: Deallocator = .free) { let (q, b) = deallocator._deallocator let d = bytes.baseAddress == nil ? _swift_dispatch_data_empty() @@ -67,6 +80,18 @@ public struct DispatchData : RandomAccessCollection { self.init(data: d) } + /// 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: UnsafeRawBufferPointer, deallocator: Deallocator = .free) { + let (q, b) = deallocator._deallocator + let d = bytes.baseAddress == nil ? _swift_dispatch_data_empty() + : dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b) + self.init(data: d) + } + internal init(data: dispatch_data_t) { __wrapped = __DispatchData(data: data, owned: true) } @@ -113,11 +138,23 @@ public struct DispatchData : RandomAccessCollection { /// /// - parameter bytes: A pointer to the bytes to copy in to the data. /// - parameter count: The number of bytes to copy. + @available(swift, deprecated: 4, message: "Use append(_: UnsafeRawBufferPointer) instead") 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 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: UnsafeRawBufferPointer) { + // Nil base address does nothing. + guard bytes.baseAddress != nil else { return } + let data = dispatch_data_create(bytes.baseAddress!, 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. @@ -156,19 +193,41 @@ public struct DispatchData : RandomAccessCollection { /// - 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. + @available(swift, deprecated: 4, message: "Use copyBytes(to: UnsafeMutableRawBufferPointer, count: Int) instead") public func copyBytes(to pointer: UnsafeMutablePointer, count: Int) { _copyBytesHelper(to: pointer, from: 0..) instead") public func copyBytes(to pointer: UnsafeMutablePointer, from range: CountableRange) { _copyBytesHelper(to: pointer, from: range) } + /// Copy a subset of the contents of the data to a pointer. + /// + /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. + /// - parameter range: The range in the `Data` to copy. + /// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes. + public func copyBytes(to pointer: UnsafeMutableRawBufferPointer, from range: CountableRange) { + guard pointer.baseAddress != nil else { return } + _copyBytesHelper(to: pointer.baseAddress!, 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 `MemoryLayout.stride * buffer.count` then the first N bytes will be copied into the buffer. From 3b5ffaf7a117657eef6acd295ea53531b967627e Mon Sep 17 00:00:00 2001 From: Kim Topley Date: Fri, 10 Mar 2017 10:57:46 -0800 Subject: [PATCH 20/48] Review comments. Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + src/swift/Data.swift | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/PATCHES b/PATCHES index 9b728f1c2..ba47ce206 100644 --- a/PATCHES +++ b/PATCHES @@ -319,3 +319,4 @@ github commits starting with 29bdc2f from [272e818] APPLIED rdar://32283666 [b6f8908] APPLIED rdar://32283666 [a6c16d0] APPLIED rdar://32283666 +[1cc64e1] APPLIED rdar://32283666 diff --git a/src/swift/Data.swift b/src/swift/Data.swift index afd8b4d0a..1e7350463 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -72,7 +72,7 @@ public struct DispatchData : RandomAccessCollection { /// /// - parameter bytes: A buffer pointer containing the data. /// - parameter deallocator: Specifies the mechanism to free the indicated buffer. - @available(swift, deprecated: 4, message: "Use init(bytes: UnsafeRawBufferPointer, deallocater: Deallocator) instead") + @available(swift, deprecated: 4, message: "Use init(bytesNoCopy: UnsafeRawBufferPointer, deallocater: Deallocator) instead") public init(bytesNoCopy bytes: UnsafeBufferPointer, deallocator: Deallocator = .free) { let (q, b) = deallocator._deallocator let d = bytes.baseAddress == nil ? _swift_dispatch_data_empty() @@ -200,10 +200,11 @@ public struct DispatchData : RandomAccessCollection { /// Copy the contents of the data to a pointer. /// - /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. + /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. The buffer must be large + /// enough to hold `count` bytes. /// - 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: UnsafeMutableRawBufferPointer, count: Int) { + assert(count <= pointer.count, "Buffer too small to copy \(count) bytes") guard pointer.baseAddress != nil else { return } _copyBytesHelper(to: pointer.baseAddress!, from: 0..) { + assert(range.count <= pointer.count, "Buffer too small to copy \(range.count) bytes") guard pointer.baseAddress != nil else { return } _copyBytesHelper(to: pointer.baseAddress!, from: range) } From b281c519facc8c31a669fca920cdd666f5565133 Mon Sep 17 00:00:00 2001 From: Kim Topley Date: Fri, 17 Mar 2017 14:00:06 -0700 Subject: [PATCH 21/48] Makes the DispatchIO initializer that accepts a path failable, reflecting the fact that a relative or non-existent path is invalid. (Radar 31115994) Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + src/swift/IO.swift | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/PATCHES b/PATCHES index ba47ce206..6b89f8bcf 100644 --- a/PATCHES +++ b/PATCHES @@ -320,3 +320,4 @@ github commits starting with 29bdc2f from [b6f8908] APPLIED rdar://32283666 [a6c16d0] APPLIED rdar://32283666 [1cc64e1] APPLIED rdar://32283666 +[d137aa4] APPLIED rdar://32283666 diff --git a/src/swift/IO.swift b/src/swift/IO.swift index 8ce417aa7..d26f64160 100644 --- a/src/swift/IO.swift +++ b/src/swift/IO.swift @@ -55,6 +55,7 @@ public extension DispatchIO { self.init(__type: type.rawValue, fd: fileDescriptor, queue: queue, handler: cleanupHandler) } + @available(swift, obsoleted: 4) public convenience init( type: StreamType, path: UnsafePointer, @@ -66,6 +67,18 @@ public extension DispatchIO { self.init(__type: type.rawValue, path: path, oflag: oflag, mode: mode, queue: queue, handler: cleanupHandler) } + @available(swift, introduced: 4) + public convenience init?( + type: StreamType, + path: UnsafePointer, + oflag: Int32, + mode: mode_t, + queue: DispatchQueue, + cleanupHandler: @escaping (_ 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, From 3fd71ebd7a592b16afaa96cec9b069e89d04ae84 Mon Sep 17 00:00:00 2001 From: Vivian Kong Date: Mon, 3 Apr 2017 09:39:58 -0400 Subject: [PATCH 22/48] Fix compile error on s390x in shims/lock.h. s390x has a strong memory model and does not require membarrier. Signed-off-by: Daniel A. Steffen --- src/shims/lock.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shims/lock.h b/src/shims/lock.h index a22517e6e..3178793a9 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -89,7 +89,7 @@ _dispatch_lock_has_failed_trylock(dispatch_lock lock_value) #elif defined(__linux__) #include -#if !defined(__x86_64__) && !defined(__i386__) +#if !defined(__x86_64__) && !defined(__i386__) && !defined(__s390x__) #include #endif #include @@ -542,8 +542,9 @@ DISPATCH_ALWAYS_INLINE static inline dispatch_once_t _dispatch_once_xchg_done(dispatch_once_t *pred) { -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(__s390x__) // On Intel, any load is a load-acquire, so we don't need to be fancy + // same for s390x return os_atomic_xchg(pred, DLOCK_ONCE_DONE, release); #elif defined(__linux__) if (unlikely(syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0) < 0)) { From 0c49ad7976ad67540f0bb2974fd0576760785175 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 5 Apr 2017 09:18:45 -0700 Subject: [PATCH 23/48] Merge pull request #234 from linux-on-ibm-z/fix_compile_error Fix compile error on s390x in shims/lock.h Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 6b89f8bcf..5a6db5a79 100644 --- a/PATCHES +++ b/PATCHES @@ -321,3 +321,4 @@ github commits starting with 29bdc2f from [a6c16d0] APPLIED rdar://32283666 [1cc64e1] APPLIED rdar://32283666 [d137aa4] APPLIED rdar://32283666 +[a69853f] APPLIED rdar://32283666 From 34203e3e82f77df58e183e56303972329f3d1eeb Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Fri, 7 Apr 2017 17:09:26 -0700 Subject: [PATCH 24/48] libdispatch: Avoid submodules for headers that should not be included libdispatch has an umbrella header, dispatch.h, that should be used for including all of the other headers. This is enforced via __DISPATCH_INDIRECT__. Since it isn't legal to include one of the other headers on their own, it isn't logical to have submodules for them. Moreover, submodules *should* have local visibility (be unaware of the context they're included from); meaning that __DISPATCH_INDIRECT__ will never be defined. Logically, all of the headers are part of a single module/interface. Patch by me & Duncan P. Exon Smith Signed-off-by: Daniel A. Steffen --- dispatch/darwin/module.modulemap | 1 - dispatch/generic/module.modulemap | 1 - private/darwin/module.modulemap | 1 - private/generic/module.modulemap | 1 - 4 files changed, 4 deletions(-) diff --git a/dispatch/darwin/module.modulemap b/dispatch/darwin/module.modulemap index addaae436..e30807f91 100644 --- a/dispatch/darwin/module.modulemap +++ b/dispatch/darwin/module.modulemap @@ -1,6 +1,5 @@ module Dispatch [system] [extern_c] { umbrella header "dispatch.h" - module * { export * } export * } diff --git a/dispatch/generic/module.modulemap b/dispatch/generic/module.modulemap index 5c248e5c8..8c3e7d016 100644 --- a/dispatch/generic/module.modulemap +++ b/dispatch/generic/module.modulemap @@ -11,7 +11,6 @@ module DispatchIntrospection [system] [extern_c] { module CDispatch [system] [extern_c] { umbrella header "dispatch.h" - module * { export * } export * requires blocks link "dispatch" diff --git a/private/darwin/module.modulemap b/private/darwin/module.modulemap index 62975a59b..ceb963a1f 100644 --- a/private/darwin/module.modulemap +++ b/private/darwin/module.modulemap @@ -1,7 +1,6 @@ module DispatchPrivate [system] [extern_c] { umbrella header "private.h" exclude header "mach_private.h" - module * { export * } export * } diff --git a/private/generic/module.modulemap b/private/generic/module.modulemap index 62975a59b..ceb963a1f 100644 --- a/private/generic/module.modulemap +++ b/private/generic/module.modulemap @@ -1,7 +1,6 @@ module DispatchPrivate [system] [extern_c] { umbrella header "private.h" exclude header "mach_private.h" - module * { export * } export * } From 446f7b85b240537733d0e588423e569e4c7c676c Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Tue, 11 Apr 2017 16:56:05 -0700 Subject: [PATCH 25/48] Merge pull request #236 from bcardosolopes/master libdispatch: Avoid submodules for headers that should not be included Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 5a6db5a79..43803e427 100644 --- a/PATCHES +++ b/PATCHES @@ -322,3 +322,4 @@ github commits starting with 29bdc2f from [1cc64e1] APPLIED rdar://32283666 [d137aa4] APPLIED rdar://32283666 [a69853f] APPLIED rdar://32283666 +[eea0667] APPLIED rdar://32283666 From bacc2aa69d9a4a5526730c72975b81e77f666a1a Mon Sep 17 00:00:00 2001 From: Kim Topley Date: Wed, 12 Apr 2017 13:32:24 -0700 Subject: [PATCH 26/48] Port changes from swift repository. (Radar 31585625) Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + src/swift/Time.swift | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/PATCHES b/PATCHES index 43803e427..e7f211332 100644 --- a/PATCHES +++ b/PATCHES @@ -323,3 +323,4 @@ github commits starting with 29bdc2f from [d137aa4] APPLIED rdar://32283666 [a69853f] APPLIED rdar://32283666 [eea0667] APPLIED rdar://32283666 +[f84d21d] APPLIED rdar://32283666 diff --git a/src/swift/Time.swift b/src/swift/Time.swift index 0b07742e6..8178ffd6c 100644 --- a/src/swift/Time.swift +++ b/src/swift/Time.swift @@ -17,6 +17,14 @@ import CDispatch public struct DispatchTime : Comparable { +#if HAVE_MACH + private static let timebaseInfo: mach_timebase_info_data_t = { + var info = mach_timebase_info_data_t(numer: 1, denom: 1) + mach_timebase_info(&info) + return info + }() +#endif + public let rawValue: dispatch_time_t public static func now() -> DispatchTime { @@ -39,16 +47,34 @@ public struct DispatchTime : Comparable { /// - Returns: A new `DispatchTime` /// - Discussion: This clock is the same as the value returned by /// `mach_absolute_time` when converted into nanoseconds. + /// On some platforms, the nanosecond value is rounded up to a + /// multiple of the Mach timebase, using the conversion factors + /// returned by `mach_timebase_info()`. The nanosecond equivalent + /// of the rounded result can be obtained by reading the + /// `uptimeNanoseconds` property. /// Note that `DispatchTime(uptimeNanoseconds: 0)` is /// equivalent to `DispatchTime.now()`, that is, its value /// represents the number of nanoseconds since boot (excluding /// system sleep time), not zero nanoseconds since boot. public init(uptimeNanoseconds: UInt64) { - self.rawValue = dispatch_time_t(uptimeNanoseconds) + var rawValue = uptimeNanoseconds +#if HAVE_MACH + if (DispatchTime.timebaseInfo.numer != DispatchTime.timebaseInfo.denom) { + rawValue = (rawValue * UInt64(DispatchTime.timebaseInfo.denom) + + UInt64(DispatchTime.timebaseInfo.numer - 1)) / UInt64(DispatchTime.timebaseInfo.numer) + } +#endif + self.rawValue = dispatch_time_t(rawValue) } public var uptimeNanoseconds: UInt64 { - return UInt64(self.rawValue) + var result = self.rawValue +#if HAVE_MACH + if (DispatchTime.timebaseInfo.numer != DispatchTime.timebaseInfo.denom) { + result = result * UInt64(DispatchTime.timebaseInfo.numer) / UInt64(DispatchTime.timebaseInfo.denom) + } +#endif + return result } } @@ -81,8 +107,12 @@ public struct DispatchWallTime : Comparable { } public func <(a: DispatchWallTime, b: DispatchWallTime) -> Bool { - if a.rawValue == ~0 || b.rawValue == ~0 { return false } - return -Int64(a.rawValue) < -Int64(b.rawValue) + if b.rawValue == ~0 { + return a.rawValue != ~0 + } else if a.rawValue == ~0 { + return false + } + return -Int64(bitPattern: a.rawValue) < -Int64(bitPattern: b.rawValue) } public func ==(a: DispatchWallTime, b: DispatchWallTime) -> Bool { @@ -147,7 +177,7 @@ public func +(time: DispatchWallTime, seconds: Double) -> DispatchWallTime { } public func -(time: DispatchWallTime, seconds: Double) -> DispatchWallTime { - let interval = seconds * Double(NSEC_PER_SEC) + let interval = -seconds * Double(NSEC_PER_SEC) let t = CDispatch.dispatch_time(time.rawValue, interval.isInfinite || interval.isNaN ? Int64.min : Int64(interval)) return DispatchWallTime(rawValue: t) From f6cb5946fc26b7e299faaecd567d6d275898acd8 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 28 Dec 2016 13:38:44 -0800 Subject: [PATCH 27/48] build: add a cmake based build system This is far from complete, but is sufficient to build a Linux version of libdispatch. It shows what a potential cmake based build system could look like, and if desired can be completed to build all the various flavours with cmake. Signed-off-by: Daniel A. Steffen --- CMakeLists.txt | 202 ++++++++++++++++++ cmake/config.h.in | 248 +++++++++++++++++++++++ cmake/modules/DispatchAppleOptions.cmake | 43 ++++ cmake/modules/FindLibRT.cmake | 39 ++++ dispatch/CMakeLists.txt | 24 +++ man/CMakeLists.txt | 23 +++ os/CMakeLists.txt | 10 + private/CMakeLists.txt | 5 + src/CMakeLists.txt | 117 +++++++++++ 9 files changed, 711 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cmake/config.h.in create mode 100644 cmake/modules/DispatchAppleOptions.cmake create mode 100644 cmake/modules/FindLibRT.cmake create mode 100644 dispatch/CMakeLists.txt create mode 100644 man/CMakeLists.txt create mode 100644 os/CMakeLists.txt create mode 100644 private/CMakeLists.txt create mode 100644 src/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..08f6fc17d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,202 @@ + +cmake_minimum_required(VERSION 3.4.3) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") + +project(dispatch + VERSION 1.3 + LANGUAGES C CXX) +enable_testing() + +set(CMAKE_C_VISIBILITY_PRESET hidden) +set(CMAKE_CXX_STANDARD 11) + +set(CMAKE_THREAD_PREFER_PTHREAD TRUE) +set(THREADS_PREFER_PTHREAD_FLAG TRUE) +find_package(Threads REQUIRED) + +include(GNUInstallDirs) +include(ExternalProject) + +set(WITH_BLOCKS_RUNTIME "" CACHE PATH "Path to blocks runtime") +set(WITH_PTHREAD_WORKQUEUES "" CACHE PATH "Path to pthread-workqueues") + +include(DispatchAppleOptions) + +option(ENABLE_DISPATCH_INIT_CONSTRUCTOR "enable libdispatch_init as a constructor" ON) +set(USE_LIBDISPATCH_INIT_CONSTRUCTOR ${ENABLE_DISPATCH_INIT_CONSTRUCTOR}) + +# TODO(compnerd) swift options + +# TODO(compnerd) consider adding a flag for USE_GOLD_LINKER. Currently, we +# expect the user to specify `-fuse-ld=gold` + +option(ENABLE_THREAD_LOCAL_STORAGE "enable usage of thread local storage via __thread" ON) +set(DISPATCH_USE_THREAD_LOCAL_STORAGE ${ENABLE_THREAD_LOCAL_STORAGE}) + +if(EXISTS "${CMAKE_SOURCE_DIR}/libpwq/CMakeLists.txt") + ExternalProject_Add(pwq + SOURCE_DIR + "${CMAKE_SOURCE_DIR}/libpwq" + CMAKE_ARGS + -DCMAKE_INSTALL_PREFIX= + -DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + BUILD_BYPRODUCTS + /${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}pthread_workqueue${CMAKE_STATIC_LIBRARY_SUFFIX}) + ExternalProject_Get_Property(pwq install_dir) + add_library(PTHREAD::workqueue UNKNOWN IMPORTED) + set_target_properties(PTHREAD::workqueue + PROPERTIES + IMPORTED_LOCATION ${install_dir}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}pthread_workqueue${CMAKE_STATIC_LIBRARY_SUFFIX}) + set(WITH_PTHREAD_WORKQUEUES "${install_dir}" CACHE PATH "Path to pthread-workqueues" FORCE) + set(HAVE_PTHREAD_WORKQUEUES 1) +else() + # TODO(compnerd) support system installed pthread-workqueues + # find_package(pthread_workqueues REQUIRED) + # set(HAVE_PTHREAD_WORKQUEUES 1) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL Linux OR + CMAKE_SYSTEM_NAME STREQUAL Android OR + CMAKE_SYSTEM_NAME STREQUAL Windows) + add_library(BlocksRuntime + STATIC + ${CMAKE_SOURCE_DIR}/src/BlocksRuntime/data.c + ${CMAKE_SOURCE_DIR}/src/BlocksRuntime/runtime.c) + set_target_properties(BlocksRuntime + PROPERTIES + POSITION_INDEPENDENT_CODE TRUE) + if(HAVE_OBJC AND CMAKE_DL_LIBS) + set_target_properties(BlocksRuntime + PROPERTIES + INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS}) + endif() + set(WITH_BLOCKS_RUNTIME "${CMAKE_SOURCE_DIR}/src/BlocksRuntime" CACHE PATH "Path to blocks runtime" FORCE) +else() + # TODO(compnerd) support system installed BlocksRuntime + # find_package(BlocksRuntime REQUIRED) +endif() + +include(CheckCSourceCompiles) +include(CheckFunctionExists) +include(CheckIncludeFiles) +include(CheckLibraryExists) +include(CheckSymbolExists) + +check_symbol_exists(__GNU_LIBRARY__ "features.h" _GNU_SOURCE) +if(_GNU_SOURCE) + set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_GNU_SOURCE) +endif() + +check_c_source_compiles("void __attribute__((__noreturn__)) main() { __builtin_trap(); }" + __BUILTIN_TRAP) +if(__BUILTIN_TRAP) + set(HAVE_NORETURN_BUILTIN_TRAP 1) +endif() + +find_package(LibRT) + +check_function_exists(_pthread_workqueue_init HAVE__PTHREAD_WORKQUEUE_INIT) +check_function_exists(getprogname HAVE_GETPROGNAME) +check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME) +check_function_exists(mach_approximate_time HAVE_MACH_APPROXIMATE_TIME) +check_function_exists(mach_port_construct HAVE_MACH_PORT_CONSTRUCT) +check_function_exists(malloc_create_zone HAVE_MALLOC_CREATE_ZONE) +check_function_exists(pthread_key_init_np HAVE_PTHREAD_KEY_INIT_NP) +check_function_exists(pthread_main_np HAVE_PTHREAD_MAIN_NP) +check_function_exists(pthread_workqueue_setdispatch_np HAVE_PTHREAD_WORKQUEUE_SETDISPATCH_NP) +check_function_exists(strlcpy HAVE_STRLCPY) +check_function_exists(sysconf HAVE_SYSCONF) + +if(NOT HAVE_STRLCPY AND NOT HAVE_GETPROGNAME) + include(FindPkgConfig) + pkg_check_modules(BSD_OVERLAY libbsd-overlay) + if(BSD_OVERLAY_FOUND) + set(HAVE_STRLCPY 1 CACHE INTERNAL "Have function strlcpy" FORCE) + set(HAVE_GETPROGNAME 1 CACHE INTERNAL "Have function getprogname" FORCE) + endif() +endif() + +find_package(Threads REQUIRED) + +check_include_files("TargetConditionals.h" HAVE_TARGETCONDITIONALS_H) +check_include_files("dlfcn.h" HAVE_DLFCN_H) +check_include_files("fcntl.h" HAVE_FCNTL_H) +check_include_files("inttypes.h" HAVE_INTTYPES_H) +check_include_files("libkern/OSAtomic.h" HAVE_LIBKERN_OSATOMIC_H) +check_include_files("libkern/OSCrossEndian.h" HAVE_LIBKERN_OSCROSSENDIAN_H) +check_include_files("libproc_internal.h" HAVE_LIBPROC_INTERNAL_H) +check_include_files("mach/mach.h" HAVE_MACH) +if(HAVE_MACH) + set(__DARWIN_NON_CANCELABLE 1) + set(USE_MACH_SEM 1) +else() + set(__DARWIN_NON_CANCELABLE 0) + set(USE_MACH_SEM 0) +endif() +check_include_files("malloc/malloc.h" HAVE_MALLOC_MALLOC_H) +check_include_files("memory.h" HAVE_MEMORY_H) +check_include_files("pthread/qos.h" HAVE_PTHREAD_QOS_H) +check_include_files("pthread/workqueue_private.h" HAVE_PTHREAD_WORKQUEUE_PRIVATE_H) +check_include_files("pthread_machdep.h" HAVE_PTHREAD_MACHDEP_H) +check_include_files("pthread_np.h" HAVE_PTHREAD_NP_H) +check_include_files("pthread_workqueue.h" HAVE_PTHREAD_WORKQUEUE_H) +check_include_files("stdint.h" HAVE_STDINT_H) +check_include_files("stdlib.h" HAVE_STDLIB_H) +check_include_files("string.h" HAVE_STRING_H) +check_include_files("strings.h" HAVE_STRINGS_H) +check_include_files("sys/cdefs.h" HAVE_SYS_CDEFS_H) +check_include_files("sys/guarded.h" HAVE_SYS_GUARDED_H) +check_include_files("sys/stat.h" HAVE_SYS_STAT_H) +check_include_files("sys/types.h" HAVE_SYS_TYPES_H) +check_include_files("unistd.h" HAVE_UNISTD_H) +check_include_files("objc/objc-internal.h" HAVE_OBJC) + +check_library_exists(pthread sem_init "" USE_POSIX_SEM) + +check_symbol_exists(CLOCK_UPTIME "time.h" HAVE_DECL_CLOCK_UPTIME) +check_symbol_exists(CLOCK_UPTIME_FAST "time.h" HAVE_DECL_CLOCK_UPTIME_FAST) +check_symbol_exists(CLOCK_MONOTONIC "time.h" HAVE_DECL_CLOCK_MONOTONIC) +check_symbol_exists(CLOCK_REALTIME "time.h" HAVE_DECL_CLOCK_REALTIME) +check_symbol_exists(FD_COPY "sys/select.h" HAVE_DECL_FD_COPY) +check_symbol_exists(NOTE_LOWAT "sys/event.h" HAVE_DECL_NOTE_LOWAT) +check_symbol_exists(NOTE_NONE "sys/event.h" HAVE_DECL_NOTE_NONE) +check_symbol_exists(NOTE_REAP "sys/event.h" HAVE_DECL_NOTE_REAP) +check_symbol_exists(NOTE_REVOKE "sys/event.h" HAVE_DECL_NOTE_REVOKE) +check_symbol_exists(NOTE_SIGNAL "sys/event.h" HAVE_DECL_NOTE_SIGNAL) +check_symbol_exists(POSIX_SPAWN_START_SUSPENDED "sys/spawn.h" HAVE_DECL_POSIX_SPAWN_START_SUSPENDED) +check_symbol_exists(SIGEMT "signal.h" HAVE_DECL_SIGEMT) +check_symbol_exists(VQ_DESIRED_DISK "sys/mount.h" HAVE_DECL_VQ_DESIRED_DISK) +check_symbol_exists(VQ_NEARLOWDISK "sys/mount.h" HAVE_DECL_VQ_NEARLOWDISK) +check_symbol_exists(VQ_QUOTA "sys/mount.h" HAVE_DECL_VQ_QUOTA) +check_symbol_exists(VQ_UPDATE "sys/mount.h" HAVE_DECL_VQ_UPDATE) +check_symbol_exists(VQ_VERYLOWDISK "sys/mount.h" HAVE_DECL_VQ_VERYLOWDISK) + +check_symbol_exists(program_invocation_name "errno.h" HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME) + +find_program(dtrace_EXECUTABLE dtrace) +if(dtrace_EXECUTABLE) + add_definitions(-DDISPATCH_USE_DTRACE=1) +else() + add_definitions(-DDISPATCH_USE_DTRACE=0) +endif() + +find_program(leaks_EXECUTABLE leaks) +if(leaks_EXECUTABLE) + set(HAVE_LEAKS TRUE) +endif() + +configure_file("${CMAKE_SOURCE_DIR}/cmake/config.h.in" + "${CMAKE_BINARY_DIR}/config/config_ac.h") +add_definitions(-DHAVE_CONFIG_H) + +add_subdirectory(dispatch) +add_subdirectory(man) +add_subdirectory(os) +add_subdirectory(private) +add_subdirectory(src) +if(ENABLE_TESTING) + add_subdirectory(tests) +endif() + diff --git a/cmake/config.h.in b/cmake/config.h.in new file mode 100644 index 000000000..27156dce4 --- /dev/null +++ b/cmake/config.h.in @@ -0,0 +1,248 @@ + +/* Define if building pthread work queues from source */ +#cmakedefine BUILD_OWN_PTHREAD_WORKQUEUES + +/* Enable usage of thread local storage via __thread */ +#cmakedefine01 DISPATCH_USE_THREAD_LOCAL_STORAGE + +/* Define to 1 if you have the declaration of `CLOCK_MONOTONIC', and to 0 if + you don't. */ +#cmakedefine01 HAVE_DECL_CLOCK_MONOTONIC + +/* Define to 1 if you have the declaration of `CLOCK_REALTIME', and to 0 if + you don't. */ +#cmakedefine01 HAVE_DECL_CLOCK_REALTIME + +/* Define to 1 if you have the declaration of `CLOCK_UPTIME', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_CLOCK_UPTIME + +/* Define to 1 if you have the declaration of `CLOCK_UPTIME_FAST', and to 0 if + you don't. */ +#cmakedefine01 HAVE_DECL_CLOCK_UPTIME_FAST + +/* Define to 1 if you have the declaration of `FD_COPY', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_FD_COPY + +/* Define to 1 if you have the declaration of `NOTE_LOWAT', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_NOTE_LOWAT + +/* Define to 1 if you have the declaration of `NOTE_NONE', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_NOTE_NONE + +/* Define to 1 if you have the declaration of `NOTE_REAP', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_NOTE_REAP + +/* Define to 1 if you have the declaration of `NOTE_REVOKE', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_NOTE_REVOKE + +/* Define to 1 if you have the declaration of `NOTE_SIGNAL', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_NOTE_SIGNAL + +/* Define to 1 if you have the declaration of `POSIX_SPAWN_START_SUSPENDED', + and to 0 if you don't. */ +#cmakedefine01 HAVE_DECL_POSIX_SPAWN_START_SUSPENDED + +/* Define to 1 if you have the declaration of `program_invocation_short_name', + and to 0 if you don't. */ +#cmakedefine01 HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME + +/* Define to 1 if you have the declaration of `SIGEMT', and to 0 if you don't. + */ +#cmakedefine01 HAVE_DECL_SIGEMT + +/* Define to 1 if you have the declaration of `VQ_DESIRED_DISK', and to 0 if + you don't. */ +#cmakedefine01 HAVE_DECL_VQ_DESIRED_DISK + +/* Define to 1 if you have the declaration of `VQ_NEARLOWDISK', and to 0 if + you don't. */ +#cmakedefine01 HAVE_DECL_VQ_NEARLOWDISK + +/* Define to 1 if you have the declaration of `VQ_QUOTA', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_VQ_QUOTA + +/* Define to 1 if you have the declaration of `VQ_UPDATE', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_VQ_UPDATE + +/* Define to 1 if you have the declaration of `VQ_VERYLOWDISK', and to 0 if + you don't. */ +#cmakedefine01 HAVE_DECL_VQ_VERYLOWDISK + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_FCNTL_H + +/* Define to 1 if you have the `getprogname' function. */ +#cmakedefine01 HAVE_GETPROGNAME + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_INTTYPES_H + +/* Define if Apple leaks program is present */ +#cmakedefine HAVE_LEAKS + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIBKERN_OSATOMIC_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIBKERN_OSCROSSENDIAN_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIBPROC_INTERNAL_H + +/* Define if mach is present */ +#cmakedefine HAVE_MACH + +/* Define to 1 if you have the `mach_absolute_time' function. */ +#cmakedefine HAVE_MACH_ABSOLUTE_TIME + +/* Define to 1 if you have the `mach_approximate_time' function. */ +#cmakedefine HAVE_MACH_APPROXIMATE_TIME + +/* Define to 1 if you have the `mach_port_construct' function. */ +#cmakedefine HAVE_MACH_PORT_CONSTRUCT + +/* Define to 1 if you have the `malloc_create_zone' function. */ +#cmakedefine HAVE_MALLOC_CREATE_ZONE + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MALLOC_MALLOC_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_MEMORY_H + +/* Define if __builtin_trap marked noreturn */ +#cmakedefine01 HAVE_NORETURN_BUILTIN_TRAP + +/* Define if you have the Objective-C runtime */ +#cmakedefine HAVE_OBJC + +/* Define to 1 if you have the `pthread_key_init_np' function. */ +#cmakedefine HAVE_PTHREAD_KEY_INIT_NP + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PTHREAD_MACHDEP_H + +/* Define to 1 if you have the `pthread_main_np' function. */ +#cmakedefine HAVE_PTHREAD_MAIN_NP + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PTHREAD_NP_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PTHREAD_QOS_H + +/* Define if pthread work queues are present */ +#cmakedefine01 HAVE_PTHREAD_WORKQUEUES + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PTHREAD_WORKQUEUE_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PTHREAD_WORKQUEUE_PRIVATE_H + +/* Define to 1 if you have the `pthread_workqueue_setdispatch_np' function. */ +#cmakedefine HAVE_PTHREAD_WORKQUEUE_SETDISPATCH_NP + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_STRING_H + +/* Define to 1 if you have the `strlcpy' function. */ +#cmakedefine01 HAVE_STRLCPY + +/* Define if building for Swift */ +#undef HAVE_SWIFT + +/* Define to 1 if you have the `sysconf' function. */ +#cmakedefine01 HAVE_SYSCONF + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_SYS_CDEFS_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_GUARDED_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_TARGETCONDITIONALS_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_UNISTD_H + +/* Define to 1 if you have the `_pthread_workqueue_init' function. */ +#cmakedefine HAVE__PTHREAD_WORKQUEUE_INIT + +/* Define to use non-portable pthread TSD optimizations for Mac OS X) */ +#cmakedefine USE_APPLE_TSD_OPTIMIZATIONS + +/* Define to tag libdispatch_init as a constructor */ +#cmakedefine01 USE_LIBDISPATCH_INIT_CONSTRUCTOR + +/* Define to use Mach semaphores */ +#cmakedefine USE_MACH_SEM + +/* Define to use POSIX semaphores */ +#cmakedefine01 USE_POSIX_SEM + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +#cmakedefine01 _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +#cmakedefine01 _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +#cmakedefine01 _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +#cmakedefine01 _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +#cmakedefine01 __EXTENSIONS__ +#endif + + +/* Version number of package */ +#define VERSION "${PROJECT_VERSION}" + +/* Define to 1 if on MINIX. */ +#cmakedefine _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#cmakedefine _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#cmakedefine _POSIX_SOURCE + +/* Define if using Darwin $NOCANCEL */ +#cmakedefine __DARWIN_NON_CANCELABLE diff --git a/cmake/modules/DispatchAppleOptions.cmake b/cmake/modules/DispatchAppleOptions.cmake new file mode 100644 index 000000000..1f95f881e --- /dev/null +++ b/cmake/modules/DispatchAppleOptions.cmake @@ -0,0 +1,43 @@ + +set(WITH_APPLE_PTHREAD_SOURCE "" CACHE PATH "Path to Apple's libpthread") +set(WITH_APPLE_LIBPLATFORM_SOURCE "" CACHE PATH "Path to Apple's libplatform") +set(WITH_APPLE_LIBCLOSURE_SOURCE "" CACHE PATH "Path to Apple's libclosure") +set(WITH_APPLE_XNU_SOURCE "" CACHE PATH "Path to Apple's XNU") +set(WITH_APPLE_OBJC4_SOURCE "" CACHE PATH "Path to Apple's ObjC4") + +if(WITH_APPLE_PTHREAD_SOURCE) + include_directories(SYSTEM "${WITH_APPLE_PTHREAD_SOURCE}") +endif() +if(WITH_APPLE_LIBPLATFORM_SOURCE) + include_directories(SYSTEM "${WITH_APPLE_LIBPLATFORM_SOURCE}/include") +endif() +if(WITH_APPLE_LIBCLOSURE_SOURCE) + include_directories(SYSTEM "${WITH_APPLE_LIBCLOSURE_SOURCE}") +endif() +if(WITH_APPLE_XNU_SOURCE) + # FIXME(compnerd) this should use -idirafter + include_directories("${WITH_APPLE_XNU_SOURCE}/libkern") + include_directories(SYSTEM + "${WITH_APPLE_XNU_SOURCE}/bsd" + "${WITH_APPLE_XNU_SOURCE}/libsyscall" + "${WITH_APPLE_XNU_SOURCE}/libsyscall/wrappers/libproc") + + # hack for xnu/bsd/sys/event.h EVFILT_SOCK declaration + add_definitions(-DPRIVATE=1) +endif() + +if(IS_DIRECTORY "/System/Library/Frameworks/System.framework/PrivateHeaders") + include_directories(SYSTEM + "/System/Library/Frameworks/System.framework/PrivateHeaders") +endif() + +option(ENABLE_APPLE_TSD_OPTIMIZATIONS "use non-portable pthread TSD optimizations" OFF) +if(ENABLE_APPLE_TSD_OPTIMIZATIONS) + set(USE_APPLE_TSD_OPTIMIZATIONS 1) +else() + set(USE_APPLE_TSD_OPTIMIZATIONS 0) +endif() + +# TODO(compnerd) link in libpthread headers + + diff --git a/cmake/modules/FindLibRT.cmake b/cmake/modules/FindLibRT.cmake new file mode 100644 index 000000000..0a9f0d80e --- /dev/null +++ b/cmake/modules/FindLibRT.cmake @@ -0,0 +1,39 @@ +#.rst: +# FindLibRT +# --------- +# +# Find librt library and headers. +# +# The mdoule defines the following variables: +# +# :: +# +# LibRT_FOUND - true if librt was found +# LibRT_INCLUDE_DIR - include search path +# LibRT_LIBRARIES - libraries to link + +if(UNIX) + find_path(LibRT_INCLUDE_DIR + NAMES + time.h) + find_library(LibRT_LIBRARIES rt) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(LibRT + REQUIRED_VARS + LibRT_LIBRARIES + LibRT_INCLUDE_DIR) + + if(LibRT_FOUND) + if(NOT TARGET RT::rt) + add_library(RT::rt UNKNOWN IMPORTED) + set_target_properties(RT::rt + PROPERTIES + IMPORTED_LOCATION ${LibRT_LIBRARIES} + INTERFACE_INCLUDE_DIRECTORIES ${LibRT_INCLUDE_DIR}) + endif() + endif() + + mark_as_advanced(LibRT_LIBRARIES LibRT_INCLUDE_DIR) +endif() + diff --git a/dispatch/CMakeLists.txt b/dispatch/CMakeLists.txt new file mode 100644 index 000000000..dbfb866a8 --- /dev/null +++ b/dispatch/CMakeLists.txt @@ -0,0 +1,24 @@ + +install(FILES + base.h + block.h + data.h + dispatch.h + group.h + introspection.h + io.h + object.h + once.h + queue.h + semaphore.h + source.h + time.h + DESTINATION + ${CMAKE_INSTALL_FULL_INCLUDEDIR}/dispatch/) +if(ENABLE_SWIFT) + install(FILES + module.modulemap + DESTINATION + ${CMAKE_INSTALL_FULL_INCLUEDIR}/dispatch/) +endif() + diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt new file mode 100644 index 000000000..e81b14b41 --- /dev/null +++ b/man/CMakeLists.txt @@ -0,0 +1,23 @@ + +# TODO(compnerd) add symlinks +if(NOT ENABLE_SWIFT) + install(FILES + dispatch.3 + dispatch_after.3 + dispatch_api.3 + dispatch_apply.3 + dispatch_async.3 + dispatch_data_create.3 + dispatch_group_create.3 + dispatch_io_create.3 + dispatch_io_read.3 + dispatch_object.3 + dispatch_once.3 + dispatch_queue_create.3 + dispatch_read.3 + dispatch_semaphore_create.3 + dispatch_source_create.3 + dispatch_time.3 + DESTINATION + "${CMAKE_INSTALL_FULL_MANDIR}/man3") +endif() diff --git a/os/CMakeLists.txt b/os/CMakeLists.txt new file mode 100644 index 000000000..6e2b41518 --- /dev/null +++ b/os/CMakeLists.txt @@ -0,0 +1,10 @@ + +# TODO(compnerd) ensure that object_private.h voucher_activity_private.h +# voucher_private.h are included in the source tarball + +install(FILES + object.h + linux_base.h + DESTINATION + "${CMAKE_INSTALL_FULL_INCLUDEDIR}/os") + diff --git a/private/CMakeLists.txt b/private/CMakeLists.txt new file mode 100644 index 000000000..18788d727 --- /dev/null +++ b/private/CMakeLists.txt @@ -0,0 +1,5 @@ + +# TODO(compnerd) ensure that benchmark.h data_private.h introduction_private.h +# io_private.h layout_private.h mach_private.h private.h queue_private.h +# source_private.h are included in the source tarball + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..113ff4e3b --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,117 @@ + +set(dispatch_BLOCK_SOURCES block.cpp) +if(HAVE_OBJC) + list(APPEND dispatch_BLOCK_SOURCES data.m object.m) +endif() +add_library(dispatch + allocator.c + apply.c + benchmark.c + data.c + init.c + introspection.c + io.c + mach.c + object.c + once.c + queue.c + semaphore.c + source.c + time.c + transform.c + voucher.c + protocol.defs + provider.d + allocator_internal.h + data_internal.h + inline_internal.h + internal.h + introspection_internal.h + io_internal.h + mach_internal.h + object_internal.h + queue_internal.h + semaphore_internal.h + shims.h + source_internal.h + trace.h + voucher_internal.h + event/event.c + event/event_config.h + event/event_epoll.c + event/event_internal.h + event/event_kevent.c + firehose/firehose_internal.h + shims/android_stubs.h + shims/atomic.h + shims/atomic_sfb.h + shims/getprogname.h + shims/hw_config.h + shims/linux_stubs.c + shims/linux_stubs.h + shims/lock.c + shims/lock.h + shims/perfmon.h + shims/time.h + shims/tsd.h + shims/yield.h + ${dispatch_BLOCK_SOURCES}) +target_include_directories(dispatch + PRIVATE + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/private) +if(WITH_PTHREAD_WORKQUEUES) + target_include_directories(dispatch + SYSTEM BEFORE PRIVATE + "${WITH_PTHREAD_WORKQUEUES}/include") +endif() +if(WITH_BLOCKS_RUNTIME) + target_include_directories(dispatch + SYSTEM BEFORE PRIVATE + "${WITH_BLOCKS_RUNTIME}") +endif() +# TODO(compnerd) make this portable +target_compile_options(dispatch PRIVATE -fno-exceptions) +if(DISPATCH_ENABLE_ASSERTS) + target_compile_definitions(dispatch + PRIVATE + -DDISPATCH_DEBUG=1) +endif() +if(BSD_OVERLAY_FOUND) + target_compile_options(dispatch + PRIVATE + ${BSD_OVERLAY_CFLAGS}) +endif() +# FIXME(compnerd) add check for -momit-leaf-frame-pointer? +target_compile_options(dispatch + PRIVATE + -Wall + -fblocks + -momit-leaf-frame-pointer) +if(BSD_OVERLAY_FOUND) + target_link_libraries(dispatch PRIVATE ${BSD_OVERLAY_LDFLAGS}) +endif() +target_link_libraries(dispatch PRIVATE Threads::Threads) +if(WITH_PTHREAD_WORKQUEUES) + target_link_libraries(dispatch PRIVATE PTHREAD::workqueue) +endif() +if(WITH_BLOCKS_RUNTIME) + target_link_libraries(dispatch PRIVATE BlocksRuntime) +endif() +if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set_property(TARGET dispatch + APPEND_STRING + PROPERTY LINK_FLAGS + "-Xlinker -compatibility_version -Xlinker 1" + "-Xlinker -current_version -Xlinker ${VERSION}" + "-Xlinker -dead_strip" + "-Xlinker -alias_list -Xlinker ${CMAKE_SOURCE_DIR}/xcodeconfig/libdispatch.aliases") +endif() + +install(TARGETS + dispatch + DESTINATION + "${CMAKE_INSTALL_FULL_LIBDIR}") + From 00e7e55409368a74d9dcc963eeac77d6990b08c6 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Wed, 19 Apr 2017 14:14:06 -0700 Subject: [PATCH 28/48] Merge pull request #196 from compnerd/cmake build: add a cmake based build system Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index e7f211332..37439a793 100644 --- a/PATCHES +++ b/PATCHES @@ -324,3 +324,4 @@ github commits starting with 29bdc2f from [a69853f] APPLIED rdar://32283666 [eea0667] APPLIED rdar://32283666 [f84d21d] APPLIED rdar://32283666 +[3da8398] APPLIED rdar://32283666 From 7b0a4483037556fc44ffa886adf6752a1f38464e Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Tue, 4 Apr 2017 16:03:06 +0930 Subject: [PATCH 29/48] lock: Avoid use of undefined DISPATCH_INTERNAL_CRASH Building swift-corelibs-libdispatch on powerpc64le under Linux lead to the following build failure: /bin/bash ../libtool --tag=CXX --mode=compile /home/ubuntu/swift-dev/build/buildbot_incremental/llvm-linux-powerpc64le/bin/clang++ -DHAVE_CONFIG_H -I. -I../config -I.. -I.. -I../private -DDISPATCH_USE_DTRACE=0 -I../libpwq/include -Wall -fvisibility=hidden -momit-leaf-frame-pointer -isystem /usr/include/bsd -DLIBBSD_OVERLAY -fblocks -I../src/BlocksRuntime -std=gnu++11 -fno-exceptions -O2 -c -o libdispatch_la-block.lo `test -f 'block.cpp' || echo './'`block.cpp libtool: compile: /home/ubuntu/swift-dev/build/buildbot_incremental/llvm-linux-powerpc64le/bin/clang++ -DHAVE_CONFIG_H -I. -I../config -I.. -I.. -I../private -DDISPATCH_USE_DTRACE=0 -I../libpwq/include -Wall -fvisibility=hidden -momit-leaf-frame-pointer -isystem /usr/include/bsd -DLIBBSD_OVERLAY -fblocks -I../src/BlocksRuntime -std=gnu++11 -fno-exce ptions -O2 -c block.cpp -fPIC -DPIC -o .libs/libdispatch_la-block.o In file included from block.cpp:32: In file included from ./internal.h:628: In file included from ./shims.h:171: ./shims/lock.h:550:3: error: use of undeclared identifier 'DISPATCH_INTERNAL_CRASH' DISPATCH_INTERNAL_CRASH(errno, "sys_membarrier not supported"); ^ 1 error generated. Makefile:701: recipe for target 'libdispatch_la-block.lo' failed make[2]: *** [libdispatch_la-block.lo] Error 1 make[2]: Leaving directory '/home/ubuntu/swift-dev/swift-corelibs-libdispatch/src' Makefile:541: recipe for target 'all' failed make[1]: *** [all] Error 2 make[1]: Leaving directory '/home/ubuntu/swift-dev/swift-corelibs-libdispatch/src' Makefile:457: recipe for target 'all-recursive' failed make: *** [all-recursive] Error 1 Include ordering in internal.h is tightly constrained, so open-code the macro to avoid the dependency problem. Signed-off-by: Andrew Jeffery Signed-off-by: Daniel A. Steffen --- src/shims/lock.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/shims/lock.h b/src/shims/lock.h index 3178793a9..4bbbb4283 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -548,7 +548,17 @@ _dispatch_once_xchg_done(dispatch_once_t *pred) return os_atomic_xchg(pred, DLOCK_ONCE_DONE, release); #elif defined(__linux__) if (unlikely(syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0) < 0)) { - DISPATCH_INTERNAL_CRASH(errno, "sys_membarrier not supported"); + /* + * sys_membarrier not supported + * + * Ideally we would call DISPATCH_INTERNAL_CRASH() here, but + * due to ordering constraints in internal.h required by Darwin + * the macro is undefined when this header is included. + * Instead, open-code what would be a call to + * _dispatch_hardware_crash() inside DISPATCH_INTERNAL_CRASH(). + */ + __asm__(""); + __builtin_trap(); } return os_atomic_xchg(pred, DLOCK_ONCE_DONE, relaxed); #else From b2789e6f67e54b0451c90320015efdf0c93153f5 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 20 Apr 2017 20:04:30 -0700 Subject: [PATCH 30/48] Merge pull request #233 from amboar/master lock: Avoid use of undefined DISPATCH_INTERNAL_CRASH Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 37439a793..9b53e9770 100644 --- a/PATCHES +++ b/PATCHES @@ -325,3 +325,4 @@ github commits starting with 29bdc2f from [eea0667] APPLIED rdar://32283666 [f84d21d] APPLIED rdar://32283666 [3da8398] APPLIED rdar://32283666 +[2df80a3] APPLIED rdar://32283666 From 64da2b1bee6d2de6a8cf2b9e12d435e46c2b90e3 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Sat, 29 Apr 2017 18:52:35 -0700 Subject: [PATCH 31/48] build: attempt to add swift support to cmake Introduce support for building the swift SDK overlay into the CMake based build system. This was the one piece which was missing from the original cmake port of the build system. Signed-off-by: Daniel A. Steffen --- cmake/modules/SwiftSupport.cmake | 69 ++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 39 +++++++++++++++++- 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 cmake/modules/SwiftSupport.cmake diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake new file mode 100644 index 000000000..a29fd26db --- /dev/null +++ b/cmake/modules/SwiftSupport.cmake @@ -0,0 +1,69 @@ + +include(CMakeParseArguments) + +function(add_swift_library library) + set(options) + set(single_value_options MODULE_NAME;MODULE_LINK_NAME;MODULE_PATH;MODULE_CACHE_PATH;OUTPUT) + set(multiple_value_options SOURCES;SWIFT_FLAGS;CFLAGS) + + cmake_parse_arguments(ASL "${options}" "${single_value_options}" "${multiple_value_options}" ${ARGN}) + + set(flags ${CMAKE_SWIFT_FLAGS}) + + list(APPEND flags -emit-library) + + if(ASL_MODULE_NAME) + list(APPEND flags -module-name;${ASL_MODULE_NAME}) + endif() + if(ASL_MODULE_LINK_NAME) + list(APPEND flags -module-link-name;${ASL_MODULE_LINK_NAME}) + endif() + if(ASL_MODULE_PATH) + list(APPEND flags -emit-module-path;${ASL_MODULE_PATH}) + endif() + if(ASL_MODULE_CACHE_PATH) + list(APPEND flags -module-cache-path;${ASL_MODULE_CACHE_PATH}) + endif() + if(ASL_SWIFT_FLAGS) + foreach(flag ${ASL_SWIFT_FLAGS}) + list(APPEND flags ${flag}) + endforeach() + endif() + if(ASL_CFLAGS) + foreach(flag ${ASL_CFLAGS}) + list(APPEND flags -Xcc;${flag}) + endforeach() + endif() + + # FIXME: We shouldn't /have/ to build things in a single process. + # + list(APPEND flags -force-single-frontend-invocation) + + set(sources) + foreach(source ${ASL_SOURCES}) + get_filename_component(location ${source} PATH) + if(IS_ABSOLUTE ${location}) + list(APPEND sources ${source}) + else() + list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/${source}) + endif() + endforeach() + + get_filename_component(module_directory ${ASL_MODULE_PATH} DIRECTORY) + + add_custom_command(OUTPUT + ${ASL_OUTPUT} + ${ASL_MODULE_PATH} + ${moodule_directory}/${ASL_MODULE_NAME}.swiftdoc + DEPENDS + ${ASL_SOURCES} + COMMAND + ${CMAKE_COMMAND} -E make_directory ${module_directory} + COMMAND + ${CMAKE_SWIFT_COMPILER} ${flags} -c ${sources} -o ${ASL_OUTPUT}) + add_custom_target(${library} + DEPENDS + ${ASL_OUTPUT} + ${ASL_MODULE_PATH} + ${moodule_directory}/${ASL_MODULE_NAME}.swiftdoc) +endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 113ff4e3b..1c4d963f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,44 @@ +include(SwiftSupport) + set(dispatch_BLOCK_SOURCES block.cpp) if(HAVE_OBJC) list(APPEND dispatch_BLOCK_SOURCES data.m object.m) endif() +set(dispatch_SWIFT_SOURCES) +if(CMAKE_SWIFT_COMPILER) + set(swift_optimization_flags) + if(CMAKE_BUILD_TYPE MATCHES Release) + set(swift_optimization_flags -O) + endif() + add_swift_library(swiftDispatch + MODULE_NAME + Dispatch + MODULE_LINK_NAME + dispatch + MODULE_PATH + ${CMAKE_CURRENT_BINARY_DIR}/swift/Dispatch.swiftmodule + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/swiftDispatch.o + SOURCES + swift/Block.swift + swift/Data.swift + swift/Dispatch.swift + swift/IO.swift + swift/Private.swift + swift/Queue.swift + swift/Source.swift + swift/Time.swift + swift/Wrapper.swift + CFLAGS + -fblocks + -fmodule-map-file=${CMAKE_SOURCE_DIR}/dispatch/module.modulemap + SWIFT_FLAGS + -I ${CMAKE_SOURCE_DIR} + ${swift_optimization_flags}) + list(APPEND dispatch_SWIFT_SOURCES + swift/DispatchStubs.cc;${CMAKE_CURRENT_BINARY_DIR}/swiftDispatch.o) +endif() add_library(dispatch allocator.c apply.c @@ -55,7 +91,8 @@ add_library(dispatch shims/time.h shims/tsd.h shims/yield.h - ${dispatch_BLOCK_SOURCES}) + ${dispatch_BLOCK_SOURCES} + ${dispatch_SWIFT_SOURCES}) target_include_directories(dispatch PRIVATE ${CMAKE_BINARY_DIR} From 44792540111053f2669355325d9fdc557eba3f19 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sun, 7 May 2017 10:09:47 -0700 Subject: [PATCH 32/48] Merge pull request #243 from compnerd/swiftDispatch build: attempt to add swift support to cmake Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 9b53e9770..25ba94501 100644 --- a/PATCHES +++ b/PATCHES @@ -326,3 +326,4 @@ github commits starting with 29bdc2f from [f84d21d] APPLIED rdar://32283666 [3da8398] APPLIED rdar://32283666 [2df80a3] APPLIED rdar://32283666 +[97a2f06] APPLIED rdar://32283666 From 1d4da8a6de84664d21b51169bb2c28048fa78e3f Mon Sep 17 00:00:00 2001 From: David Grove Date: Fri, 10 Mar 2017 11:14:26 -0500 Subject: [PATCH 33/48] SR-4201: DispatchSourceSignal not working on Linux The observed bug is that signals sent to the main thread after it called dispatch_main were not triggering the event handler of a DispatchSourceSignal that had been previously created and activated to handle that signal. This patch addresses the problem by: - export _dispatch_sigmask() as the way to block signals in a process using dispatch - call it when dispatch_main() is called - each time dispatch registers a signal handler, register a sigaction that will catch signals for threads with wrong masks and will fix the thread configuration then raise the signal again by directing a pthread_kill to the manager thread so that it is delivered to the signalfd as expected. Patch by Pierre Habouzit from PR-231 with minor compilation fixes by Dave Grove. Signed-off-by: Daniel A. Steffen --- src/event/event_epoll.c | 25 ++++++++++++++++++++++++- src/init.c | 23 +++++++++++++++++++++++ src/internal.h | 2 ++ src/queue.c | 40 ++-------------------------------------- 4 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/event/event_epoll.c b/src/event/event_epoll.c index 2788b1008..647552f65 100644 --- a/src/event/event_epoll.c +++ b/src/event/event_epoll.c @@ -117,9 +117,28 @@ _dispatch_muxnote_dispose(dispatch_muxnote_t dmn) free(dmn); } +static pthread_t manager_thread; + +static void +_dispatch_muxnote_signal_block_and_raise(int signo) +{ + // On linux, for signals to be delivered to the signalfd, signals + // must be blocked, else any thread that hasn't them blocked may + // receive them. Fix that by lazily noticing, blocking said signal, + // and raising the signal again when it happens + _dispatch_sigmask(); + pthread_kill(manager_thread, signo); +} + static dispatch_muxnote_t _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events) { + static sigset_t signals_with_unotes; + static struct sigaction sa = { + .sa_handler = _dispatch_muxnote_signal_block_and_raise, + .sa_flags = SA_RESTART, + }; + dispatch_muxnote_t dmn; struct stat sb; int fd = du._du->du_ident; @@ -129,13 +148,17 @@ _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events) switch (filter) { case EVFILT_SIGNAL: + if (!sigismember(&signals_with_unotes, du._du->du_ident)) { + manager_thread = pthread_self(); + sigaddset(&signals_with_unotes, du._du->du_ident); + sigaction(du._du->du_ident, &sa, NULL); + } sigemptyset(&sigmask); sigaddset(&sigmask, du._du->du_ident); fd = signalfd(-1, &sigmask, SFD_NONBLOCK | SFD_CLOEXEC); if (fd < 0) { return NULL; } - sigprocmask(SIG_BLOCK, &sigmask, NULL); break; case EVFILT_WRITE: diff --git a/src/init.c b/src/init.c index a04daeb96..4ccb1f2d9 100644 --- a/src/init.c +++ b/src/init.c @@ -72,6 +72,29 @@ dispatch_atfork_child(void) _dispatch_unsafe_fork = 0; } +int +_dispatch_sigmask(void) +{ + sigset_t mask; + int r = 0; + + /* Workaround: 6269619 Not all signals can be delivered on any thread */ + r |= sigfillset(&mask); + r |= sigdelset(&mask, SIGILL); + r |= sigdelset(&mask, SIGTRAP); +#if HAVE_DECL_SIGEMT + r |= sigdelset(&mask, SIGEMT); +#endif + r |= sigdelset(&mask, SIGFPE); + r |= sigdelset(&mask, SIGBUS); + r |= sigdelset(&mask, SIGSEGV); + r |= sigdelset(&mask, SIGSYS); + r |= sigdelset(&mask, SIGPIPE); + r |= sigdelset(&mask, SIGPROF); + r |= pthread_sigmask(SIG_BLOCK, &mask, NULL); + (void)dispatch_assume_zero(r); +} + #pragma mark - #pragma mark dispatch_globals diff --git a/src/internal.h b/src/internal.h index 743d0b2c6..489da74a8 100644 --- a/src/internal.h +++ b/src/internal.h @@ -990,6 +990,8 @@ extern int _dispatch_evfilt_machport_direct_enabled; #endif // DISPATCH_USE_EVFILT_MACHPORT_DIRECT +int _dispatch_sigmask(void); + /* #includes dependent on internal.h */ #include "object_internal.h" #include "semaphore_internal.h" diff --git a/src/queue.c b/src/queue.c index 088c5cfd2..be831ab4c 100644 --- a/src/queue.c +++ b/src/queue.c @@ -66,7 +66,6 @@ static void _dispatch_worker_thread2(int priority, int options, void *context); #endif #if DISPATCH_USE_PTHREAD_POOL static void *_dispatch_worker_thread(void *context); -static int _dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset); #endif #if DISPATCH_COCOA_COMPAT @@ -5466,13 +5465,8 @@ _dispatch_worker_thread(void *context) pqc->dpq_thread_configure(); } - sigset_t mask; - int r; // workaround tweaks the kernel workqueue does for us - r = sigfillset(&mask); - (void)dispatch_assume_zero(r); - r = _dispatch_pthread_sigmask(SIG_BLOCK, &mask, NULL); - (void)dispatch_assume_zero(r); + _dispatch_sigmask(); _dispatch_introspection_thread_add(); const int64_t timeout = 5ull * NSEC_PER_SEC; @@ -5489,37 +5483,6 @@ _dispatch_worker_thread(void *context) return NULL; } - -int -_dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset) -{ - int r; - - /* Workaround: 6269619 Not all signals can be delivered on any thread */ - - r = sigdelset(set, SIGILL); - (void)dispatch_assume_zero(r); - r = sigdelset(set, SIGTRAP); - (void)dispatch_assume_zero(r); -#if HAVE_DECL_SIGEMT - r = sigdelset(set, SIGEMT); - (void)dispatch_assume_zero(r); -#endif - r = sigdelset(set, SIGFPE); - (void)dispatch_assume_zero(r); - r = sigdelset(set, SIGBUS); - (void)dispatch_assume_zero(r); - r = sigdelset(set, SIGSEGV); - (void)dispatch_assume_zero(r); - r = sigdelset(set, SIGSYS); - (void)dispatch_assume_zero(r); - r = sigdelset(set, SIGPIPE); - (void)dispatch_assume_zero(r); - r = sigdelset(set, SIGPROF); - (void)dispatch_assume_zero(r); - - return pthread_sigmask(how, set, oset); -} #endif // DISPATCH_USE_PTHREAD_POOL #pragma mark - @@ -5749,6 +5712,7 @@ dispatch_main(void) pthread_key_t dispatch_main_key; pthread_key_create(&dispatch_main_key, _dispatch_sig_thread); pthread_setspecific(dispatch_main_key, &dispatch_main_key); + _dispatch_sigmask(); #endif pthread_exit(NULL); DISPATCH_INTERNAL_CRASH(errno, "pthread_exit() returned"); From ec53c5604bf1c4994da556f9e0f8d8c6a904984d Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sun, 7 May 2017 10:59:12 -0700 Subject: [PATCH 34/48] Merge pull request #231 from dgrove-oss/SR-4201-signalsource SR-4201: DispatchSourceSignal not working on Linux Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 25ba94501..04bc0e063 100644 --- a/PATCHES +++ b/PATCHES @@ -327,3 +327,4 @@ github commits starting with 29bdc2f from [3da8398] APPLIED rdar://32283666 [2df80a3] APPLIED rdar://32283666 [97a2f06] APPLIED rdar://32283666 +[f76b8f5] APPLIED rdar://32283666 From eee9a8d06137ceb887842e6be00f7aca0e2014b1 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 18 May 2017 20:33:37 -0700 Subject: [PATCH 35/48] fix build failures due to missing return value Signed-off-by: Daniel A. Steffen --- src/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.c b/src/init.c index 4ccb1f2d9..22a61e346 100644 --- a/src/init.c +++ b/src/init.c @@ -92,7 +92,7 @@ _dispatch_sigmask(void) r |= sigdelset(&mask, SIGPIPE); r |= sigdelset(&mask, SIGPROF); r |= pthread_sigmask(SIG_BLOCK, &mask, NULL); - (void)dispatch_assume_zero(r); + return dispatch_assume_zero(r); } #pragma mark - From f1ad3ff122d5ec4ea7466b8db097e8c911ecf7b7 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 3 May 2017 10:21:03 -0700 Subject: [PATCH 36/48] Create a DISPATCH_PTR_SIZE macro and use it This introduces a new macro, `DISPATCH_PTR_SIZE` which is defined much like `LLVM_PTR_SIZE`. We can gracefully fallback to alternate means of checking the width of the pointer and use this rather than `__LP64__` to determine if we are on a 64-bit host. Signed-off-by: Daniel A. Steffen --- src/event/event_kevent.c | 2 +- src/object_internal.h | 2 +- src/queue_internal.h | 7 ++----- src/shims/hw_config.h | 16 ++++++++++++++++ 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c index b3bd63f3a..32758880e 100644 --- a/src/event/event_kevent.c +++ b/src/event/event_kevent.c @@ -1557,7 +1557,7 @@ _dispatch_mach_notify_port_init(void *context DISPATCH_UNUSED) kern_return_t kr; #if HAVE_MACH_PORT_CONSTRUCT mach_port_options_t opts = { .flags = MPO_CONTEXT_AS_GUARD | MPO_STRICT }; -#ifdef __LP64__ +#if DISPATCH_SIZEOF_PTR == 8 const mach_port_context_t guard = 0xfeed09071f1ca7edull; #else const mach_port_context_t guard = 0xff1ca7edull; diff --git a/src/object_internal.h b/src/object_internal.h index abc3f4811..61caebfe4 100644 --- a/src/object_internal.h +++ b/src/object_internal.h @@ -225,7 +225,7 @@ .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT #endif -#ifdef __LP64__ +#if DISPATCH_SIZEOF_PTR == 8 // the bottom nibble must not be zero, the rest of the bits should be random // we sign extend the 64-bit version so that a better instruction encoding is // generated on Intel diff --git a/src/queue_internal.h b/src/queue_internal.h index 29e83cc59..ca9886c61 100644 --- a/src/queue_internal.h +++ b/src/queue_internal.h @@ -748,7 +748,6 @@ dispatch_queue_attr_t _dispatch_get_default_queue_attr(void); void *dc_ctxt; \ void *dc_data; \ void *dc_other -#define _DISPATCH_SIZEOF_PTR 8 #elif OS_OBJECT_HAVE_OBJC1 #define DISPATCH_CONTINUATION_HEADER(x) \ dispatch_function_t dc_func; \ @@ -766,7 +765,6 @@ dispatch_queue_attr_t _dispatch_get_default_queue_attr(void); void *dc_ctxt; \ void *dc_data; \ void *dc_other -#define _DISPATCH_SIZEOF_PTR 4 #else #define DISPATCH_CONTINUATION_HEADER(x) \ union { \ @@ -784,17 +782,16 @@ dispatch_queue_attr_t _dispatch_get_default_queue_attr(void); void *dc_ctxt; \ void *dc_data; \ void *dc_other -#define _DISPATCH_SIZEOF_PTR 4 #endif #define _DISPATCH_CONTINUATION_PTRS 8 #if DISPATCH_HW_CONFIG_UP // UP devices don't contend on continuations so we don't need to force them to // occupy a whole cacheline (which is intended to avoid contention) #define DISPATCH_CONTINUATION_SIZE \ - (_DISPATCH_CONTINUATION_PTRS * _DISPATCH_SIZEOF_PTR) + (_DISPATCH_CONTINUATION_PTRS * DISPATCH_SIZEOF_PTR) #else #define DISPATCH_CONTINUATION_SIZE ROUND_UP_TO_CACHELINE_SIZE( \ - (_DISPATCH_CONTINUATION_PTRS * _DISPATCH_SIZEOF_PTR)) + (_DISPATCH_CONTINUATION_PTRS * DISPATCH_SIZEOF_PTR)) #endif #define ROUND_UP_TO_CONTINUATION_SIZE(x) \ (((x) + (DISPATCH_CONTINUATION_SIZE - 1u)) & \ diff --git a/src/shims/hw_config.h b/src/shims/hw_config.h index 6b5a06929..26856bce9 100644 --- a/src/shims/hw_config.h +++ b/src/shims/hw_config.h @@ -27,6 +27,22 @@ #ifndef __DISPATCH_SHIMS_HW_CONFIG__ #define __DISPATCH_SHIMS_HW_CONFIG__ +#ifdef __SIZEOF_POINTER__ +#define DISPATCH_SIZEOF_PTR __SIZEOF_POINTER__ +#elif defined(_WIN64) +#define DISPATCH_SIZEOF_PTR 8 +#elif defined(_WIN32) +#define DISPATCH_SIZEOF_PTR 4 +#elif defined(_MSC_VER) +#error "could not determine pointer size as a constant int for MSVC" +#elif defined(__LP64__) || defined(__LLP64__) +#define DISPATCH_SIZEOF_PTR 8 +#elif defined(__ILP32__) +#define DISPATCH_SIZEOF_PTR 4 +#else +#error "could not determine pointer size as a constant int" +#endif // __SIZEOF_POINTER__ + #if !TARGET_OS_WIN32 typedef enum { From 26d2dced078bd7a67b4fa0d8682cc4c3b96607b1 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sun, 7 May 2017 12:21:15 -0700 Subject: [PATCH 37/48] Merge pull request #244 from compnerd/ptrsize Create a DISPATCH_PTR_SIZE macro and use it Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 04bc0e063..04cf6af88 100644 --- a/PATCHES +++ b/PATCHES @@ -328,3 +328,4 @@ github commits starting with 29bdc2f from [2df80a3] APPLIED rdar://32283666 [97a2f06] APPLIED rdar://32283666 [f76b8f5] APPLIED rdar://32283666 +[3828fbb] APPLIED rdar://32283666 From 3d5b6ce41cd98ae7dc317c0711b5c00348036ab1 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Sat, 6 May 2017 18:38:36 -0700 Subject: [PATCH 38/48] guard includes with checks sys/cdefs.h and unistd.h are not always available. We already have checks for these, guard the inclusion appropriately. Signed-off-by: Daniel A. Steffen --- dispatch/dispatch.h | 4 ++++ os/object_private.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index 585940cc0..a0622e6cb 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -39,13 +39,17 @@ #endif #endif // __APPLE__ +#if HAVE_SYS_CDEFS_H #include +#endif #include #include #include #include #include +#if HAVE_UNISTD_H #include +#endif #include #if defined(__linux__) && defined(__has_feature) diff --git a/os/object_private.h b/os/object_private.h index 36a807cb0..ebaf8549f 100644 --- a/os/object_private.h +++ b/os/object_private.h @@ -27,7 +27,9 @@ #ifndef __OS_OBJECT_PRIVATE__ #define __OS_OBJECT_PRIVATE__ +#if HAVE_SYS_CDEFS_H #include +#endif #include #include From 9c8afdaad472de4b07d2503a9eb2d461b2f94c48 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Sat, 6 May 2017 18:40:02 -0700 Subject: [PATCH 39/48] invert Linux handling Rather than checking for non-Linux and including the target specific header, invert the check and include the linux target header if `__linux__` is defined. This makes it easier to target other platforms. Signed-off-by: Daniel A. Steffen --- os/object.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/os/object.h b/os/object.h index b0b47059a..b98a93e57 100644 --- a/os/object.h +++ b/os/object.h @@ -26,10 +26,10 @@ #include #include #endif -#ifndef __linux__ -#include -#else +#ifdef __linux__ #include +#else +#include #endif /*! From 2ab4696ea9b0d02e28fe85f62f0fcf2a8bcf459c Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Sat, 6 May 2017 18:48:10 -0700 Subject: [PATCH 40/48] build: improve support for cl-like compilers Address some of the portability considerations for the build flags. This improves some of the conditions for building for Windows. Signed-off-by: Daniel A. Steffen --- CMakeLists.txt | 4 ++++ src/CMakeLists.txt | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08f6fc17d..755f3c6c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,6 +154,10 @@ check_include_files("unistd.h" HAVE_UNISTD_H) check_include_files("objc/objc-internal.h" HAVE_OBJC) check_library_exists(pthread sem_init "" USE_POSIX_SEM) +if(CMAKE_SYSTEM_NAME STREQUAL Windows) + add_definitions(-DTARGET_OS_WIN32) + add_definitions(-DUSE_WIN32_SEM) +endif() check_symbol_exists(CLOCK_UPTIME "time.h" HAVE_DECL_CLOCK_UPTIME) check_symbol_exists(CLOCK_UPTIME_FAST "time.h" HAVE_DECL_CLOCK_UPTIME_FAST) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1c4d963f0..8bc572bfb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -109,24 +109,47 @@ if(WITH_BLOCKS_RUNTIME) SYSTEM BEFORE PRIVATE "${WITH_BLOCKS_RUNTIME}") endif() -# TODO(compnerd) make this portable -target_compile_options(dispatch PRIVATE -fno-exceptions) +if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") + target_compile_options(dispatch PRIVATE /EHsc-) +else() + target_compile_options(dispatch PRIVATE -fno-exceptions) +endif() if(DISPATCH_ENABLE_ASSERTS) target_compile_definitions(dispatch PRIVATE -DDISPATCH_DEBUG=1) endif() +if(CMAKE_SYSTEM_NAME STREQUAL Windows) + target_compile_definitions(dispatch + PRIVATE + -D_CRT_SECURE_NO_WARNINGS) +endif() if(BSD_OVERLAY_FOUND) target_compile_options(dispatch PRIVATE ${BSD_OVERLAY_CFLAGS}) endif() -# FIXME(compnerd) add check for -momit-leaf-frame-pointer? -target_compile_options(dispatch - PRIVATE - -Wall - -fblocks - -momit-leaf-frame-pointer) +if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") + target_compile_options(dispatch + PRIVATE + /W3) +else() + target_compile_options(dispatch + PRIVATE + -Wall) +endif() +# FIXME(compnerd) add check for -fblocks? +if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") + target_compile_options(dispatch + PRIVATE + -Xclang -fblocks) +else() + # FIXME(compnerd) add check for -momit-leaf-frame-pointer? + target_compile_options(dispatch + PRIVATE + -fblocks + -momit-leaf-frame-pointer) +endif() if(BSD_OVERLAY_FOUND) target_link_libraries(dispatch PRIVATE ${BSD_OVERLAY_LDFLAGS}) endif() From 3b42f6bf7cfc0ed34370f2ae07256a8e5638903d Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sun, 7 May 2017 12:21:39 -0700 Subject: [PATCH 41/48] Merge pull request #245 from compnerd/windows-cleanups Windows cleanups Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 04cf6af88..b22aa5cfa 100644 --- a/PATCHES +++ b/PATCHES @@ -329,3 +329,4 @@ github commits starting with 29bdc2f from [97a2f06] APPLIED rdar://32283666 [f76b8f5] APPLIED rdar://32283666 [3828fbb] APPLIED rdar://32283666 +[5e8789e] APPLIED rdar://32283666 From 8af68ef3e4bbc1ad94af27045950467086cf6305 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 18 May 2017 18:52:34 -0700 Subject: [PATCH 42/48] fix invalid use of config defines in API/SPI headers Signed-off-by: Daniel A. Steffen --- dispatch/dispatch.h | 21 ++++----------------- os/linux_base.h | 17 +++++++++++++++++ os/object.h | 8 +++----- os/object_private.h | 10 ++-------- 4 files changed, 26 insertions(+), 30 deletions(-) diff --git a/dispatch/dispatch.h b/dispatch/dispatch.h index a0622e6cb..6f8b31b25 100644 --- a/dispatch/dispatch.h +++ b/dispatch/dispatch.h @@ -24,30 +24,17 @@ #ifdef __APPLE__ #include #include -#else -#ifndef API_AVAILABLE -#define API_AVAILABLE(...) +#include +#elif defined(__linux__) +#include #endif -#ifndef API_DEPRECATED -#define API_DEPRECATED(...) -#endif -#ifndef API_UNAVAILABLE -#define API_UNAVAILABLE(...) -#endif -#ifndef API_DEPRECATED_WITH_REPLACEMENT -#define API_DEPRECATED_WITH_REPLACEMENT(...) -#endif -#endif // __APPLE__ -#if HAVE_SYS_CDEFS_H -#include -#endif #include #include #include #include #include -#if HAVE_UNISTD_H +#if !defined(HAVE_UNISTD_H) || HAVE_UNISTD_H #include #endif #include diff --git a/os/linux_base.h b/os/linux_base.h index d0048d615..c8b9cad7c 100644 --- a/os/linux_base.h +++ b/os/linux_base.h @@ -15,6 +15,23 @@ #include +#if HAVE_SYS_CDEFS_H +#include +#endif + +#ifndef API_AVAILABLE +#define API_AVAILABLE(...) +#endif +#ifndef API_DEPRECATED +#define API_DEPRECATED(...) +#endif +#ifndef API_UNAVAILABLE +#define API_UNAVAILABLE(...) +#endif +#ifndef API_DEPRECATED_WITH_REPLACEMENT +#define API_DEPRECATED_WITH_REPLACEMENT(...) +#endif + #if __GNUC__ #define OS_EXPECT(x, v) __builtin_expect((x), (v)) #define OS_UNUSED __attribute__((__unused__)) diff --git a/os/object.h b/os/object.h index b98a93e57..100721fc0 100644 --- a/os/object.h +++ b/os/object.h @@ -23,13 +23,11 @@ #ifdef __APPLE__ #include -#include #include -#endif -#ifdef __linux__ -#include -#else +#include #include +#elif defined(__linux__) +#include #endif /*! diff --git a/os/object_private.h b/os/object_private.h index ebaf8549f..2f8cdf468 100644 --- a/os/object_private.h +++ b/os/object_private.h @@ -27,15 +27,9 @@ #ifndef __OS_OBJECT_PRIVATE__ #define __OS_OBJECT_PRIVATE__ -#if HAVE_SYS_CDEFS_H -#include -#endif -#include #include - -#ifndef API_AVAILABLE -#define API_AVAILABLE(...) -#endif +#include +#include #if __GNUC__ #define OS_OBJECT_NOTHROW __attribute__((__nothrow__)) From a15c12c796aa46aa81d5094254e1451a143b9045 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 12 May 2017 08:14:20 -0700 Subject: [PATCH 43/48] build: fix typo in build system This fixes a typo in the build system which is important because it fixes the dependency tracking and the output location for the swift doc that is generated for the swift SDK overlay. Signed-off-by: Daniel A. Steffen --- cmake/modules/SwiftSupport.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index a29fd26db..196593999 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -54,7 +54,7 @@ function(add_swift_library library) add_custom_command(OUTPUT ${ASL_OUTPUT} ${ASL_MODULE_PATH} - ${moodule_directory}/${ASL_MODULE_NAME}.swiftdoc + ${module_directory}/${ASL_MODULE_NAME}.swiftdoc DEPENDS ${ASL_SOURCES} COMMAND @@ -65,5 +65,5 @@ function(add_swift_library library) DEPENDS ${ASL_OUTPUT} ${ASL_MODULE_PATH} - ${moodule_directory}/${ASL_MODULE_NAME}.swiftdoc) + ${module_directory}/${ASL_MODULE_NAME}.swiftdoc) endfunction() From 2735e2211ca91e513a1bf23948069bc342c882d2 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Fri, 12 May 2017 10:45:15 -0700 Subject: [PATCH 44/48] Merge pull request #246 from compnerd/build-dependencies build: fix typo in build system Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index b22aa5cfa..9dae27fe9 100644 --- a/PATCHES +++ b/PATCHES @@ -330,3 +330,4 @@ github commits starting with 29bdc2f from [f76b8f5] APPLIED rdar://32283666 [3828fbb] APPLIED rdar://32283666 [5e8789e] APPLIED rdar://32283666 +[3fba60a] APPLIED rdar://32283666 From 6dcf9a39464b477464dbb9d806a2e9bbc3fae385 Mon Sep 17 00:00:00 2001 From: David Grove Date: Wed, 25 Jan 2017 17:29:01 -0500 Subject: [PATCH 45/48] implement pthread_workqueue within libdispatch Provide an implementation of the pthread_workqueue functionality (libpwq) as a fully integrated component of libdispatch. Integration of the workqueue implementation into the libdispatch code base simplifies the process of evolving the APIs between the two layers and thus prepares for future optimization and enhancements. The overall design is to augment libdispatch's existing pthread_root_queue option with periodic user-space monitoring of the status of a root queue's worker threads and to oversubscribe the workqueue when not enough workers are observed to be runnable when the queue has available work. Initially, the integrated pthread_workqueue is only enabled by default on Linux. The current monitoring implementation relies on Linux-specific code to dynamically estimate the number of runnable worker threads by reading /proc. Porting the monitoring code to non-Linux platforms would entail providing similar functionality for those platforms. Remove libpwq git submodule and autotools support for building libpwq from source as part of building libdispatch. Signed-off-by: Daniel A. Steffen --- .gitmodules | 3 - Makefile.am | 5 - configure.ac | 27 ++-- libpwq | 1 - src/Makefile.am | 16 +- src/apply.c | 14 +- src/event/workqueue.c | 273 +++++++++++++++++++++++++++++++++ src/event/workqueue_internal.h | 52 +++++++ src/inline_internal.h | 2 +- src/queue.c | 104 +++++++++---- src/queue_internal.h | 4 +- src/shims.h | 2 + 12 files changed, 444 insertions(+), 59 deletions(-) delete mode 160000 libpwq create mode 100644 src/event/workqueue.c create mode 100644 src/event/workqueue_internal.h diff --git a/.gitmodules b/.gitmodules index e6068b432..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "libpwq"] - path = libpwq - url = https://github.com/mheily/libpwq.git diff --git a/Makefile.am b/Makefile.am index ffc82df29..f1be02951 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,17 +4,12 @@ ACLOCAL_AMFLAGS = -I m4 -if BUILD_OWN_PTHREAD_WORKQUEUES - MAYBE_PTHREAD_WORKQUEUES = libpwq -endif - if BUILD_TESTS MAYBE_TESTS = tests endif SUBDIRS= \ dispatch \ - $(MAYBE_PTHREAD_WORKQUEUES) \ man \ os \ private \ diff --git a/configure.ac b/configure.ac index 53f8d64a9..050e3d6d1 100644 --- a/configure.ac +++ b/configure.ac @@ -320,22 +320,31 @@ AS_IF([test -n "$apple_libpthread_source_path" -a -n "$apple_xnu_source_osfmk_pa AC_CHECK_HEADERS([pthread_machdep.h pthread/qos.h]) # pthread_workqueues. -# Look for own version first, then system version. -AS_IF([test -f $srcdir/libpwq/configure.ac], - [AC_DEFINE(BUILD_OWN_PTHREAD_WORKQUEUES, 1, [Define if building pthread work queues from source]) - ac_configure_args="--disable-libpwq-install $ac_configure_args" - AC_CONFIG_SUBDIRS([libpwq]) - build_own_pthread_workqueues=true +# Look for own version first, than see if there is a system version. +AC_ARG_ENABLE([internal-libpwq], + [AS_HELP_STRING([--enable-internal-libpwq], + [Use libdispatch's own implementation of pthread workqueues.])],, + [case $target_os in + linux*) + enable_internal_libpwq=yes + ;; + *) + enable_internal_libpwq=no + esac] +) +AS_IF([test "x$enable_internal_libpwq" = "xyes"], + [AC_DEFINE(DISPATCH_USE_INTERNAL_WORKQUEUE, 1, [Use libdispatch's own implementation of pthread_workqueue API]) AC_DEFINE(HAVE_PTHREAD_WORKQUEUES, 1, [Define if pthread work queues are present]) + dispatch_use_internal_workqueue=true have_pthread_workqueues=true], - [build_own_pthread_workqueues=false + [dispatch_use_internal_workqueue=false AC_CHECK_HEADERS([pthread/workqueue_private.h pthread_workqueue.h], [AC_DEFINE(HAVE_PTHREAD_WORKQUEUES, 1, [Define if pthread work queues are present]) have_pthread_workqueues=true], [have_pthread_workqueues=false] - )] + )] ) -AM_CONDITIONAL(BUILD_OWN_PTHREAD_WORKQUEUES, $build_own_pthread_workqueues) +AM_CONDITIONAL(DISPATCH_USE_INTERNAL_WORKQUEUE, $dispatch_use_internal_workqueue) AM_CONDITIONAL(HAVE_PTHREAD_WORKQUEUES, $have_pthread_workqueues) AC_CHECK_HEADERS([libproc_internal.h], [], [], [#include ]) diff --git a/libpwq b/libpwq deleted file mode 160000 index 18437d2be..000000000 --- a/libpwq +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 18437d2be372f4422b207ec6442c8caf7974025d diff --git a/src/Makefile.am b/src/Makefile.am index a0ddbc98b..ac2f74cfd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,6 +9,12 @@ else lib_LTLIBRARIES=libdispatch.la endif +if DISPATCH_USE_INTERNAL_WORKQUEUE +INTERNAL_WORKQUEUE_SOURCES= \ + event/workqueue.c \ + event/workqueue_internal.h +endif + libdispatch_la_SOURCES= \ allocator.c \ apply.c \ @@ -60,7 +66,8 @@ libdispatch_la_SOURCES= \ shims/perfmon.h \ shims/time.h \ shims/tsd.h \ - shims/yield.h + shims/yield.h \ + $(INTERNAL_WORKQUEUE_SOURCES) EXTRA_libdispatch_la_SOURCES= EXTRA_libdispatch_la_DEPENDENCIES= @@ -77,12 +84,13 @@ AM_OBJCFLAGS=$(DISPATCH_CFLAGS) $(CBLOCKS_FLAGS) AM_CXXFLAGS=$(PTHREAD_WORKQUEUE_CFLAGS) $(DISPATCH_CFLAGS) $(CXXBLOCKS_FLAGS) AM_OBJCXXFLAGS=$(DISPATCH_CFLAGS) $(CXXBLOCKS_FLAGS) -if BUILD_OWN_PTHREAD_WORKQUEUES - PTHREAD_WORKQUEUE_LIBS=$(top_builddir)/libpwq/libpthread_workqueue.la - PTHREAD_WORKQUEUE_CFLAGS=-I$(top_srcdir)/libpwq/include +if DISPATCH_USE_INTERNAL_WORKQUEUE + PTHREAD_WORKQUEUE_LIBS= + PTHREAD_WORKQUEUE_CFLAGS= else if HAVE_PTHREAD_WORKQUEUES PTHREAD_WORKQUEUE_LIBS=-lpthread_workqueue + PTHREAD_WORKQUEUE_CFLAGS= endif endif diff --git a/src/apply.c b/src/apply.c index 79c4e9594..0f1d85d77 100644 --- a/src/apply.c +++ b/src/apply.c @@ -159,11 +159,11 @@ static inline void _dispatch_apply_f2(dispatch_queue_t dq, dispatch_apply_t da, dispatch_function_t func) { - uint32_t i = 0; + int32_t i = 0; dispatch_continuation_t head = NULL, tail = NULL; // The current thread does not need a continuation - uint32_t continuation_cnt = da->da_thr_cnt - 1; + int32_t continuation_cnt = da->da_thr_cnt - 1; dispatch_assert(continuation_cnt); @@ -192,14 +192,14 @@ static void _dispatch_apply_redirect(void *ctxt) { dispatch_apply_t da = (dispatch_apply_t)ctxt; - uint32_t da_width = da->da_thr_cnt - 1; + int32_t da_width = da->da_thr_cnt - 1; dispatch_queue_t dq = da->da_dc->dc_data, rq = dq, tq; do { - uint32_t width = _dispatch_queue_try_reserve_apply_width(rq, da_width); + int32_t width = _dispatch_queue_try_reserve_apply_width(rq, da_width); if (slowpath(da_width > width)) { - uint32_t excess = da_width - width; + int32_t excess = da_width - width; for (tq = dq; tq != rq; tq = tq->do_targetq) { _dispatch_queue_relinquish_width(tq, excess); } @@ -234,7 +234,7 @@ dispatch_apply_f(size_t iterations, dispatch_queue_t dq, void *ctxt, if (slowpath(iterations == 0)) { return; } - uint32_t thr_cnt = dispatch_hw_config(active_cpus); + int32_t thr_cnt = dispatch_hw_config(active_cpus); dispatch_thread_context_t dtctxt = _dispatch_thread_context_find(_dispatch_apply_key); size_t nested = dtctxt ? dtctxt->dtc_apply_nesting : 0; dispatch_queue_t old_dq = _dispatch_queue_get_current(); @@ -247,7 +247,7 @@ dispatch_apply_f(size_t iterations, dispatch_queue_t dq, void *ctxt, ? nested * iterations : DISPATCH_APPLY_MAX; } if (iterations < thr_cnt) { - thr_cnt = (uint32_t)iterations; + thr_cnt = iterations; } if (slowpath(dq == DISPATCH_APPLY_CURRENT_ROOT_QUEUE)) { dq = old_dq ? old_dq : _dispatch_get_root_queue( diff --git a/src/event/workqueue.c b/src/event/workqueue.c new file mode 100644 index 000000000..0b9bc0ac5 --- /dev/null +++ b/src/event/workqueue.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2017-2017 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +#include "internal.h" + +#if DISPATCH_USE_INTERNAL_WORKQUEUE + +// forward looking typedef; not yet defined in dispatch +typedef pid_t dispatch_tid; + +/* + * dispatch_workq monitors the thread pool that is + * executing the work enqueued on libdispatch's pthread + * root queues and dynamically adjusts its size. + * + * The dynamic monitoring could be implemented using either + * (a) low-frequency user-level approximation of the number of runnable + * worker threads via reading the /proc file system + * (b) a Linux kernel extension that hooks the process change handler + * to accurately track the number of runnable normal worker threads + * This file provides an implementation of option (a). + * + * Using either form of monitoring, if (i) there appears to be + * work available in the monitored pthread root queue, (ii) the + * number of runnable workers is below the target size for the pool, + * and (iii) the total number of worker threads is below an upper limit, + * then an additional worker thread will be added to the pool. + */ + +#pragma mark static data for monitoring subsystem + +/* + * State for the user-level monitoring of a workqueue. + */ +typedef struct dispatch_workq_monitor_s { + /* The dispatch_queue we are monitoring */ + dispatch_queue_t dq; + + /* The observed number of runnable worker threads */ + int32_t num_runnable; + + /* The desired number of runnable worker threads */ + int32_t target_runnable; + + /* + * Tracking of registered workers; all accesses must hold lock. + * Invariant: registered_tids[0]...registered_tids[num_registered_tids-1] + * contain the dispatch_tids of the worker threads we are monitoring. + */ + dispatch_unfair_lock_s registered_tid_lock; + dispatch_tid *registered_tids; + int num_registered_tids; +} dispatch_workq_monitor_s, *dispatch_workq_monitor_t; + +static dispatch_workq_monitor_s _dispatch_workq_monitors[WORKQ_NUM_PRIORITIES]; + +#pragma mark Implementation of the monitoring subsystem. + +#define WORKQ_MAX_TRACKED_TIDS DISPATCH_WORKQ_MAX_PTHREAD_COUNT +#define WORKQ_OVERSUBSCRIBE_FACTOR 2 + +static void _dispatch_workq_init_once(void *context DISPATCH_UNUSED); +static dispatch_once_t _dispatch_workq_init_once_pred; + +void +_dispatch_workq_worker_register(dispatch_queue_t root_q, int priority) +{ + dispatch_once_f(&_dispatch_workq_init_once_pred, NULL, &_dispatch_workq_init_once); + +#if HAVE_DISPATCH_WORKQ_MONITORING + dispatch_workq_monitor_t mon = &_dispatch_workq_monitors[priority]; + dispatch_assert(mon->dq == root_q); + dispatch_tid tid = _dispatch_thread_getspecific(tid); + _dispatch_unfair_lock_lock(&mon->registered_tid_lock); + dispatch_assert(mon->num_registered_tids < WORKQ_MAX_TRACKED_TIDS-1); + int worker_id = mon->num_registered_tids++; + mon->registered_tids[worker_id] = tid; + _dispatch_unfair_lock_unlock(&mon->registered_tid_lock); +#endif // HAVE_DISPATCH_WORKQ_MONITORING +} + +void +_dispatch_workq_worker_unregister(dispatch_queue_t root_q, int priority) +{ +#if HAVE_DISPATCH_WORKQ_MONITORING + dispatch_workq_monitor_t mon = &_dispatch_workq_monitors[priority]; + dispatch_tid tid = _dispatch_thread_getspecific(tid); + _dispatch_unfair_lock_lock(&mon->registered_tid_lock); + for (int i = 0; i < mon->num_registered_tids; i++) { + if (mon->registered_tids[i] == tid) { + int last = mon->num_registered_tids - 1; + mon->registered_tids[i] = mon->registered_tids[last]; + mon->registered_tids[last] = 0; + mon->num_registered_tids--; + break; + } + } + _dispatch_unfair_lock_unlock(&mon->registered_tid_lock); +#endif // HAVE_DISPATCH_WORKQ_MONITORING +} + + +#if HAVE_DISPATCH_WORKQ_MONITORING +#if defined(__linux__) +/* + * For each pid that is a registered worker, read /proc/[pid]/stat + * to get a count of the number of them that are actually runnable. + * See the proc(5) man page for the format of the contents of /proc/[pid]/stat + */ +static void +_dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) +{ + char path[128]; + char buf[4096]; + int running_count = 0; + + _dispatch_unfair_lock_lock(&mon->registered_tid_lock); + + for (int i = 0; i < mon->num_registered_tids; i++) { + dispatch_tid tid = mon->registered_tids[i]; + int fd; + size_t bytes_read = -1; + + int r = snprintf(path, sizeof(path), "/proc/%d/stat", tid); + dispatch_assert(r > 0 && r < sizeof(path)); + + fd = open(path, O_RDONLY | O_NONBLOCK); + if (unlikely(fd == -1)) { + DISPATCH_CLIENT_CRASH(tid, + "workq: registered worker exited prematurely"); + } else { + bytes_read = read(fd, buf, sizeof(buf)-1); + (void)close(fd); + } + + if (bytes_read > 0) { + buf[bytes_read] = '\0'; + char state; + if (sscanf(buf, "%*d %*s %c", &state) == 1) { + // _dispatch_debug("workq: Worker %d, state %c\n", tid, state); + if (state == 'R') { + running_count++; + } + } else { + _dispatch_debug("workq: sscanf of state failed for %d", tid); + } + } else { + _dispatch_debug("workq: Failed to read %s", path); + } + } + + mon->num_runnable = running_count; + + _dispatch_unfair_lock_unlock(&mon->registered_tid_lock); +} +#else +#error must define _dispatch_workq_count_runnable_workers +#endif + +static void +_dispatch_workq_monitor_pools(void *context DISPATCH_UNUSED) +{ + // TODO: Once we switch away from the legacy priorities to + // newer QoS, we can loop in order of decreasing QoS + // and track the total number of runnable threads seen + // across pools. We can then use that number to + // implement a global policy where low QoS queues + // are not eligible for over-subscription if the higher + // QoS queues have already consumed the target + // number of threads. + for (int i = 0; i < WORKQ_NUM_PRIORITIES; i++) { + dispatch_workq_monitor_t mon = &_dispatch_workq_monitors[i]; + dispatch_queue_t dq = mon->dq; + + if (!_dispatch_queue_class_probe(dq)) { + _dispatch_debug("workq: %s is empty.", dq->dq_label); + continue; + } + + _dispatch_workq_count_runnable_workers(mon); + _dispatch_debug("workq: %s has %d runnable wokers (target is %d)", + dq->dq_label, mon->num_runnable, mon->target_runnable); + + if (mon->num_runnable == 0) { + // We are below target, and no worker is runnable. + // It is likely the program is stalled. Therefore treat + // this as if dq were an overcommit queue and call poke + // with the limit being the maximum number of workers for dq. + int32_t floor = mon->target_runnable - WORKQ_MAX_TRACKED_TIDS; + _dispatch_debug("workq: %s has no runnable workers; poking with floor %d", + dq->dq_label, floor); + _dispatch_global_queue_poke(dq, 1, floor); + } else if (mon->num_runnable < mon->target_runnable) { + // We are below target, but some workers are still runnable. + // We want to oversubscribe to hit the desired load target. + // However, this under-utilization may be transitory so set the + // floor as a small multiple of threads per core. + int32_t floor = (1 - WORKQ_OVERSUBSCRIBE_FACTOR) * mon->target_runnable; + int32_t floor2 = mon->target_runnable - WORKQ_MAX_TRACKED_TIDS; + floor = MAX(floor, floor2); + _dispatch_debug("workq: %s under utilization target; poking with floor %d", + dq->dq_label, floor); + _dispatch_global_queue_poke(dq, 1, floor); + } + } +} +#endif // HAVE_DISPATCH_WORKQ_MONITORING + + +// temporary until we switch over to QoS based interface. +static dispatch_queue_t +get_root_queue_from_legacy_priority(int priority) +{ + switch (priority) { + case WORKQ_HIGH_PRIOQUEUE: + return &_dispatch_root_queues[DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS]; + case WORKQ_DEFAULT_PRIOQUEUE: + return &_dispatch_root_queues[DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS]; + case WORKQ_LOW_PRIOQUEUE: + return &_dispatch_root_queues[DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS]; + case WORKQ_BG_PRIOQUEUE: + return &_dispatch_root_queues[DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS]; + case WORKQ_BG_PRIOQUEUE_CONDITIONAL: + return &_dispatch_root_queues[DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS]; + case WORKQ_HIGH_PRIOQUEUE_CONDITIONAL: + return &_dispatch_root_queues[DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS]; + default: + return NULL; + } +} + +static void +_dispatch_workq_init_once(void *context DISPATCH_UNUSED) +{ +#if HAVE_DISPATCH_WORKQ_MONITORING + int target_runnable = dispatch_hw_config(active_cpus); + for (int i = 0; i < WORKQ_NUM_PRIORITIES; i++) { + dispatch_workq_monitor_t mon = &_dispatch_workq_monitors[i]; + mon->dq = get_root_queue_from_legacy_priority(i); + void *buf = _dispatch_calloc(WORKQ_MAX_TRACKED_TIDS, sizeof(dispatch_tid)); + mon->registered_tids = buf; + mon->target_runnable = target_runnable; + } + + // Create monitoring timer that will periodically run on dispatch_mgr_q + dispatch_source_t ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, + 0, 0, &_dispatch_mgr_q); + dispatch_source_set_timer(ds, dispatch_time(DISPATCH_TIME_NOW, 0), + NSEC_PER_SEC, 0); + dispatch_source_set_event_handler_f(ds, _dispatch_workq_monitor_pools); + dispatch_set_context(ds, ds); // avoid appearing as leaked + dispatch_activate(ds); +#endif // HAVE_DISPATCH_WORKQ_MONITORING +} + +#endif // DISPATCH_USE_INTERNAL_WORKQUEUE diff --git a/src/event/workqueue_internal.h b/src/event/workqueue_internal.h new file mode 100644 index 000000000..012e554fb --- /dev/null +++ b/src/event/workqueue_internal.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017-2017 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + * IMPORTANT: This header file describes INTERNAL interfaces to libdispatch + * which are subject to change in future releases of Mac OS X. Any applications + * relying on these interfaces WILL break. + */ + +#ifndef __DISPATCH_WORKQUEUE_INTERNAL__ +#define __DISPATCH_WORKQUEUE_INTERNAL__ + +/* Work queue priority attributes. */ +#define WORKQ_HIGH_PRIOQUEUE 0 +#define WORKQ_DEFAULT_PRIOQUEUE 1 +#define WORKQ_LOW_PRIOQUEUE 2 +#define WORKQ_BG_PRIOQUEUE 3 +#define WORKQ_BG_PRIOQUEUE_CONDITIONAL 4 +#define WORKQ_HIGH_PRIOQUEUE_CONDITIONAL 5 + +#define WORKQ_NUM_PRIORITIES 6 + +#define DISPATCH_WORKQ_MAX_PTHREAD_COUNT 255 + +void _dispatch_workq_worker_register(dispatch_queue_t root_q, int priority); +void _dispatch_workq_worker_unregister(dispatch_queue_t root_q, int priority); + +#if defined(__linux__) +#define HAVE_DISPATCH_WORKQ_MONITORING 1 +#else +#define HAVE_DISPATCH_WORKQ_MONITORING 0 +#endif + +#endif /* __DISPATCH_WORKQUEUE_INTERNAL__ */ + diff --git a/src/inline_internal.h b/src/inline_internal.h index a7ccb8260..d76b77aff 100644 --- a/src/inline_internal.h +++ b/src/inline_internal.h @@ -1479,7 +1479,7 @@ _dispatch_root_queue_push_inline(dispatch_queue_t dq, dispatch_object_t _head, struct dispatch_object_s *head = _head._do, *tail = _tail._do; if (unlikely(_dispatch_queue_push_update_tail_list(dq, head, tail))) { _dispatch_queue_push_update_head(dq, head); - return _dispatch_global_queue_poke(dq, n); + return _dispatch_global_queue_poke(dq, n, 0); } } diff --git a/src/queue.c b/src/queue.c index be831ab4c..42b51f3eb 100644 --- a/src/queue.c +++ b/src/queue.c @@ -23,7 +23,7 @@ #include "protocol.h" // _dispatch_send_wakeup_runloop_thread #endif -#if (!HAVE_PTHREAD_WORKQUEUES || DISPATCH_DEBUG) && \ +#if (!HAVE_PTHREAD_WORKQUEUES || DISPATCH_DEBUG || DISPATCH_USE_INTERNAL_WORKQUEUE) && \ !defined(DISPATCH_ENABLE_THREAD_POOL) #define DISPATCH_ENABLE_THREAD_POOL 1 #endif @@ -32,6 +32,7 @@ #endif #if HAVE_PTHREAD_WORKQUEUES && (!HAVE_PTHREAD_WORKQUEUE_QOS || DISPATCH_DEBUG) && \ !HAVE_PTHREAD_WORKQUEUE_SETDISPATCH_NP && \ + !DISPATCH_USE_INTERNAL_WORKQUEUE && \ !defined(DISPATCH_USE_LEGACY_WORKQUEUE_FALLBACK) #define DISPATCH_USE_LEGACY_WORKQUEUE_FALLBACK 1 #endif @@ -142,12 +143,14 @@ static struct dispatch_pthread_root_queue_context_s }; #endif -#define MAX_PTHREAD_COUNT 255 +#ifndef DISPATCH_WORKQ_MAX_PTHREAD_COUNT +#define DISPATCH_WORKQ_MAX_PTHREAD_COUNT 255 +#endif struct dispatch_root_queue_context_s { union { struct { - unsigned int volatile dgq_pending; + int volatile dgq_pending; #if HAVE_PTHREAD_WORKQUEUES qos_class_t dgq_qos; int dgq_wq_priority, dgq_wq_options; @@ -157,7 +160,7 @@ struct dispatch_root_queue_context_s { #endif // HAVE_PTHREAD_WORKQUEUES #if DISPATCH_USE_PTHREAD_POOL void *dgq_ctxt; - uint32_t volatile dgq_thread_pool_size; + int32_t volatile dgq_thread_pool_size; #endif }; char _dgq_pad[DISPATCH_CACHELINE_SIZE]; @@ -662,7 +665,15 @@ _dispatch_root_queues_init_workq(int *wq_supported) result = result || dispatch_assume(pwq); } #endif // DISPATCH_USE_LEGACY_WORKQUEUE_FALLBACK - qc->dgq_kworkqueue = pwq ? pwq : (void*)(~0ul); + if (pwq) { + qc->dgq_kworkqueue = pwq; + } else { + qc->dgq_kworkqueue = (void*)(~0ul); + // because the fastpath of _dispatch_global_queue_poke didn't + // know yet that we're using the internal pool implementation + // we have to undo its setting of dgq_pending + qc->dgq_pending = 0; + } } #if DISPATCH_USE_LEGACY_WORKQUEUE_FALLBACK if (!disable_wq) { @@ -679,10 +690,10 @@ _dispatch_root_queues_init_workq(int *wq_supported) #if DISPATCH_USE_PTHREAD_POOL static inline void _dispatch_root_queue_init_pthread_pool(dispatch_root_queue_context_t qc, - uint8_t pool_size, bool overcommit) + int32_t pool_size, bool overcommit) { dispatch_pthread_root_queue_context_t pqc = qc->dgq_ctxt; - uint32_t thread_pool_size = overcommit ? MAX_PTHREAD_COUNT : + int32_t thread_pool_size = overcommit ? DISPATCH_WORKQ_MAX_PTHREAD_COUNT : dispatch_hw_config(active_cpus); if (slowpath(pool_size) && pool_size < thread_pool_size) { thread_pool_size = pool_size; @@ -715,7 +726,7 @@ _dispatch_root_queues_init_once(void *context DISPATCH_UNUSED) size_t i; for (i = 0; i < DISPATCH_ROOT_QUEUE_COUNT; i++) { bool overcommit = true; -#if TARGET_OS_EMBEDDED +#if TARGET_OS_EMBEDDED || (DISPATCH_USE_INTERNAL_WORKQUEUE && HAVE_DISPATCH_WORKQ_MONITORING) // some software hangs if the non-overcommitting queues do not // overcommit when threads block. Someday, this behavior should // apply to all platforms @@ -1978,8 +1989,8 @@ _dispatch_pthread_root_queue_create(const char *label, unsigned long flags, dispatch_pthread_root_queue_context_t pqc; dispatch_queue_flags_t dqf = 0; size_t dqs; - uint8_t pool_size = flags & _DISPATCH_PTHREAD_ROOT_QUEUE_FLAG_POOL_SIZE ? - (uint8_t)(flags & ~_DISPATCH_PTHREAD_ROOT_QUEUE_FLAG_POOL_SIZE) : 0; + int32_t pool_size = flags & _DISPATCH_PTHREAD_ROOT_QUEUE_FLAG_POOL_SIZE ? + (int8_t)(flags & ~_DISPATCH_PTHREAD_ROOT_QUEUE_FLAG_POOL_SIZE) : 0; dqs = sizeof(struct dispatch_queue_s) - DISPATCH_QUEUE_CACHELINE_PAD; dqs = roundup(dqs, _Alignof(struct dispatch_root_queue_context_s)); @@ -3944,10 +3955,10 @@ _dispatch_runloop_queue_poke(dispatch_queue_t dq, dispatch_qos_t qos, DISPATCH_NOINLINE static void -_dispatch_global_queue_poke_slow(dispatch_queue_t dq, unsigned int n) +_dispatch_global_queue_poke_slow(dispatch_queue_t dq, int n, int floor) { dispatch_root_queue_context_t qc = dq->do_ctxt; - uint32_t i = n; + int remaining = n; int r = ENOSYS; _dispatch_root_queues_init(); @@ -3967,16 +3978,16 @@ _dispatch_global_queue_poke_slow(dispatch_queue_t dq, unsigned int n) r = pthread_workqueue_additem_np(qc->dgq_kworkqueue, _dispatch_worker_thread4, dq, &wh, &gen_cnt); (void)dispatch_assume_zero(r); - } while (--i); + } while (--remaining); return; } #endif // DISPATCH_USE_LEGACY_WORKQUEUE_FALLBACK #if HAVE_PTHREAD_WORKQUEUE_QOS - r = _pthread_workqueue_addthreads((int)i, + r = _pthread_workqueue_addthreads(remaining, _dispatch_priority_to_pp(dq->dq_priority)); #elif HAVE_PTHREAD_WORKQUEUE_SETDISPATCH_NP r = pthread_workqueue_addthreads_np(qc->dgq_wq_priority, - qc->dgq_wq_options, (int)i); + qc->dgq_wq_options, remaining); #endif (void)dispatch_assume_zero(r); return; @@ -3986,23 +3997,43 @@ _dispatch_global_queue_poke_slow(dispatch_queue_t dq, unsigned int n) dispatch_pthread_root_queue_context_t pqc = qc->dgq_ctxt; if (fastpath(pqc->dpq_thread_mediator.do_vtable)) { while (dispatch_semaphore_signal(&pqc->dpq_thread_mediator)) { - if (!--i) { + _dispatch_root_queue_debug("signaled sleeping worker for " + "global queue: %p", dq); + if (!--remaining) { return; } } } - uint32_t j, t_count; + + bool overcommit = dq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT; + if (overcommit) { + os_atomic_add2o(qc, dgq_pending, remaining, relaxed); + } else { + if (!os_atomic_cmpxchg2o(qc, dgq_pending, 0, remaining, relaxed)) { + _dispatch_root_queue_debug("worker thread request still pending for " + "global queue: %p", dq); + return; + } + } + + int32_t can_request, t_count; // seq_cst with atomic store to tail t_count = os_atomic_load2o(qc, dgq_thread_pool_size, ordered); do { - if (!t_count) { + can_request = t_count < floor ? 0 : t_count - floor; + if (remaining > can_request) { + _dispatch_root_queue_debug("pthread pool reducing request from %d to %d", + remaining, can_request); + os_atomic_sub2o(qc, dgq_pending, remaining - can_request, relaxed); + remaining = can_request; + } + if (remaining == 0) { _dispatch_root_queue_debug("pthread pool is full for root queue: " "%p", dq); return; } - j = i > t_count ? t_count : i; } while (!os_atomic_cmpxchgvw2o(qc, dgq_thread_pool_size, t_count, - t_count - j, &t_count, acquire)); + t_count - remaining, &t_count, acquire)); pthread_attr_t *attr = &pqc->dpq_thread_attr; pthread_t tid, *pthr = &tid; @@ -4019,13 +4050,13 @@ _dispatch_global_queue_poke_slow(dispatch_queue_t dq, unsigned int n) } _dispatch_temporary_resource_shortage(); } - } while (--j); + } while (--remaining); #endif // DISPATCH_USE_PTHREAD_POOL } DISPATCH_NOINLINE void -_dispatch_global_queue_poke(dispatch_queue_t dq, unsigned int n) +_dispatch_global_queue_poke(dispatch_queue_t dq, int n, int floor) { if (!_dispatch_queue_class_probe(dq)) { return; @@ -4042,7 +4073,7 @@ _dispatch_global_queue_poke(dispatch_queue_t dq, unsigned int n) return; } #endif // HAVE_PTHREAD_WORKQUEUES - return _dispatch_global_queue_poke_slow(dq, n); + return _dispatch_global_queue_poke_slow(dq, n, floor); } #pragma mark - @@ -5247,7 +5278,7 @@ _dispatch_root_queue_drain_one_slow(dispatch_queue_t dq) (void)os_atomic_dec2o(qc, dgq_pending, relaxed); } if (!available) { - _dispatch_global_queue_poke(dq, 1); + _dispatch_global_queue_poke(dq, 1, 0); } return available; } @@ -5314,7 +5345,7 @@ _dispatch_root_queue_drain_one(dispatch_queue_t dq) } os_atomic_store2o(dq, dq_items_head, next, relaxed); - _dispatch_global_queue_poke(dq, 1); + _dispatch_global_queue_poke(dq, 1, 0); out: return head; } @@ -5411,7 +5442,7 @@ _dispatch_worker_thread4(void *context) dispatch_root_queue_context_t qc = dq->do_ctxt; _dispatch_introspection_thread_add(); - int pending = (int)os_atomic_dec2o(qc, dgq_pending, relaxed); + int pending = os_atomic_dec2o(qc, dgq_pending, relaxed); dispatch_assert(pending >= 0); _dispatch_root_queue_drain(dq, _dispatch_get_priority()); _dispatch_voucher_debug("root queue clear", NULL); @@ -5457,6 +5488,11 @@ _dispatch_worker_thread(void *context) dispatch_root_queue_context_t qc = dq->do_ctxt; dispatch_pthread_root_queue_context_t pqc = qc->dgq_ctxt; + int pending = os_atomic_dec2o(qc, dgq_pending, relaxed); + if (unlikely(pending < 0)) { + DISPATCH_INTERNAL_CRASH(pending, "Pending thread request underflow"); + } + if (pqc->dpq_observer_hooks.queue_will_execute) { _dispatch_set_pthread_root_queue_observer_hooks( &pqc->dpq_observer_hooks); @@ -5469,6 +5505,15 @@ _dispatch_worker_thread(void *context) _dispatch_sigmask(); _dispatch_introspection_thread_add(); +#if DISPATCH_USE_INTERNAL_WORKQUEUE + bool overcommit = (qc->dgq_wq_options & WORKQ_ADDTHREADS_OPTION_OVERCOMMIT); + bool manager = (dq == &_dispatch_mgr_root_queue); + bool monitored = !(overcommit || manager); + if (monitored) { + _dispatch_workq_worker_register(dq, qc->dgq_wq_priority); + } +#endif + const int64_t timeout = 5ull * NSEC_PER_SEC; pthread_priority_t old_pri = _dispatch_get_priority(); do { @@ -5477,8 +5522,13 @@ _dispatch_worker_thread(void *context) } while (dispatch_semaphore_wait(&pqc->dpq_thread_mediator, dispatch_time(0, timeout)) == 0); +#if DISPATCH_USE_INTERNAL_WORKQUEUE + if (monitored) { + _dispatch_workq_worker_unregister(dq, qc->dgq_wq_priority); + } +#endif (void)os_atomic_inc2o(qc, dgq_thread_pool_size, release); - _dispatch_global_queue_poke(dq, 1); + _dispatch_global_queue_poke(dq, 1, 0); _dispatch_release(dq); return NULL; diff --git a/src/queue_internal.h b/src/queue_internal.h index ca9886c61..91a31864a 100644 --- a/src/queue_internal.h +++ b/src/queue_internal.h @@ -563,7 +563,7 @@ void _dispatch_queue_resume(dispatch_queue_t dq, bool activate); void _dispatch_queue_finalize_activation(dispatch_queue_t dq); void _dispatch_queue_invoke(dispatch_queue_t dq, dispatch_invoke_context_t dic, dispatch_invoke_flags_t flags); -void _dispatch_global_queue_poke(dispatch_queue_t dq, unsigned int n); +void _dispatch_global_queue_poke(dispatch_queue_t dq, int n, int floor); void _dispatch_queue_push(dispatch_queue_t dq, dispatch_object_t dou, dispatch_qos_t qos); void _dispatch_try_lock_transfer_or_wakeup(dispatch_queue_t dq); @@ -945,7 +945,7 @@ struct dispatch_apply_s { dispatch_continuation_t da_dc; dispatch_thread_event_s da_event; dispatch_invoke_flags_t da_flags; - uint32_t da_thr_cnt; + int32_t da_thr_cnt; }; typedef struct dispatch_apply_s *dispatch_apply_t; diff --git a/src/shims.h b/src/shims.h index 8434341ec..c9d727592 100644 --- a/src/shims.h +++ b/src/shims.h @@ -41,6 +41,8 @@ #if HAVE_PTHREAD_WORKQUEUES #if __has_include() #include +#elif DISPATCH_USE_INTERNAL_WORKQUEUE +#include #else #include #endif From 624ae1dc035dfd8b1d18bd0cc66ea13e78d4b0e3 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 18 May 2017 13:45:43 -0700 Subject: [PATCH 46/48] Merge pull request #206 from dgrove-oss/internal-pwq-impl implement pthread_workqueue within libdispatch Signed-off-by: Daniel A. Steffen --- PATCHES | 1 + 1 file changed, 1 insertion(+) diff --git a/PATCHES b/PATCHES index 9dae27fe9..963c8b113 100644 --- a/PATCHES +++ b/PATCHES @@ -331,3 +331,4 @@ github commits starting with 29bdc2f from [3828fbb] APPLIED rdar://32283666 [5e8789e] APPLIED rdar://32283666 [3fba60a] APPLIED rdar://32283666 +[d6eb245] APPLIED rdar://32283666 From 2e6188ec64eb906e3227e81b60176c340cadac62 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 18 May 2017 18:30:11 -0700 Subject: [PATCH 47/48] fix #include of project header Signed-off-by: Daniel A. Steffen --- src/shims.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims.h b/src/shims.h index c9d727592..eba277470 100644 --- a/src/shims.h +++ b/src/shims.h @@ -42,7 +42,7 @@ #if __has_include() #include #elif DISPATCH_USE_INTERNAL_WORKQUEUE -#include +#include "event/workqueue_internal.h" #else #include #endif From 5e87d7c7ad6a530df3da03eb211aa6d72fdfc454 Mon Sep 17 00:00:00 2001 From: "Daniel A. Steffen" Date: Thu, 18 May 2017 20:33:16 -0700 Subject: [PATCH 48/48] fix build failures due to signed vs unsigned warnings Signed-off-by: Daniel A. Steffen --- src/apply.c | 11 ++++++----- src/inline_internal.h | 30 +++++++++++++++--------------- src/queue.c | 2 +- src/trace.h | 2 +- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/apply.c b/src/apply.c index 0f1d85d77..40e6f3275 100644 --- a/src/apply.c +++ b/src/apply.c @@ -234,20 +234,21 @@ dispatch_apply_f(size_t iterations, dispatch_queue_t dq, void *ctxt, if (slowpath(iterations == 0)) { return; } - int32_t thr_cnt = dispatch_hw_config(active_cpus); - dispatch_thread_context_t dtctxt = _dispatch_thread_context_find(_dispatch_apply_key); + int32_t thr_cnt = (int32_t)dispatch_hw_config(active_cpus); + dispatch_thread_context_t dtctxt = + _dispatch_thread_context_find(_dispatch_apply_key); size_t nested = dtctxt ? dtctxt->dtc_apply_nesting : 0; dispatch_queue_t old_dq = _dispatch_queue_get_current(); if (!slowpath(nested)) { nested = iterations; } else { - thr_cnt = nested < thr_cnt ? thr_cnt / nested : 1; + thr_cnt = nested < (size_t)thr_cnt ? thr_cnt / (int32_t)nested : 1; nested = nested < DISPATCH_APPLY_MAX && iterations < DISPATCH_APPLY_MAX ? nested * iterations : DISPATCH_APPLY_MAX; } - if (iterations < thr_cnt) { - thr_cnt = iterations; + if (iterations < (size_t)thr_cnt) { + thr_cnt = (int32_t)iterations; } if (slowpath(dq == DISPATCH_APPLY_CURRENT_ROOT_QUEUE)) { dq = old_dq ? old_dq : _dispatch_get_root_queue( diff --git a/src/inline_internal.h b/src/inline_internal.h index d76b77aff..53548eded 100644 --- a/src/inline_internal.h +++ b/src/inline_internal.h @@ -592,18 +592,18 @@ _dq_state_has_side_suspend_cnt(uint64_t dq_state) } DISPATCH_ALWAYS_INLINE -static inline uint32_t +static inline int32_t _dq_state_extract_width_bits(uint64_t dq_state) { dq_state &= DISPATCH_QUEUE_WIDTH_MASK; - return (uint32_t)(dq_state >> DISPATCH_QUEUE_WIDTH_SHIFT); + return (int32_t)(dq_state >> DISPATCH_QUEUE_WIDTH_SHIFT); } DISPATCH_ALWAYS_INLINE -static inline uint32_t +static inline int32_t _dq_state_available_width(uint64_t dq_state) { - uint32_t full = DISPATCH_QUEUE_WIDTH_FULL; + int32_t full = DISPATCH_QUEUE_WIDTH_FULL; if (likely(!(dq_state & DISPATCH_QUEUE_WIDTH_FULL_BIT))) { return full - _dq_state_extract_width_bits(dq_state); } @@ -611,11 +611,11 @@ _dq_state_available_width(uint64_t dq_state) } DISPATCH_ALWAYS_INLINE -static inline uint32_t +static inline int32_t _dq_state_used_width(uint64_t dq_state, uint16_t dq_width) { - uint32_t full = DISPATCH_QUEUE_WIDTH_FULL; - uint32_t width = _dq_state_extract_width_bits(dq_state); + int32_t full = DISPATCH_QUEUE_WIDTH_FULL; + int32_t width = _dq_state_extract_width_bits(dq_state); if (dq_state & DISPATCH_QUEUE_PENDING_BARRIER) { // DISPATCH_QUEUE_PENDING_BARRIER means (dq_width - 1) of the used width @@ -1030,21 +1030,21 @@ _dispatch_queue_try_reserve_sync_width(dispatch_queue_t dq) * possibly 0 */ DISPATCH_ALWAYS_INLINE DISPATCH_WARN_RESULT -static inline uint32_t -_dispatch_queue_try_reserve_apply_width(dispatch_queue_t dq, uint32_t da_width) +static inline int32_t +_dispatch_queue_try_reserve_apply_width(dispatch_queue_t dq, int32_t da_width) { uint64_t old_state, new_state; - uint32_t width; + int32_t width; (void)os_atomic_rmw_loop2o(dq, dq_state, old_state, new_state, relaxed, { - width = _dq_state_available_width(old_state); + width = (int32_t)_dq_state_available_width(old_state); if (unlikely(!width)) { os_atomic_rmw_loop_give_up(return 0); } if (width > da_width) { width = da_width; } - new_state = old_state + width * DISPATCH_QUEUE_WIDTH_INTERVAL; + new_state = old_state + (uint64_t)width * DISPATCH_QUEUE_WIDTH_INTERVAL; }); return width; } @@ -1055,10 +1055,10 @@ _dispatch_queue_try_reserve_apply_width(dispatch_queue_t dq, uint32_t da_width) */ DISPATCH_ALWAYS_INLINE static inline void -_dispatch_queue_relinquish_width(dispatch_queue_t dq, uint32_t da_width) +_dispatch_queue_relinquish_width(dispatch_queue_t dq, int32_t da_width) { (void)os_atomic_sub2o(dq, dq_state, - da_width * DISPATCH_QUEUE_WIDTH_INTERVAL, relaxed); + (uint64_t)da_width * DISPATCH_QUEUE_WIDTH_INTERVAL, relaxed); } /* Used by target-queue recursing code @@ -1474,7 +1474,7 @@ _dispatch_queue_push_update_head(dispatch_queue_t dq, DISPATCH_ALWAYS_INLINE static inline void _dispatch_root_queue_push_inline(dispatch_queue_t dq, dispatch_object_t _head, - dispatch_object_t _tail, unsigned int n) + dispatch_object_t _tail, int n) { struct dispatch_object_s *head = _head._do, *tail = _tail._do; if (unlikely(_dispatch_queue_push_update_tail_list(dq, head, tail))) { diff --git a/src/queue.c b/src/queue.c index 42b51f3eb..394ed7cd4 100644 --- a/src/queue.c +++ b/src/queue.c @@ -694,7 +694,7 @@ _dispatch_root_queue_init_pthread_pool(dispatch_root_queue_context_t qc, { dispatch_pthread_root_queue_context_t pqc = qc->dgq_ctxt; int32_t thread_pool_size = overcommit ? DISPATCH_WORKQ_MAX_PTHREAD_COUNT : - dispatch_hw_config(active_cpus); + (int32_t)dispatch_hw_config(active_cpus); if (slowpath(pool_size) && pool_size < thread_pool_size) { thread_pool_size = pool_size; } diff --git a/src/trace.h b/src/trace.h index 35722043b..872cd6ff5 100644 --- a/src/trace.h +++ b/src/trace.h @@ -132,7 +132,7 @@ _dispatch_trace_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t)) DISPATCH_ALWAYS_INLINE static inline void _dispatch_trace_root_queue_push_list(dispatch_queue_t dq, - dispatch_object_t _head, dispatch_object_t _tail, unsigned int n) + dispatch_object_t _head, dispatch_object_t _tail, int n) { if (slowpath(DISPATCH_QUEUE_PUSH_ENABLED())) { struct dispatch_object_s *dou = _head._do;