Skip to content

Support OpenBSD. #559

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Apr 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions cmake/modules/SwiftSupport.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
4 changes: 3 additions & 1 deletion private/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels a bit ... worrisome to me. If this ever gets re-ordered, we will have a subtle way to change the semantics. Currently __linux__ will define dispatch_runloop_handle_t to int rather than uint64_t. Is there a reason to prefer the __unix__ spelling here over __OpenBSD__?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The runloop implementation is POSIX-portable, it just uses pipe2; it is not OpenBSD-specific, hence the __unix__ spelling.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the conditional twice here is a little kludgy but I don't know if we want to refactor that further right now.

#elif defined(_WIN32)
typedef void *dispatch_runloop_handle_t;
#else
Expand Down
2 changes: 1 addition & 1 deletion src/event/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to worry about truncation? IIRC, a timer on Windows would be a HANDLE which would be truncated by uint32_t as it should be uintptr_t.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

du_ident on Windows is indeed a uintptr_t, as it is on OpenBSD. The timer index here is a uint32_t, so as written there is already a truncation occurring. du_ident is already initialized in various places from _dispatch_timer_unote_idx which returns an unsigned int, but here we access du_ident directly, which is not guaranteed to be 32-bit wide.

Casting here just suppresses the error. I don't think there is actually a problem here on looking how du_ident is used in this module; the 32-bit assumption is baked a little hard in the timer code and disentangling that should be handled separately.


dispatch_assert(_dispatch_unote_armed(dt));
_dispatch_timer_heap_remove(&dth[tidx], dt);
Expand Down
2 changes: 2 additions & 0 deletions src/event/event_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
71 changes: 61 additions & 10 deletions src/event/event_kevent.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -388,16 +392,18 @@ _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),
!ke->udata ? NULL :
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);
}
}

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

Expand All @@ -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) {
Expand Down Expand Up @@ -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:
Expand All @@ -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");
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't be defined on all platforms (e.g. Windows).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but Windows is using src/event/event_windows.c. This entire file gets #ifdef'd out on Windows.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But, you can use the kevent backend on Windows with libkqueue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I've just changed this to !defined instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually -- that is wrong. NOTE_ABSOLUTE is defined in event_kevent.h, and is set to 0 if it is undefined. I'm going to go back to !NOTE_ABSOLUTE, since the change caused problems.

target = range.delay;
#if defined(__OpenBSD__)
target /= 1000000;
#endif
#endif

_dispatch_event_loop_timer_program(dth, tidx, target, range.leeway,
EV_ADD | EV_ENABLE);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 = {
Expand Down
46 changes: 46 additions & 0 deletions src/event/workqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <sys/param.h>
#include <sys/sysctl.h>
#include <sys/proc.h>

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
Expand Down
2 changes: 1 addition & 1 deletion src/event/workqueue_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 2 additions & 4 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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 : "<unknown>",
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
Expand Down Expand Up @@ -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
}
}
Expand Down
Loading