From 014d874e5a410868737e17d0cfe0fcf76d4eca1a Mon Sep 17 00:00:00 2001 From: michael-yuji Date: Wed, 18 Dec 2024 14:24:27 -0800 Subject: [PATCH] Additional FreeBSD fixes (#865) Add FreeBSD support for swift-testing. ### Result: With this PR, swift-testing can be built on FreeBSD (tested on x86_64 FreeBSD 14.1-RELEASE-p6) ### Known issue: There are some issue running `swift test` on this repo, but most likely due to bugs in my host toolchain. - Tests failed to link due to duplicated main symbols: ``` error: link command failed with exit code 1 (use -v to see invocation) ld: error: duplicate symbol: main >>> defined at TestingMacrosMain.swift:0 (/zdata/swift-main/swift-project/swift-testing/Sources/TestingMacros/TestingMacrosMain.swift:0) >>> /zdata/swift-main/swift-project/swift-testing/.build/x86_64-unknown-freebsd14.1/debug/TestingMacros-tool.build/TestingMacrosMain.swift.o:(main) >>> defined at runner.swift:0 (/zdata/swift-main/swift-project/swift-testing/.build/x86_64-unknown-freebsd14.1/debug/swift-testingPackageTests.derived/runner.swift:0) >>> /zdata/swift-main/swift-project/swift-testing/.build/x86_64-unknown-freebsd14.1/debug/swift_testingPackageTests-tool.build/runner.swift.o:(.text.main+0x0) clang: error: linker command failed with exit code 1 (use -v to see invocation) [25/26] Linking swift-testingPackageTests.xctest ``` - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated. --- Sources/Testing/ExitTests/ExitTest.swift | 2 +- Sources/Testing/ExitTests/SpawnProcess.swift | 9 ++++++++- Sources/Testing/ExitTests/WaitFor.swift | 6 +++++- Sources/Testing/Support/Locked.swift | 18 ++++++++++-------- Sources/_TestingInternals/include/Includes.h | 8 ++++++++ 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Sources/Testing/ExitTests/ExitTest.swift b/Sources/Testing/ExitTests/ExitTest.swift index edb01c4dc..5c3179ae5 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 2d13b1955..91a2b48a3 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..61013cd33 100644 --- a/Sources/Testing/Support/Locked.swift +++ b/Sources/Testing/Support/Locked.swift @@ -36,20 +36,22 @@ 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)) - private typealias _Lock = pthread_mutex_t +#if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded)) + typealias PlatformLock = pthread_mutex_t +#elseif os(FreeBSD) + 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)) @@ -66,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 }) @@ -142,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) diff --git a/Sources/_TestingInternals/include/Includes.h b/Sources/_TestingInternals/include/Includes.h index 4a621d5c2..51c02e277 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 @@ -125,6 +129,10 @@ #endif #endif +#if defined(__FreeBSD__) +#include +#endif + #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #define NOMINMAX