Skip to content

Commit

Permalink
Additional FreeBSD fixes (#865)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
michael-yuji authored Dec 18, 2024
1 parent c61e5ad commit 014d874
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 11 deletions.
2 changes: 1 addition & 1 deletion Sources/Testing/ExitTests/ExitTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion Sources/Testing/ExitTests/SpawnProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion Sources/Testing/ExitTests/WaitFor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@ private let _childProcessContinuations = Locked<[pid_t: CheckedContinuation<Exit
/// A condition variable used to suspend the waiter thread created by
/// `_createWaitThread()` when there are no child processes to await.
private nonisolated(unsafe) let _waitThreadNoChildrenCondition = {
#if os(FreeBSD)
let result = UnsafeMutablePointer<pthread_cond_t?>.allocate(capacity: 1)
#else
let result = UnsafeMutablePointer<pthread_cond_t>.allocate(capacity: 1)
#endif
_ = pthread_cond_init(result, nil)
return result
}()
Expand Down Expand Up @@ -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()
Expand Down
18 changes: 10 additions & 8 deletions Sources/Testing/Support/Locked.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,22 @@ struct Locked<T>: 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<T, _Lock> {
private final class _Storage: ManagedBuffer<T, PlatformLock> {
deinit {
withUnsafeMutablePointerToElements { lock in
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded))
Expand All @@ -66,7 +68,7 @@ struct Locked<T>: RawRepresentable, Sendable where T: Sendable {
}

/// Storage for the underlying lock and wrapped value.
private nonisolated(unsafe) var _storage: ManagedBuffer<T, _Lock>
private nonisolated(unsafe) var _storage: ManagedBuffer<T, PlatformLock>

init(rawValue: T) {
_storage = _Storage.create(minimumCapacity: 1, makingHeaderWith: { _ in rawValue })
Expand Down Expand Up @@ -142,7 +144,7 @@ struct Locked<T>: 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<R>(_ body: (UnsafeMutablePointer<pthread_mutex_t>, T) throws -> R) rethrows -> R {
nonmutating func withUnsafeUnderlyingLock<R>(_ body: (UnsafeMutablePointer<PlatformLock>, T) throws -> R) rethrows -> R {
try withLock { value in
try _storage.withUnsafeMutablePointerToElements { lock in
try body(lock, value)
Expand Down
8 changes: 8 additions & 0 deletions Sources/_TestingInternals/include/Includes.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@
#include <pthread.h>
#endif

#if __has_include(<pthread_np.h>)
#include <pthread_np.h>
#endif

#if __has_include(<pty.h>)
#include <pty.h>
#endif
Expand Down Expand Up @@ -125,6 +129,10 @@
#endif
#endif

#if defined(__FreeBSD__)
#include <libutil.h>
#endif

#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
Expand Down

0 comments on commit 014d874

Please sign in to comment.