Skip to content

[FreeBSD] support FreeBSD #861

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions private/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
46 changes: 46 additions & 0 deletions src/event/workqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <sys/sysctl.h>
#include <sys/proc.h>
#include <sys/user.h>

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) {
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we should use ARRAY_SIZEOF for the second parameter.

#define ARRAY_SIZEOF(array) (sizeof((array))/sizeof(*(array)))

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't really think it's a good idea to introduce a macro, especially just for one place.

Although it makes it more readable, but I think it is reasonable to expect the next person who need to change this line are already familiar with the correct usage of sysctl

_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
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) || defined(__OpenBSD__)
#if defined(__linux__) || defined(_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__)
#define HAVE_DISPATCH_WORKQ_MONITORING 1
#else
#define HAVE_DISPATCH_WORKQ_MONITORING 0
Expand Down
4 changes: 4 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 : "<unknown>",
#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
Expand Down
3 changes: 3 additions & 0 deletions src/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ upcast(dispatch_object_t dou)
#include <sys/sysctl.h>
#include <sys/queue.h>
#endif
#if defined(__FreeBSD__)
#include <sys/eventfd.h>
#endif // __FreeBSD__
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/mman.h>
Expand Down
1 change: 0 additions & 1 deletion src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

#if defined(__FreeBSD__)
#include <fcntl.h>
#define F_RDADVISE F_RDAHEAD
#endif

#ifndef DISPATCH_IO_DEBUG
Expand Down
5 changes: 3 additions & 2 deletions src/queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
31 changes: 27 additions & 4 deletions src/shims/lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down
22 changes: 22 additions & 0 deletions src/shims/lock.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,28 @@ _dispatch_lock_owner(dispatch_lock lock_value)
return lock_value & DLOCK_OWNER_MASK;
}

#elif defined(__FreeBSD__)

#include <sys/types.h>
#include <sys/umtx.h>
#include <sched.h>

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 <Windows.h>
Expand Down
13 changes: 11 additions & 2 deletions src/swift/Source.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

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

Why the different name? Should we not be using the name names to maintain source consistency?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is because NOTE_TRACK is only available on FreeBSD but not Darwin

Copy link
Member

Choose a reason for hiding this comment

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

Sure, having an extended FreeBSD only option is fine, but this does remove the signal note doesn't it? I take it that NOTE_TRACK is meant to replace that? If so, why not keep the name incongruous with the underlying note to allow easier porting?

Copy link
Member Author

@michael-yuji michael-yuji May 23, 2025

Choose a reason for hiding this comment

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

Sorry, I should've add more context in my previous reply. NOTE_SIGNAL on Darwin and NOTE_TRACK on FreeBSD are not interchangeable and each are platform specific.

NOTE_SIGNAL on Darwin allow users to monitor if the process was sent a signal,

on the other hand, NOTE_TRACK on FreeBSD cause kqueue to follow the target process across fork and automatically register events with same monitor. For example, NOTE_TRACK | NOTE_EXIT on a pid cause exit event of the tracing process, and all its decedents to be reported.

#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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
8 changes: 6 additions & 2 deletions src/swift/Wrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions src/swift/shims/DispatchOverlayShims.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion tests/bsdtestharness.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion tests/dispatch_apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions tests/dispatch_io_pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion tests/dispatch_select.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down