diff --git a/private/private.h b/private/private.h index b0ee07022..8b1e19670 100644 --- a/private/private.h +++ b/private/private.h @@ -189,9 +189,9 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit); #if TARGET_OS_MAC typedef mach_port_t dispatch_runloop_handle_t; -#elif defined(__linux__) || defined(__FreeBSD__) +#elif defined(__linux__) typedef int dispatch_runloop_handle_t; -#elif defined(__unix__) && !defined(__linux__) && !defined(__FreeBSD__) +#elif defined(__unix__) typedef uint64_t dispatch_runloop_handle_t; #elif defined(_WIN32) typedef void *dispatch_runloop_handle_t; diff --git a/src/event/workqueue.c b/src/event/workqueue.c index 6bc65c3b6..07cc17bc5 100644 --- a/src/event/workqueue.c +++ b/src/event/workqueue.c @@ -293,6 +293,52 @@ _dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) _dispatch_unfair_lock_unlock(&mon->registered_tid_lock); } +#elif defined(__FreeBSD__) +#include +#include +#include + +static void +_dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) +{ + struct kinfo_proc kp[WORKQ_MAX_TRACKED_TIDS]; + size_t size; + int count, runners = 0; + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, (int)getpid()}; + + // get size we need + if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0) { + _dispatch_debug("workq: failed to get size for kinfo_proc[] from sysctll"); + return; + } + + // only care about up to WORKQ_MAX_TRACKED_TIDS threads + size = MIN(sizeof(kp), size); + + if (sysctl(mib, 4, kp, &size, NULL, 0) < 0) { + _dispatch_debug("workq: failed to get kinfo_proc[] from sysctl"); + return; + } + + count = (int)(size / sizeof(struct kinfo_proc)); + + _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]; + for (int j = 0; i < count; ++i) { + if ((dispatch_tid)kp[j].ki_tid != tid) { continue; } + if (kp[j].ki_stat == SRUN || kp[j].ki_stat == SIDL) { + ++runners; + break; + } + } + } + + mon->num_runnable = runners; + + _dispatch_unfair_lock_unlock(&mon->registered_tid_lock); +} #else #error must define _dispatch_workq_count_runnable_workers #endif diff --git a/src/event/workqueue_internal.h b/src/event/workqueue_internal.h index 118d42db5..cc9474e80 100644 --- a/src/event/workqueue_internal.h +++ b/src/event/workqueue_internal.h @@ -30,7 +30,7 @@ void _dispatch_workq_worker_register(dispatch_queue_global_t root_q); void _dispatch_workq_worker_unregister(dispatch_queue_global_t root_q); -#if defined(__linux__) || defined(_WIN32) || defined(__OpenBSD__) +#if defined(__linux__) || defined(_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__) #define HAVE_DISPATCH_WORKQ_MONITORING 1 #else #define HAVE_DISPATCH_WORKQ_MONITORING 0 diff --git a/src/init.c b/src/init.c index 1640cbab8..2f2efb0ae 100644 --- a/src/init.c +++ b/src/init.c @@ -1049,7 +1049,11 @@ _dispatch_bug_kevent_vanished(dispatch_unote_t du) "{ %p[%s], ident: %" PRIdPTR " / 0x%" PRIxPTR ", handler: %p }", dux_type(du._du)->dst_kind, dou._dq, dou._dq->dq_label ? dou._dq->dq_label : "", +#if defined(__FreeBSD__) + (intptr_t)du._du->du_ident, (intptr_t)du._du->du_ident, func); +#else (intptr_t)du._du->du_ident, (uintptr_t)du._du->du_ident, func); +#endif } #endif // RDAR_49023449 diff --git a/src/internal.h b/src/internal.h index 9f74f2c19..a67a771dc 100644 --- a/src/internal.h +++ b/src/internal.h @@ -277,6 +277,9 @@ upcast(dispatch_object_t dou) #include #include #endif +#if defined(__FreeBSD__) +#include +#endif // __FreeBSD__ #include #include #include diff --git a/src/io.c b/src/io.c index 8b03e2934..95c9d2d60 100644 --- a/src/io.c +++ b/src/io.c @@ -22,7 +22,6 @@ #if defined(__FreeBSD__) #include -#define F_RDADVISE F_RDAHEAD #endif #ifndef DISPATCH_IO_DEBUG diff --git a/src/queue.c b/src/queue.c index 356fef19b..1d948e947 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6490,7 +6490,7 @@ _dispatch_runloop_queue_get_handle(dispatch_lane_t dq) #elif defined(__linux__) // decode: 0 is a valid fd, so offset by 1 to distinguish from NULL return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1; -#elif defined(__unix__) && !defined(__linux__) +#elif defined(__unix__) return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt); #elif defined(_WIN32) return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt); @@ -6509,7 +6509,7 @@ _dispatch_runloop_queue_set_handle(dispatch_lane_t dq, #elif defined(__linux__) // encode: 0 is a valid fd, so offset by 1 to distinguish from NULL dq->do_ctxt = (void *)(uintptr_t)(handle + 1); -#elif defined(__unix__) && !defined(__linux__) +#elif defined(__unix__) dq->do_ctxt = (void *)(uintptr_t)handle; #elif defined(_WIN32) dq->do_ctxt = (void *)(uintptr_t)handle; @@ -6574,6 +6574,7 @@ _dispatch_runloop_queue_handle_init(void *ctxt) } handle = fd; #elif defined(__unix__) && !defined(__linux__) + // swift-corelib-foundation PR #3004 implemented a pipe based queue handle int fds[2]; int r = pipe2(fds, O_CLOEXEC | O_NONBLOCK); if (r == -1) { diff --git a/src/shims/lock.c b/src/shims/lock.c index 8102c877c..6d0ab8764 100644 --- a/src/shims/lock.c +++ b/src/shims/lock.c @@ -54,9 +54,20 @@ _dispatch_thread_switch(dispatch_lock value, dispatch_lock_options_t flags, SwitchToThread(); } #endif -#endif - -#if defined(__unix__) +#elif defined(__FreeBSD__) +#if !HAVE_UL_UNFAIR_LOCK +DISPATCH_ALWAYS_INLINE +static inline void +_dispatch_thread_switch(dispatch_lock value, dispatch_lock_options_t flags, + uint32_t timeout) +{ + (void)value; + (void)flags; + (void)timeout; + sched_yield(); +} +#endif // HAVE_UL_UNFAIR_LOCK +#elif defined(__unix__) #if !HAVE_UL_UNFAIR_LOCK && !HAVE_FUTEX_PI DISPATCH_ALWAYS_INLINE static inline void @@ -539,6 +550,16 @@ _dispatch_wait_on_address(uint32_t volatile *_address, uint32_t value, ? INFINITE : ((nsecs + 1000000) / 1000000); if (dwMilliseconds == 0) return ETIMEDOUT; return WaitOnAddress(address, &value, sizeof(value), dwMilliseconds) == TRUE; +#elif defined(__FreeBSD__) + (void)flags; + if (nsecs != DISPATCH_TIME_FOREVER) { + struct timespec ts = { + .tv_sec = (__typeof__(ts.tv_sec))(nsecs / NSEC_PER_SEC), + .tv_nsec = (__typeof__(ts.tv_nsec))(nsecs % NSEC_PER_SEC), + }; + return _umtx_op((void*)address, UMTX_OP_WAIT_UINT, value, (void*)(uintptr_t)sizeof(struct timespec), (void*)&ts); + } + return _umtx_op((void*)address, UMTX_OP_WAIT_UINT, value, 0, 0); #else #error _dispatch_wait_on_address unimplemented for this platform #endif @@ -553,6 +574,8 @@ _dispatch_wake_by_address(uint32_t volatile *address) _dispatch_futex_wake((uint32_t *)address, INT_MAX, FUTEX_PRIVATE_FLAG); #elif defined(_WIN32) WakeByAddressAll((uint32_t *)address); +#elif defined(__FreeBSD__) + _umtx_op((void*)address, UMTX_OP_WAKE, INT_MAX, 0, 0); #else (void)address; #endif @@ -712,7 +735,7 @@ _dispatch_once_wait(dispatch_once_gate_t dgo) _dispatch_futex_wait(lock, (dispatch_lock)new_v, NULL, FUTEX_PRIVATE_FLAG); #else - _dispatch_thread_switch(new_v, 0, timeout++); + _dispatch_thread_switch((dispatch_lock)new_v, 0, timeout++); #endif (void)timeout; } diff --git a/src/shims/lock.h b/src/shims/lock.h index 0fcb65eb6..36ccc9920 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -79,6 +79,28 @@ _dispatch_lock_owner(dispatch_lock lock_value) return lock_value & DLOCK_OWNER_MASK; } +#elif defined(__FreeBSD__) + +#include +#include +#include + +typedef uint32_t dispatch_tid; +typedef uint32_t dispatch_lock; + +#define DLOCK_OWNER_NULL ((dispatch_tid)0) +#define DLOCK_OWNER_MASK ((dispatch_lock)0xfffffffc) +#define DLOCK_WAITERS_BIT ((dispatch_lock)0x00000001) +#define DLOCK_FAILED_TRYLOCK_BIT ((dispatch_lock)0x00000002) +#define _dispatch_tid_self() ((dispatch_tid)(_dispatch_get_tsd_base()->tid << 2)) + +DISPATCH_ALWAYS_INLINE +static inline dispatch_tid +_dispatch_lock_owner(dispatch_lock lock_value) +{ + return lock_value & DLOCK_OWNER_MASK; +} + #elif defined(_WIN32) #include diff --git a/src/swift/Source.swift b/src/swift/Source.swift index f9c24280d..92201f8e0 100644 --- a/src/swift/Source.swift +++ b/src/swift/Source.swift @@ -124,8 +124,17 @@ extension DispatchSource { public static let exit = ProcessEvent(rawValue: 0x80000000) public static let fork = ProcessEvent(rawValue: 0x40000000) public static let exec = ProcessEvent(rawValue: 0x20000000) +#if os(FreeBSD) + public static let track = ProcessEvent(rawValue: 0x00000001) +#else public static let signal = ProcessEvent(rawValue: 0x08000000) +#endif + +#if os(FreeBSD) + public static let all: ProcessEvent = [.exit, .fork, .exec, .track] +#else public static let all: ProcessEvent = [.exit, .fork, .exec, .signal] +#endif } #endif @@ -224,7 +233,7 @@ extension DispatchSource { return DispatchSource(source: source) as DispatchSourceUserDataReplace } -#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) && !os(FreeBSD) public class func makeFileSystemObjectSource(fileDescriptor: Int32, eventMask: FileSystemEvent, queue: DispatchQueue? = nil) -> DispatchSourceFileSystemObject { let source = dispatch_source_create(_swift_dispatch_source_type_VNODE(), UInt(fileDescriptor), eventMask.rawValue, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceFileSystemObject @@ -293,7 +302,7 @@ extension DispatchSourceMemoryPressure { #if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) extension DispatchSourceProcess { public var handle: pid_t { - return pid_t(dispatch_source_get_handle(self as! DispatchSource)) + return pid_t(CDispatch.dispatch_source_get_handle((self as! DispatchSource).__wrapped)) } public var data: DispatchSource.ProcessEvent { diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index 63f76bcd9..1118bb6e4 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -183,8 +183,12 @@ extension DispatchSource : DispatchSourceMachSend, #endif #if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) -extension DispatchSource : DispatchSourceProcess, - DispatchSourceFileSystemObject { +extension DispatchSource : DispatchSourceProcess { +} +#endif + +#if !os(Linux) && !os(Android) && !os(Windows) && !os(FreeBSD) && !os(OpenBSD) +extension DispatchSource : DispatchSourceFileSystemObject { } #endif diff --git a/src/swift/shims/DispatchOverlayShims.h b/src/swift/shims/DispatchOverlayShims.h index 80e87a8db..5ed8dd228 100644 --- a/src/swift/shims/DispatchOverlayShims.h +++ b/src/swift/shims/DispatchOverlayShims.h @@ -88,6 +88,11 @@ SWIFT_DISPATCH_SOURCE_TYPE(PROC) SWIFT_DISPATCH_SOURCE_TYPE(VNODE) #endif +#if defined(__FreeBSD__) +SWIFT_DISPATCH_SOURCE_TYPE(PROC) +SWIFT_DISPATCH_SOURCE_TYPE(VNODE) +#endif + extern void _swift_dispatch_source_create_abort(void); diff --git a/tests/bsdtestharness.c b/tests/bsdtestharness.c index 4b66c8956..5014cba37 100644 --- a/tests/bsdtestharness.c +++ b/tests/bsdtestharness.c @@ -212,7 +212,7 @@ main(int argc, char *argv[]) #else dispatch_queue_t main_q = dispatch_get_main_queue(); - dispatch_source_t tmp_ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, main_q); + dispatch_source_t tmp_ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, (uintptr_t)pid, DISPATCH_PROC_EXIT, main_q); assert(tmp_ds); dispatch_source_set_event_handler(tmp_ds, ^{ int status; diff --git a/tests/dispatch_apply.c b/tests/dispatch_apply.c index 1f2dfb470..01b3dfb65 100644 --- a/tests/dispatch_apply.c +++ b/tests/dispatch_apply.c @@ -81,7 +81,7 @@ static void busythread(void *ignored) static void test_apply_contended(dispatch_queue_t dq) { uint32_t activecpu; -#if defined(__linux__) || defined(__OpenBSD__) +#if defined(__linux__) || defined(__OpenBSD__) || defined(__FreeBSD__) activecpu = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN); #elif defined(_WIN32) SYSTEM_INFO si; diff --git a/tests/dispatch_io_pipe.c b/tests/dispatch_io_pipe.c index 50ddc8a87..eb32b6b87 100644 --- a/tests/dispatch_io_pipe.c +++ b/tests/dispatch_io_pipe.c @@ -90,6 +90,10 @@ test_get_pipe_buffer_size(int kind) CloseHandle(write_handle); }); return size; +#elif defined(__FreeBSD__) + // buffer size of blocking and non-blocking pipes is different on FreeBSD + (void)kind; + return PIPE_BUF; #else (void)kind; static dispatch_once_t once; diff --git a/tests/dispatch_select.c b/tests/dispatch_select.c index 352157a6e..8a1147a5b 100644 --- a/tests/dispatch_select.c +++ b/tests/dispatch_select.c @@ -39,7 +39,7 @@ void finish(void* cxt); void stage1(int stage) { -#if defined(_WIN32) +#if defined(_WIN32) || defined(__FreeBSD__) char *path = dispatch_test_get_large_file(); dispatch_fd_t fd = dispatch_test_fd_open(path, O_RDONLY); if (fd == -1)