3405691582 03fe46f43b
OpenBSD support. (#1126)
* Advise porter on where to make necessary change.

In #1075 the change was already made for BSD (thank you!); my working
edit had this guidance to ensure future porters get an error directing
them where to make a necessary change.

Otherwise, the FoundationEssentials build will fail and complain these
variables are not defined but not have guidance as to where they are
sourced from.

* OpenBSD does not support extended attributes.

* OpenBSD does not have secure_getenv.

* Remaining OpenBSD changes.

* OpenBSD also needs `pthread_mutex_t?`.

* Originally I followed Darwin's check with `d_namlen`, but this should
  work too.

* Correct statvfs type casts for OpenBSD.

On OpenBSD, fsblkcnt_t -- the type of f_blocks -- is a UInt64; therefore,
so must `blockSize` be.

Ultimately, both sides of the `totalSizeBytes` multiplication should
probably be type cast for all platforms, but that's a more significant
functional change for another time.

* Default activeProcessorCount to 1, not 0.

After a rather tedious debugging session trying to figure out why
swiftpm-bootstrap appeared to be deadlocked, this turned out to be the
culprit. Perhaps this should be #error instead, but for now, set a
sensible default.

* Use sysconf for activeProcessorCount.

This is what Dispatch does in some places for OpenBSD anyway, so do
likewise here.
2025-04-07 10:46:18 -07:00

167 lines
5.1 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#if canImport(os)
internal import os
#if FOUNDATION_FRAMEWORK && canImport(C.os.lock)
internal import C.os.lock
#endif
#elseif canImport(Bionic)
@preconcurrency import Bionic
#elseif canImport(Glibc)
@preconcurrency import Glibc
#elseif canImport(Musl)
@preconcurrency import Musl
#elseif canImport(WinSDK)
import WinSDK
#endif
package struct LockedState<State> {
// Internal implementation for a cheap lock to aid sharing code across platforms
private struct _Lock {
#if canImport(os)
typealias Primitive = os_unfair_lock
#elseif os(FreeBSD) || os(OpenBSD)
typealias Primitive = pthread_mutex_t?
#elseif canImport(Bionic) || canImport(Glibc) || canImport(Musl)
typealias Primitive = pthread_mutex_t
#elseif canImport(WinSDK)
typealias Primitive = SRWLOCK
#elseif os(WASI)
// WASI is single-threaded, so we don't need a lock.
typealias Primitive = Void
#endif
typealias PlatformLock = UnsafeMutablePointer<Primitive>
var _platformLock: PlatformLock
fileprivate static func initialize(_ platformLock: PlatformLock) {
#if canImport(os)
platformLock.initialize(to: os_unfair_lock())
#elseif canImport(Bionic) || canImport(Glibc) || canImport(Musl)
pthread_mutex_init(platformLock, nil)
#elseif canImport(WinSDK)
InitializeSRWLock(platformLock)
#elseif os(WASI)
// no-op
#else
#error("LockedState._Lock.initialize is unimplemented on this platform")
#endif
}
fileprivate static func deinitialize(_ platformLock: PlatformLock) {
#if canImport(Bionic) || canImport(Glibc) || canImport(Musl)
pthread_mutex_destroy(platformLock)
#endif
platformLock.deinitialize(count: 1)
}
static fileprivate func lock(_ platformLock: PlatformLock) {
#if canImport(os)
os_unfair_lock_lock(platformLock)
#elseif canImport(Bionic) || canImport(Glibc) || canImport(Musl)
pthread_mutex_lock(platformLock)
#elseif canImport(WinSDK)
AcquireSRWLockExclusive(platformLock)
#elseif os(WASI)
// no-op
#else
#error("LockedState._Lock.lock is unimplemented on this platform")
#endif
}
static fileprivate func unlock(_ platformLock: PlatformLock) {
#if canImport(os)
os_unfair_lock_unlock(platformLock)
#elseif canImport(Bionic) || canImport(Glibc) || canImport(Musl)
pthread_mutex_unlock(platformLock)
#elseif canImport(WinSDK)
ReleaseSRWLockExclusive(platformLock)
#elseif os(WASI)
// no-op
#else
#error("LockedState._Lock.unlock is unimplemented on this platform")
#endif
}
}
private class _Buffer: ManagedBuffer<State, _Lock.Primitive> {
deinit {
withUnsafeMutablePointerToElements {
_Lock.deinitialize($0)
}
}
}
private let _buffer: ManagedBuffer<State, _Lock.Primitive>
package init(initialState: State) {
_buffer = _Buffer.create(minimumCapacity: 1, makingHeaderWith: { buf in
buf.withUnsafeMutablePointerToElements {
_Lock.initialize($0)
}
return initialState
})
}
package func withLock<T>(_ body: @Sendable (inout State) throws -> T) rethrows -> T {
try withLockUnchecked(body)
}
package func withLockUnchecked<T>(_ body: (inout State) throws -> T) rethrows -> T {
try _buffer.withUnsafeMutablePointers { state, lock in
_Lock.lock(lock)
defer { _Lock.unlock(lock) }
return try body(&state.pointee)
}
}
// Ensures the managed state outlives the locked scope.
package func withLockExtendingLifetimeOfState<T>(_ body: @Sendable (inout State) throws -> T) rethrows -> T {
try _buffer.withUnsafeMutablePointers { state, lock in
_Lock.lock(lock)
return try withExtendedLifetime(state.pointee) {
defer { _Lock.unlock(lock) }
return try body(&state.pointee)
}
}
}
}
extension LockedState where State == Void {
package init() {
self.init(initialState: ())
}
package func withLock<R: Sendable>(_ body: @Sendable () throws -> R) rethrows -> R {
return try withLock { _ in
try body()
}
}
package func lock() {
_buffer.withUnsafeMutablePointerToElements { lock in
_Lock.lock(lock)
}
}
package func unlock() {
_buffer.withUnsafeMutablePointerToElements { lock in
_Lock.unlock(lock)
}
}
}
extension LockedState: @unchecked Sendable where State: Sendable {}