From 6753c35d24c38e0395a4aa15c0fcbb14964cf058 Mon Sep 17 00:00:00 2001 From: Michael Chiu Date: Wed, 18 Dec 2024 13:14:29 -0800 Subject: [PATCH 1/3] add FreeBSD support --- Sources/Testing/ExitTests/ExitTest.swift | 2 +- Sources/Testing/ExitTests/SpawnProcess.swift | 9 +++++- Sources/Testing/ExitTests/WaitFor.swift | 6 +++- Sources/Testing/Support/Locked.swift | 34 ++++++++++++++++++-- Sources/_TestingInternals/include/Includes.h | 4 +++ 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/Sources/Testing/ExitTests/ExitTest.swift b/Sources/Testing/ExitTests/ExitTest.swift index f21104f31..73d78d9b2 100644 --- a/Sources/Testing/ExitTests/ExitTest.swift +++ b/Sources/Testing/ExitTests/ExitTest.swift @@ -114,7 +114,7 @@ extension ExitTest { // As with Linux, disable the generation core files. FreeBSD does not, as // far as I can tell, special-case RLIMIT_CORE=1. var rl = rlimit(rlim_cur: 0, rlim_max: 0) - _ = setrlimit(CInt(RLIMIT_CORE.rawValue), &rl) + _ = setrlimit(RLIMIT_CORE, &rl) #elseif os(Windows) // On Windows, similarly disable Windows Error Reporting and the Windows // Error Reporting UI. Note we expect to be the first component to call diff --git a/Sources/Testing/ExitTests/SpawnProcess.swift b/Sources/Testing/ExitTests/SpawnProcess.swift index 7dd845c67..e58584be4 100644 --- a/Sources/Testing/ExitTests/SpawnProcess.swift +++ b/Sources/Testing/ExitTests/SpawnProcess.swift @@ -143,12 +143,19 @@ func spawnExecutable( #if SWT_TARGET_OS_APPLE // Close all other file descriptors open in the parent. flags |= CShort(POSIX_SPAWN_CLOEXEC_DEFAULT) -#elseif os(Linux) || os(FreeBSD) +#elseif os(Linux) // This platform doesn't have POSIX_SPAWN_CLOEXEC_DEFAULT, but we can at // least close all file descriptors higher than the highest inherited one. // We are assuming here that the caller didn't set FD_CLOEXEC on any of // these file descriptors. _ = swt_posix_spawn_file_actions_addclosefrom_np(fileActions, highestFD + 1) +#elseif os(FreeBSD) + // Like Linux, this platfrom doesn't have POSIX_SPAWN_CLOEXEC_DEFAULT; + // However; unlike Linux, all non-EOL FreeBSD (>= 13.1) supports + // `posix_spawn_file_actions_addclosefrom_np` and therefore we don't need + // need `swt_posix_spawn_file_actions_addclosefrom_np` to guard the availability + // of this api. + _ = posix_spawn_file_actions_addclosefrom_np(fileActions, highestFD + 1) #else #warning("Platform-specific implementation missing: cannot close unused file descriptors") #endif diff --git a/Sources/Testing/ExitTests/WaitFor.swift b/Sources/Testing/ExitTests/WaitFor.swift index 521a092d3..287e26e4d 100644 --- a/Sources/Testing/ExitTests/WaitFor.swift +++ b/Sources/Testing/ExitTests/WaitFor.swift @@ -85,7 +85,11 @@ private let _childProcessContinuations = Locked<[pid_t: CheckedContinuation.allocate(capacity: 1) + #else let result = UnsafeMutablePointer.allocate(capacity: 1) + #endif _ = pthread_cond_init(result, nil) return result }() @@ -132,7 +136,7 @@ private let _createWaitThread: Void = { // Create the thread. It will run immediately; because it runs in an infinite // loop, we aren't worried about detaching or joining it. -#if SWT_TARGET_OS_APPLE +#if SWT_TARGET_OS_APPLE || os(FreeBSD) var thread: pthread_t? #else var thread = pthread_t() diff --git a/Sources/Testing/Support/Locked.swift b/Sources/Testing/Support/Locked.swift index df18319d0..028907522 100644 --- a/Sources/Testing/Support/Locked.swift +++ b/Sources/Testing/Support/Locked.swift @@ -36,8 +36,10 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { /// To keep the implementation of this type as simple as possible, /// `pthread_mutex_t` is used on Apple platforms instead of `os_unfair_lock` /// or `OSAllocatedUnfairLock`. -#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) private typealias _Lock = pthread_mutex_t +#elseif os(FreeBSD) + private typealias _Lock = pthread_mutex_t? #elseif os(Windows) private typealias _Lock = SRWLOCK #elseif os(WASI) @@ -121,7 +123,7 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { } } -#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) /// Acquire the lock and invoke a function while it is held, yielding both the /// protected value and a reference to the lock itself. /// @@ -149,6 +151,34 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { } } } +#elseif os(FreeBSD) + /// Acquire the lock and invoke a function while it is held, yielding both the + /// protected value and a reference to the lock itself. + /// + /// - Parameters: + /// - body: A closure to invoke while the lock is held. + /// + /// - Returns: Whatever is returned by `body`. + /// + /// - Throws: Whatever is thrown by `body`. + /// + /// This function is equivalent to ``withLock(_:)`` except that the closure + /// passed to it also takes a reference to the underlying platform lock. This + /// function can be used when platform-specific functionality such as a + /// `pthread_cond_t` is needed. Because the caller has direct access to the + /// lock and is able to unlock and re-lock it, it is unsafe to modify the + /// protected value. + /// + /// - Warning: Callers that unlock the lock _must_ lock it again before the + /// closure returns. If the lock is not acquired when `body` returns, the + /// effect is undefined. + nonmutating func withUnsafeUnderlyingLock(_ body: (UnsafeMutablePointer, T) throws -> R) rethrows -> R { + try withLock { value in + try _storage.withUnsafeMutablePointerToElements { lock in + try body(lock, value) + } + } + } #endif } diff --git a/Sources/_TestingInternals/include/Includes.h b/Sources/_TestingInternals/include/Includes.h index 4a621d5c2..4962fb342 100644 --- a/Sources/_TestingInternals/include/Includes.h +++ b/Sources/_TestingInternals/include/Includes.h @@ -80,6 +80,10 @@ #include #endif +#if __has_include() +#include +#endif + #if __has_include() #include #endif From 53a4b5db12063c078a3c8cbf66376735143f37c8 Mon Sep 17 00:00:00 2001 From: Michael Chiu Date: Wed, 18 Dec 2024 13:17:56 -0800 Subject: [PATCH 2/3] Rename _Lock to PlatformLock, change visibility to internal --- Sources/Testing/Support/Locked.swift | 46 ++++++---------------------- 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/Sources/Testing/Support/Locked.swift b/Sources/Testing/Support/Locked.swift index 028907522..61013cd33 100644 --- a/Sources/Testing/Support/Locked.swift +++ b/Sources/Testing/Support/Locked.swift @@ -37,21 +37,21 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { /// `pthread_mutex_t` is used on Apple platforms instead of `os_unfair_lock` /// or `OSAllocatedUnfairLock`. #if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) - private typealias _Lock = pthread_mutex_t + typealias PlatformLock = pthread_mutex_t #elseif os(FreeBSD) - private typealias _Lock = pthread_mutex_t? + typealias PlatformLock = pthread_mutex_t? #elseif os(Windows) - private typealias _Lock = SRWLOCK + typealias PlatformLock = SRWLOCK #elseif os(WASI) // No locks on WASI without multithreaded runtime. - private typealias _Lock = Void + typealias PlatformLock = Void #else #warning("Platform-specific implementation missing: locking unavailable") - private typealias _Lock = Void + typealias PlatformLock = Void #endif /// A type providing heap-allocated storage for an instance of ``Locked``. - private final class _Storage: ManagedBuffer { + private final class _Storage: ManagedBuffer { deinit { withUnsafeMutablePointerToElements { lock in #if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) @@ -68,7 +68,7 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { } /// Storage for the underlying lock and wrapped value. - private nonisolated(unsafe) var _storage: ManagedBuffer + private nonisolated(unsafe) var _storage: ManagedBuffer init(rawValue: T) { _storage = _Storage.create(minimumCapacity: 1, makingHeaderWith: { _ in rawValue }) @@ -123,35 +123,7 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { } } -#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) - /// Acquire the lock and invoke a function while it is held, yielding both the - /// protected value and a reference to the lock itself. - /// - /// - Parameters: - /// - body: A closure to invoke while the lock is held. - /// - /// - Returns: Whatever is returned by `body`. - /// - /// - Throws: Whatever is thrown by `body`. - /// - /// This function is equivalent to ``withLock(_:)`` except that the closure - /// passed to it also takes a reference to the underlying platform lock. This - /// function can be used when platform-specific functionality such as a - /// `pthread_cond_t` is needed. Because the caller has direct access to the - /// lock and is able to unlock and re-lock it, it is unsafe to modify the - /// protected value. - /// - /// - Warning: Callers that unlock the lock _must_ lock it again before the - /// closure returns. If the lock is not acquired when `body` returns, the - /// effect is undefined. - nonmutating func withUnsafeUnderlyingLock(_ body: (UnsafeMutablePointer, T) throws -> R) rethrows -> R { - try withLock { value in - try _storage.withUnsafeMutablePointerToElements { lock in - try body(lock, value) - } - } - } -#elseif os(FreeBSD) +#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) /// Acquire the lock and invoke a function while it is held, yielding both the /// protected value and a reference to the lock itself. /// @@ -172,7 +144,7 @@ struct Locked: RawRepresentable, Sendable where T: Sendable { /// - Warning: Callers that unlock the lock _must_ lock it again before the /// closure returns. If the lock is not acquired when `body` returns, the /// effect is undefined. - nonmutating func withUnsafeUnderlyingLock(_ body: (UnsafeMutablePointer, T) throws -> R) rethrows -> R { + nonmutating func withUnsafeUnderlyingLock(_ body: (UnsafeMutablePointer, T) throws -> R) rethrows -> R { try withLock { value in try _storage.withUnsafeMutablePointerToElements { lock in try body(lock, value) From cfe7035749d20ae6241cbf5ffbd799902a2acf97 Mon Sep 17 00:00:00 2001 From: Michael Chiu Date: Wed, 18 Dec 2024 13:26:07 -0800 Subject: [PATCH 3/3] add missing header for FreeBSD --- Sources/_TestingInternals/include/Includes.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/_TestingInternals/include/Includes.h b/Sources/_TestingInternals/include/Includes.h index 4962fb342..51c02e277 100644 --- a/Sources/_TestingInternals/include/Includes.h +++ b/Sources/_TestingInternals/include/Includes.h @@ -129,6 +129,10 @@ #endif #endif +#if defined(__FreeBSD__) +#include +#endif + #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #define NOMINMAX