diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index a42b61e40..c1e5c9d4c 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -27,8 +27,12 @@ function(get_swift_host_arch result_var_name) set("${result_var_name}" "armv7" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") set("${result_var_name}" "armv7" PARENT_SCOPE) - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64") - set("${result_var_name}" "x86_64" PARENT_SCOPE) + elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "amd64|AMD64") + if(CMAKE_SYSTEM_NAME MATCHES "Windows") + set("${result_var_name}" "x86_64" PARENT_SCOPE) + else() + set("${result_var_name}" "amd64" PARENT_SCOPE) + endif() elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "IA64") set("${result_var_name}" "itanium" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86") diff --git a/private/private.h b/private/private.h index b87f5dc2b..b0ee07022 100644 --- a/private/private.h +++ b/private/private.h @@ -177,7 +177,7 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit); #if TARGET_OS_MAC #define DISPATCH_COCOA_COMPAT 1 -#elif defined(__linux__) || defined(__FreeBSD__) || defined(_WIN32) +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(_WIN32) #define DISPATCH_COCOA_COMPAT 1 #else #define DISPATCH_COCOA_COMPAT 0 @@ -191,6 +191,8 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit); typedef mach_port_t dispatch_runloop_handle_t; #elif defined(__linux__) || defined(__FreeBSD__) typedef int dispatch_runloop_handle_t; +#elif defined(__unix__) && !defined(__linux__) && !defined(__FreeBSD__) +typedef uint64_t dispatch_runloop_handle_t; #elif defined(_WIN32) typedef void *dispatch_runloop_handle_t; #else diff --git a/src/event/event.c b/src/event/event.c index 6ace80ecb..33df9f171 100644 --- a/src/event/event.c +++ b/src/event/event.c @@ -792,7 +792,7 @@ static void _dispatch_timer_unote_disarm(dispatch_timer_source_refs_t dt, dispatch_timer_heap_t dth) { - uint32_t tidx = dt->du_ident; + uint32_t tidx = (uint32_t)dt->du_ident; dispatch_assert(_dispatch_unote_armed(dt)); _dispatch_timer_heap_remove(&dth[tidx], dt); diff --git a/src/event/event_internal.h b/src/event/event_internal.h index 14c485ee3..5b2c7fc80 100644 --- a/src/event/event_internal.h +++ b/src/event/event_internal.h @@ -125,6 +125,8 @@ _dispatch_timer_flags_from_clock(dispatch_clock_t clock) #if defined(_WIN32) typedef uintptr_t dispatch_unote_ident_t; +#elif defined(__OpenBSD__) +typedef uintptr_t dispatch_unote_ident_t; #else typedef uint32_t dispatch_unote_ident_t; #endif diff --git a/src/event/event_kevent.c b/src/event/event_kevent.c index 16b69b37d..0d8db09f1 100644 --- a/src/event/event_kevent.c +++ b/src/event/event_kevent.c @@ -101,8 +101,12 @@ _evfiltstr(short filt) _evfilt2(EVFILT_MACHPORT); _evfilt2(DISPATCH_EVFILT_MACH_NOTIFICATION); #endif +#ifdef EVFILT_FS _evfilt2(EVFILT_FS); +#endif +#ifdef EVFILT_USER _evfilt2(EVFILT_USER); +#endif #ifdef EVFILT_SOCK _evfilt2(EVFILT_SOCK); #endif @@ -236,9 +240,9 @@ dispatch_kevent_debug(const char *verb, const dispatch_kevent_s *kev, #define _dispatch_du_debug(what, du) \ _dispatch_debug("kevent-source[%p]: %s kevent[%p] " \ - "{ filter = %s, ident = 0x%x }", \ + "{ filter = %s, ident = 0x%llx }", \ _dispatch_wref2ptr((du)->du_owner_wref), what, \ - (du), _evfiltstr((du)->du_filter), (du)->du_ident) + (du), _evfiltstr((du)->du_filter), (unsigned long long)(du)->du_ident) #if DISPATCH_MACHPORT_DEBUG #ifndef MACH_PORT_TYPE_SPREQUEST @@ -388,8 +392,10 @@ _dispatch_kevent_print_error(dispatch_kevent_t ke) switch (ke->data) { case 0: return; +#if DISPATCH_USE_KEVENT_QOS case ERANGE: /* A broken QoS was passed to kevent_id() */ DISPATCH_INTERNAL_CRASH(ke->qos, "Invalid kevent priority"); +#endif default: // log the unexpected error _dispatch_bug_kevent_client("kevent", _evfiltstr(ke->filter), @@ -397,7 +403,7 @@ _dispatch_kevent_print_error(dispatch_kevent_t ke) ke->flags & EV_DELETE ? "delete" : ke->flags & EV_ADD ? "add" : ke->flags & EV_ENABLE ? "enable" : "monitor", - (int)ke->data, ke->ident, ke->udata, du); + (int)ke->data, ke->ident, (uint64_t)ke->udata, du); } } @@ -528,11 +534,22 @@ _dispatch_kevent_merge_muxed(dispatch_kevent_t ke) } } +/* + * If the kevent implementation doesn't support EVFILT_USER for + * signaling, then we use EVFILT_TIMER with EV_ONESHOT with this ident + * to make do. + */ +#define DISPATCH_KEVENT_ERSATZ_EVFILT_USER_IDENT (~0ull << 9) + DISPATCH_NOINLINE static void _dispatch_kevent_drain(dispatch_kevent_t ke) { +#ifdef EVFILT_USER if (ke->filter == EVFILT_USER) { +#else + if (ke->filter == EVFILT_TIMER && ke->ident == DISPATCH_KEVENT_ERSATZ_EVFILT_USER_IDENT) { +#endif _dispatch_kevent_mgr_debug("received", ke); return; } @@ -579,10 +596,17 @@ static void _dispatch_kq_create(intptr_t *fd_ptr) { static const dispatch_kevent_s kev = { +#ifdef EVFILT_USER .ident = 1, .filter = EVFILT_USER, .flags = EV_ADD|EV_CLEAR, .udata = (dispatch_kevent_udata_t)DISPATCH_WLH_MANAGER, +#else + .ident = DISPATCH_KEVENT_ERSATZ_EVFILT_USER_IDENT, + .filter = EVFILT_TIMER, + .flags = EV_ADD|EV_DISABLE|EV_ONESHOT, + .data = 1, +#endif }; int kqfd; @@ -591,7 +615,6 @@ _dispatch_kq_create(intptr_t *fd_ptr) guardid_t guard = (uintptr_t)fd_ptr; kqfd = guarded_kqueue_np(&guard, GUARD_CLOSE | GUARD_DUP); #else - (void)guard_ptr; kqfd = kqueue(); #endif if (kqfd == -1) { @@ -743,7 +766,7 @@ _dispatch_kq_poll(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n, switch (err) { case ENOMEM: _dispatch_temporary_resource_shortage(); - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; case EINTR: goto retry; case EBADF: @@ -754,7 +777,7 @@ _dispatch_kq_poll(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n, (flags & KEVENT_FLAG_DYNAMIC_KQ_MUST_EXIST)) { return 0; } - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; #endif // DISPATCH_USE_KEVENT_WORKLOOP default: DISPATCH_CLIENT_CRASH(err, "Unexpected error from kevent"); @@ -786,9 +809,15 @@ _dispatch_kq_drain(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n, #if DISPATCH_DEBUG for (r = 0; r < n; r++) { +#ifdef EVFILT_USER if (ke[r].filter != EVFILT_USER || DISPATCH_MGR_QUEUE_DEBUG) { _dispatch_kevent_debug_n(NULL, ke + r, r, n); } +#else + if (DISPATCH_MGR_QUEUE_DEBUG) { + _dispatch_kevent_debug_n(NULL, ke + r, r, n); + } +#endif } #endif @@ -860,7 +889,6 @@ _dispatch_kq_unote_set_kevent(dispatch_unote_t _du, dispatch_kevent_t dk, du->du_priority), #endif }; - (void)pp; // if DISPATCH_USE_KEVENT_QOS == 0 } DISPATCH_ALWAYS_INLINE @@ -921,9 +949,13 @@ _dispatch_kq_deferred_update(dispatch_wlh_t wlh, dispatch_kevent_t ke) ke->udata); dispatch_kevent_t dk = _dispatch_kq_deferred_reuse_slot(wlh, ddi, slot); *dk = *ke; +#ifdef EVFILT_USER if (ke->filter != EVFILT_USER) { _dispatch_kevent_mgr_debug("deferred", ke); } +#else + _dispatch_kevent_mgr_debug("deferred", ke); +#endif } else { _dispatch_kq_update_one(wlh, ke); } @@ -985,6 +1017,7 @@ _dispatch_sync_ipc_handoff_end(dispatch_wlh_t wlh, mach_port_t port) } #endif +#if DISPATCH_HAVE_DIRECT_KNOTES DISPATCH_NOINLINE static bool _dispatch_kq_unote_update(dispatch_wlh_t wlh, dispatch_unote_t _du, @@ -1055,6 +1088,7 @@ _dispatch_kq_unote_update(dispatch_wlh_t wlh, dispatch_unote_t _du, dispatch_assume_zero(r); return true; } +#endif #pragma mark dispatch_muxnote_t @@ -1283,6 +1317,7 @@ _dispatch_unote_unregister_direct(dispatch_unote_t du, uint32_t flags) #pragma mark - #pragma mark dispatch_event_loop +#if DISPATCH_USE_KEVENT_WORKLOOP enum { DISPATCH_WORKLOOP_ASYNC, DISPATCH_WORKLOOP_ASYNC_FROM_SYNC, @@ -1316,6 +1351,7 @@ static char const * const _dispatch_workloop_actions[] = { [DISPATCH_WORKLOOP_SYNC_WAKE] = "sync-wake", [DISPATCH_WORKLOOP_SYNC_END] = "sync-end", }; +#endif void _dispatch_event_loop_atfork_child(void) @@ -1410,7 +1446,7 @@ _dispatch_kq_fill_workloop_event(dispatch_kevent_t ke, int which, switch (which) { case DISPATCH_WORKLOOP_ASYNC_FROM_SYNC: fflags |= NOTE_WL_END_OWNERSHIP; - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; case DISPATCH_WORKLOOP_ASYNC: case DISPATCH_WORKLOOP_ASYNC_DISCOVER_SYNC: case DISPATCH_WORKLOOP_ASYNC_QOS_UPDATE: @@ -1434,10 +1470,10 @@ _dispatch_kq_fill_workloop_event(dispatch_kevent_t ke, int which, case DISPATCH_WORKLOOP_ASYNC_LEAVE_FROM_SYNC: fflags |= NOTE_WL_END_OWNERSHIP; - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; case DISPATCH_WORKLOOP_ASYNC_LEAVE_FROM_TRANSFER: fflags |= NOTE_WL_IGNORE_ESTALE; - /* FALLTHROUGH */ + DISPATCH_FALLTHROUGH; case DISPATCH_WORKLOOP_ASYNC_LEAVE: dispatch_assert(!_dq_state_is_enqueued_on_target(dq_state)); action = EV_ADD | EV_DELETE | EV_ENABLE; @@ -1881,10 +1917,17 @@ _dispatch_event_loop_poke(dispatch_wlh_t wlh, uint64_t dq_state, uint32_t flags) { if (wlh == DISPATCH_WLH_MANAGER) { dispatch_kevent_s ke = (dispatch_kevent_s){ +#ifdef EVFILT_USER .ident = 1, .filter = EVFILT_USER, .fflags = NOTE_TRIGGER, .udata = (dispatch_kevent_udata_t)DISPATCH_WLH_MANAGER, +#else + .ident = DISPATCH_KEVENT_ERSATZ_EVFILT_USER_IDENT, + .filter = EVFILT_TIMER, + .flags = EV_ADD|EV_ENABLE|EV_ONESHOT, + .data = 1 +#endif }; return _dispatch_kq_deferred_update(DISPATCH_WLH_ANON, &ke); } else if (wlh && wlh != DISPATCH_WLH_ANON) { @@ -2357,6 +2400,12 @@ _dispatch_event_loop_timer_arm(dispatch_timer_heap_t dth, uint32_t tidx, target += range.leeway; range.leeway = 0; } +#if !NOTE_ABSOLUTE + target = range.delay; +#if defined(__OpenBSD__) + target /= 1000000; +#endif +#endif _dispatch_event_loop_timer_program(dth, tidx, target, range.leeway, EV_ADD | EV_ENABLE); @@ -2445,6 +2494,7 @@ const dispatch_source_type_s _dispatch_source_type_vnode = { .dst_merge_evt = _dispatch_source_merge_evt, }; +#ifdef EVFILT_FS const dispatch_source_type_s _dispatch_source_type_vfs = { .dst_kind = "vfs", .dst_filter = EVFILT_FS, @@ -2477,6 +2527,7 @@ const dispatch_source_type_s _dispatch_source_type_vfs = { .dst_create = _dispatch_unote_create_without_handle, .dst_merge_evt = _dispatch_source_merge_evt, }; +#endif #ifdef EVFILT_SOCK const dispatch_source_type_s _dispatch_source_type_sock = { diff --git a/src/event/workqueue.c b/src/event/workqueue.c index 749b0a452..6bc65c3b6 100644 --- a/src/event/workqueue.c +++ b/src/event/workqueue.c @@ -247,6 +247,52 @@ _dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) _dispatch_unfair_lock_unlock(&mon->registered_tid_lock); } +#elif defined(__OpenBSD__) +#include +#include +#include + +static void +_dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon) +{ + struct kinfo_proc kp[WORKQ_MAX_TRACKED_TIDS] = {0}; + size_t size, len; + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)getpid(), (int)sizeof(struct kinfo_proc), 0}; + if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) { + _dispatch_debug("workq: Failed to sysctl1"); + return; + } + + size = size > sizeof(kp)? sizeof(kp): size; + len = size / sizeof(struct kinfo_proc); + mib[5] = (int)len; + if (sysctl(mib, 6, kp, &size, NULL, 0) < 0) { + _dispatch_debug("workq: Failed to sysctl2"); + return; + } + + 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]; + for (size_t j = 0; j < len; j++) { + if ((dispatch_tid)kp[j].p_tid != tid) { + continue; + } + + if (kp[j].p_stat == SRUN || kp[j].p_stat == SIDL || kp[j].p_stat == SONPROC) { + running_count++; + break; + } + } + } + + mon->num_runnable = running_count; + + _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 62028077a..118d42db5 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) +#if defined(__linux__) || defined(_WIN32) || defined(__OpenBSD__) #define HAVE_DISPATCH_WORKQ_MONITORING 1 #else #define HAVE_DISPATCH_WORKQ_MONITORING 0 diff --git a/src/init.c b/src/init.c index d54da4121..1640cbab8 100644 --- a/src/init.c +++ b/src/init.c @@ -964,7 +964,6 @@ _dispatch_continuation_get_function_symbol(dispatch_continuation_t dc) return dc->dc_func; } -#if HAVE_MACH void _dispatch_bug_kevent_client(const char *msg, const char *filter, const char *operation, int err, uint64_t ident, uint64_t udata, @@ -1008,7 +1007,6 @@ _dispatch_bug_kevent_client(const char *msg, const char *filter, msg, strerror(err), err, udata, filter, ident, ident, func); } } -#endif // HAVE_MACH #if RDAR_49023449 @@ -1051,7 +1049,7 @@ _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 : "", - du._du->du_ident, du._du->du_ident, func); + (intptr_t)du._du->du_ident, (uintptr_t)du._du->du_ident, func); } #endif // RDAR_49023449 @@ -1157,7 +1155,7 @@ _dispatch_logv_init(void *context DISPATCH_UNUSED) #else dprintf(dispatch_logfile, "=== log file opened for %s[%u] at " "%ld.%06u ===\n", getprogname() ?: "", getpid(), - tv.tv_sec, (int)tv.tv_usec); + (long)tv.tv_sec, (int)tv.tv_usec); #endif } } diff --git a/src/internal.h b/src/internal.h index 4df1a2976..9f74f2c19 100644 --- a/src/internal.h +++ b/src/internal.h @@ -475,12 +475,10 @@ void _dispatch_bug_mach_client(const char *msg, mach_msg_return_t kr); struct dispatch_unote_class_s; -#if HAVE_MACH DISPATCH_NOINLINE DISPATCH_COLD void _dispatch_bug_kevent_client(const char *msg, const char *filter, const char *operation, int err, uint64_t ident, uint64_t udata, struct dispatch_unote_class_s *du); -#endif // HAVE_MACH DISPATCH_NOINLINE DISPATCH_COLD void _dispatch_bug_kevent_vanished(struct dispatch_unote_class_s *du); diff --git a/src/io.c b/src/io.c index e31e28c82..8f73916d1 100644 --- a/src/io.c +++ b/src/io.c @@ -2328,8 +2328,11 @@ _dispatch_operation_advise(dispatch_operation_t op, size_t chunk_size) case ESPIPE: break; // fd refers to a pipe or FIFO default: (void)dispatch_assume_zero(err); break; } +#elif defined(__OpenBSD__) + (void)err; #else #error "_dispatch_operation_advise not implemented on this platform" + (void)err; #endif // defined(F_RDADVISE) #endif // defined(_WIN32) } diff --git a/src/queue.c b/src/queue.c index 40f059c7a..356fef19b 100644 --- a/src/queue.c +++ b/src/queue.c @@ -6472,7 +6472,7 @@ _dispatch_runloop_handle_is_valid(dispatch_runloop_handle_t handle) { #if TARGET_OS_MAC return MACH_PORT_VALID(handle); -#elif defined(__linux__) +#elif defined(__linux__) || defined(__unix__) return handle >= 0; #elif defined(_WIN32) return handle != NULL; @@ -6490,6 +6490,8 @@ _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__) + return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt); #elif defined(_WIN32) return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt); #else @@ -6507,6 +6509,8 @@ _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__) + dq->do_ctxt = (void *)(uintptr_t)handle; #elif defined(_WIN32) dq->do_ctxt = (void *)(uintptr_t)handle; #else @@ -6514,6 +6518,12 @@ _dispatch_runloop_queue_set_handle(dispatch_lane_t dq, #endif } +#if defined(__unix__) +#define DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd) (((uint64_t)(rfd) << 32) | (wfd)) +#define DISPATCH_RUNLOOP_HANDLE_RFD(h) ((int)((h) >> 32)) +#define DISPATCH_RUNLOOP_HANDLE_WFD(h) ((int)((h) & 0xffffffff)) +#endif + static void _dispatch_runloop_queue_handle_init(void *ctxt) { @@ -6563,6 +6573,14 @@ _dispatch_runloop_queue_handle_init(void *ctxt) } } handle = fd; +#elif defined(__unix__) && !defined(__linux__) + int fds[2]; + int r = pipe2(fds, O_CLOEXEC | O_NONBLOCK); + if (r == -1) { + DISPATCH_CLIENT_CRASH(errno, "pipe2 failure"); + } + uint32_t rfd = (uint32_t)fds[0], wfd = (uint32_t)fds[1]; + handle = DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd); #elif defined(_WIN32) HANDLE hEvent; hEvent = CreateEventW(NULL, /*bManualReset=*/FALSE, @@ -6597,6 +6615,11 @@ _dispatch_runloop_queue_handle_dispose(dispatch_lane_t dq) #elif defined(__linux__) int rc = close(handle); (void)dispatch_assume_zero(rc); +#elif defined(__unix__) && !defined(__linux__) + int rc = close(DISPATCH_RUNLOOP_HANDLE_WFD(handle)); + (void)dispatch_assume_zero(rc); + rc = close(DISPATCH_RUNLOOP_HANDLE_RFD(handle)); + (void)dispatch_assume_zero(rc); #elif defined(_WIN32) BOOL bSuccess; bSuccess = CloseHandle(handle); @@ -6633,6 +6656,13 @@ _dispatch_runloop_queue_class_poke(dispatch_lane_t dq) result = eventfd_write(handle, 1); } while (result == -1 && errno == EINTR); (void)dispatch_assume_zero(result); +#elif defined(__unix__) && !defined(__linux__) + int wfd = DISPATCH_RUNLOOP_HANDLE_WFD(handle); + ssize_t result; + do { + result = write(wfd, "x", 1); + } while (result == -1 && errno == EINTR); + (void)dispatch_assume_zero(result - 1); #elif defined(_WIN32) BOOL bSuccess; bSuccess = SetEvent(handle); @@ -6920,7 +6950,7 @@ _dispatch_runloop_root_queue_wakeup_4CF(dispatch_queue_t dq) _dispatch_runloop_queue_wakeup(upcast(dq)._dl, 0, false); } -#if TARGET_OS_MAC || defined(_WIN32) +#if TARGET_OS_MAC || defined(_WIN32) || defined(__OpenBSD__) dispatch_runloop_handle_t _dispatch_runloop_root_queue_get_port_4CF(dispatch_queue_t dq) { @@ -7311,6 +7341,13 @@ _gettid(void) { return (pid_t)pthread_getthreadid_np(); } +#elif defined(__OpenBSD__) +DISPATCH_ALWAYS_INLINE +static inline pid_t +_gettid(void) +{ + return getthrid(); +} #elif defined(_WIN32) DISPATCH_ALWAYS_INLINE static inline DWORD diff --git a/src/shims/lock.c b/src/shims/lock.c index 88fb8f8b6..8102c877c 100644 --- a/src/shims/lock.c +++ b/src/shims/lock.c @@ -56,6 +56,20 @@ _dispatch_thread_switch(dispatch_lock value, dispatch_lock_options_t flags, #endif #endif +#if defined(__unix__) +#if !HAVE_UL_UNFAIR_LOCK && !HAVE_FUTEX_PI +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; +} +#endif +#endif + #pragma mark - semaphores #if USE_MACH_SEM @@ -395,8 +409,10 @@ _dispatch_unfair_lock_wake(uint32_t *uaddr, uint32_t flags) #include #ifdef __ANDROID__ #include -#else +#elif __linux__ #include +#else +#include #endif /* __ANDROID__ */ DISPATCH_ALWAYS_INLINE @@ -405,7 +421,12 @@ _dispatch_futex(uint32_t *uaddr, int op, uint32_t val, const struct timespec *timeout, uint32_t *uaddr2, uint32_t val3, int opflags) { +#if __linux__ return (int)syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3); +#else + (void)val3; + return futex(uaddr, op | opflags, (int)val, timeout, uaddr2); +#endif } // returns 0, ETIMEDOUT, EFAULT, EINTR, EWOULDBLOCK @@ -455,6 +476,7 @@ _dispatch_futex_wake(uint32_t *uaddr, int wake, int opflags) DISPATCH_INTERNAL_CRASH(errno, "_dlock_wake() failed"); } +#if HAVE_FUTEX_PI static void _dispatch_futex_lock_pi(uint32_t *uaddr, struct timespec *timeout, int detect, int opflags) @@ -472,6 +494,7 @@ _dispatch_futex_unlock_pi(uint32_t *uaddr, int opflags) if (rc == 0) return; DISPATCH_CLIENT_CRASH(errno, "futex_unlock_pi() failed"); } +#endif #endif #pragma mark - wait for address @@ -606,7 +629,7 @@ _dispatch_unfair_lock_lock_slow(dispatch_unfair_lock_t dul, } } } -#elif HAVE_FUTEX +#elif HAVE_FUTEX_PI void _dispatch_unfair_lock_lock_slow(dispatch_unfair_lock_t dul, dispatch_lock_options_t flags) @@ -643,7 +666,7 @@ _dispatch_unfair_lock_unlock_slow(dispatch_unfair_lock_t dul, dispatch_lock cur) if (_dispatch_lock_has_waiters(cur)) { _dispatch_unfair_lock_wake(&dul->dul_lock, 0); } -#elif HAVE_FUTEX +#elif HAVE_FUTEX_PI // futex_unlock_pi() handles both OWNER_DIED which we abuse & WAITERS _dispatch_futex_unlock_pi(&dul->dul_lock, FUTEX_PRIVATE_FLAG); #else diff --git a/src/shims/lock.h b/src/shims/lock.h index 6bf825aa7..0fcb65eb6 100644 --- a/src/shims/lock.h +++ b/src/shims/lock.h @@ -100,6 +100,25 @@ _dispatch_lock_owner(dispatch_lock lock_value) return lock_value & DLOCK_OWNER_MASK; } +#elif defined(__OpenBSD__) + +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)) + +DISPATCH_ALWAYS_INLINE +static inline dispatch_tid +_dispatch_lock_owner(dispatch_lock lock_value) +{ + return lock_value & DLOCK_OWNER_MASK; +} + #else # error define _dispatch_lock encoding scheme for your platform here #endif @@ -167,10 +186,15 @@ _dispatch_lock_has_failed_trylock(dispatch_lock lock_value) #endif #ifndef HAVE_FUTEX -#ifdef __linux__ +#if defined(__linux__) +#define HAVE_FUTEX 1 +#define HAVE_FUTEX_PI 1 +#elif defined(__OpenBSD__) #define HAVE_FUTEX 1 +#define HAVE_FUTEX_PI 0 #else #define HAVE_FUTEX 0 +#define HAVE_FUTEX_PI 0 #endif #endif // HAVE_FUTEX diff --git a/src/source.c b/src/source.c index d1581351d..69b731d92 100644 --- a/src/source.c +++ b/src/source.c @@ -1401,8 +1401,8 @@ _dispatch_source_debug_attr(dispatch_source_t ds, char* buf, size_t bufsiz) return dsnprintf(buf, bufsiz, "target = %s[%p], ident = 0x%llx, " "mask = 0x%x, pending_data = 0x%llx, registered = %d, " "armed = %d, %s%s%s", - target && target->dq_label ? target->dq_label : "", target, - (unsigned long long)dr->du_ident, dr->du_fflags, + target && target->dq_label ? target->dq_label : "", + target, (unsigned long long)dr->du_ident, dr->du_fflags, (unsigned long long)dr->ds_pending_data, _du_state_registered(du_state), _du_state_armed(du_state), (dqf & DSF_CANCELED) ? "cancelled, " : "", diff --git a/src/swift/Source.swift b/src/swift/Source.swift index 57677c2c2..f9c24280d 100644 --- a/src/swift/Source.swift +++ b/src/swift/Source.swift @@ -116,7 +116,7 @@ extension DispatchSource { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) public struct ProcessEvent : OptionSet, RawRepresentable { public let rawValue: UInt public init(rawValue: UInt) { self.rawValue = rawValue } @@ -174,7 +174,7 @@ extension DispatchSource { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) public class func makeProcessSource(identifier: pid_t, eventMask: ProcessEvent, queue: DispatchQueue? = nil) -> DispatchSourceProcess { let source = dispatch_source_create(_swift_dispatch_source_type_PROC(), UInt(identifier), eventMask.rawValue, queue?.__wrapped) return DispatchSource(source: source) as DispatchSourceProcess @@ -224,7 +224,7 @@ extension DispatchSource { return DispatchSource(source: source) as DispatchSourceUserDataReplace } -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) 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 @@ -290,7 +290,7 @@ extension DispatchSourceMemoryPressure { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) +#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)) @@ -646,7 +646,7 @@ extension DispatchSourceTimer { } } -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) extension DispatchSourceFileSystemObject { public var handle: Int32 { return Int32(dispatch_source_get_handle((self as! DispatchSource).__wrapped)) diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index 999c22d6c..63f76bcd9 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -182,7 +182,7 @@ extension DispatchSource : DispatchSourceMachSend, } #endif -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) extension DispatchSource : DispatchSourceProcess, DispatchSourceFileSystemObject { } @@ -273,7 +273,7 @@ public protocol DispatchSourceMemoryPressure : DispatchSourceProtocol { } #endif -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) public protocol DispatchSourceProcess : DispatchSourceProtocol { var handle: pid_t { get } @@ -303,7 +303,7 @@ public protocol DispatchSourceTimer : DispatchSourceProtocol { func scheduleRepeating(wallDeadline: DispatchWallTime, interval: Double, leeway: DispatchTimeInterval) } -#if !os(Linux) && !os(Android) && !os(Windows) +#if !os(Linux) && !os(Android) && !os(Windows) && !os(OpenBSD) public protocol DispatchSourceFileSystemObject : DispatchSourceProtocol { var handle: Int32 { get } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0176a062b..9430c7c92 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -183,6 +183,12 @@ set_tests_properties(dispatch_io_pipe_close PROPERTIES TIMEOUT 5) add_unit_test(dispatch_c99 SOURCES dispatch_c99.c) add_unit_test(dispatch_plusplus SOURCES dispatch_plusplus.cpp) +if (DISPATCH_USE_INTERNAL_WORKQUEUE) + add_unit_test(dispatch_workqueue + SOURCES + dispatch_workqueue.c) +endif() + # test-specific link options if(WIN32) target_link_libraries(dispatch_io_muxed PRIVATE WS2_32) diff --git a/tests/bsdtestharness.c b/tests/bsdtestharness.c index 93ed8324b..4b66c8956 100644 --- a/tests/bsdtestharness.c +++ b/tests/bsdtestharness.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) @@ -144,7 +145,7 @@ main(int argc, char *argv[]) //fprintf(stderr, "pid = %d\n", pid); assert(pid > 0); -#if defined(__linux__) +#if defined(__unix__) int status; struct rusage usage; struct timeval tv_stop, tv_wall; @@ -159,9 +160,9 @@ main(int argc, char *argv[]) assert(res2 != -1); test_long("Process exited", (WIFEXITED(status) && WEXITSTATUS(status) && WEXITSTATUS(status) != 0xff) || WIFSIGNALED(status), 0); - printf("[PERF]\twall time: %ld.%06ld\n", tv_wall.tv_sec, tv_wall.tv_usec); - printf("[PERF]\tuser time: %ld.%06ld\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec); - printf("[PERF]\tsystem time: %ld.%06ld\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec); + printf("[PERF]\twall time: %" PRIdMAX ".%06" PRIdMAX "\n", (intmax_t)tv_wall.tv_sec, (intmax_t)tv_wall.tv_usec); + printf("[PERF]\tuser time: %" PRIdMAX ".%06" PRIdMAX"\n", (intmax_t)usage.ru_utime.tv_sec, (intmax_t)usage.ru_utime.tv_usec); + printf("[PERF]\tsystem time: %" PRIdMAX ".%06" PRIdMAX "\n", (intmax_t)usage.ru_stime.tv_sec, (intmax_t)usage.ru_stime.tv_usec); printf("[PERF]\tmax resident set size: %ld\n", usage.ru_maxrss); printf("[PERF]\tpage faults: %ld\n", usage.ru_majflt); printf("[PERF]\tswaps: %ld\n", usage.ru_nswap); diff --git a/tests/dispatch_select.c b/tests/dispatch_select.c index 6202711cb..352157a6e 100644 --- a/tests/dispatch_select.c +++ b/tests/dispatch_select.c @@ -67,8 +67,9 @@ stage1(int stage) dispatch_source_set_event_handler(source, ^{ size_t buffer_size = 500*1024; - char buffer[500*1024]; + char *buffer = malloc(buffer_size*sizeof(char)); ssize_t sz = dispatch_test_fd_read(fd, buffer, buffer_size); + free(buffer); test_sizet_less_than_or_equal("kevent read 1", sz, buffer_size+1); dispatch_source_cancel(source); }); @@ -129,12 +130,14 @@ stage2(void) dispatch_source_set_event_handler(source, ^{ size_t est = dispatch_source_get_data(source); test_sizet_less_than_or_equal("estimated", est, expected - actual); - char buffer[500*1024]; - ssize_t sz = dispatch_test_fd_read(fd, buffer, sizeof(buffer)); + size_t buffer_size = 500*1024*sizeof(char); + char *buffer = malloc(buffer_size); + ssize_t sz = dispatch_test_fd_read(fd, buffer, buffer_size); + free(buffer); actual += sz; - if (sz < (ssize_t)sizeof(buffer)) + if (sz < (ssize_t)(buffer_size)) { - sz = dispatch_test_fd_read(fd, buffer, sizeof(buffer)); + sz = dispatch_test_fd_read(fd, buffer, buffer_size); actual += sz; test_long("EOF", sz, 0); dispatch_source_cancel(source); diff --git a/tests/dispatch_workqueue.c b/tests/dispatch_workqueue.c new file mode 100644 index 000000000..21e96e043 --- /dev/null +++ b/tests/dispatch_workqueue.c @@ -0,0 +1,74 @@ +#include +#include "dispatch_test.h" + +struct test_context { + uint32_t ncpu; + int flag; +}; + +static void +timeout(void *context) +{ + struct test_context *ctx = (struct test_context *)context; + sleep(2); // Give the monitor the best chance of firing. + test_int32_format(ctx->flag, 1, "flag"); + test_stop(); +} + +static void +raise_flag(void *context) +{ + struct test_context *ctx = (struct test_context *)context; + ctx->flag++; +} + +static void +spin(void *context) +{ + struct test_context *ctx = (struct test_context *)context; + sleep(ctx->ncpu * 2); +} + +static uint32_t +activecpu(void) +{ + uint32_t activecpu; +#if defined(__linux__) || defined(__OpenBSD__) + activecpu = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(_WIN32) + SYSTEM_INFO si; + GetSystemInfo(&si); + activecpu = si.dwNumberOfProcessors; +#else + size_t s = sizeof(activecpu); + sysctlbyname("hw.activecpu", &activecpu, &s, NULL, 0); +#endif + return activecpu; +} + +struct test_context ctx; + +int +main(void) +{ + uint32_t ncpu = activecpu(); + + dispatch_test_start("Dispatch workqueue"); + + dispatch_queue_t global = dispatch_get_global_queue(0, 0); + test_ptr_notnull("dispatch_get_global_queue", global); + + ctx.ncpu = ncpu; + dispatch_async_f(global, &ctx, timeout); + + for(int i = 0; i < (int)ncpu - 1; i++) { + dispatch_async_f(global, &ctx, spin); + } + + // All cpus are tied up at this point. Workqueue + // should execute this function by overcommit. + dispatch_async_f(global, &ctx, raise_flag); + + dispatch_main(); + return 0; +}