diff --git a/Sources/Testing/Support/Locked.swift b/Sources/Testing/Support/Locked.swift index fbebaa063..601fb14ce 100644 --- a/Sources/Testing/Support/Locked.swift +++ b/Sources/Testing/Support/Locked.swift @@ -9,7 +9,9 @@ // internal import _TestingInternals +#if canImport(Synchronization) private import Synchronization +#endif /// A type that wraps a value requiring access from a synchronous caller during /// concurrent execution. @@ -24,7 +26,7 @@ private import Synchronization /// This type is not part of the public interface of the testing library. struct Locked { /// A type providing storage for the underlying lock and wrapped value. -#if SWT_TARGET_OS_APPLE && canImport(os) +#if SWT_TARGET_OS_APPLE && !SWT_NO_OS_UNFAIR_LOCK private typealias _Storage = ManagedBuffer #elseif !SWT_FIXED_85448 && (os(Linux) || os(Android)) private final class _Storage: ManagedBuffer { @@ -34,7 +36,7 @@ struct Locked { } } } -#else +#elseif canImport(Synchronization) private final class _Storage { let mutex: Mutex @@ -42,6 +44,8 @@ struct Locked { mutex = Mutex(rawValue) } } +#else +#error("Platform-specific misconfiguration: no mutex or lock type available") #endif /// Storage for the underlying lock and wrapped value. @@ -52,7 +56,7 @@ extension Locked: Sendable where T: Sendable {} extension Locked: RawRepresentable { init(rawValue: T) { -#if SWT_TARGET_OS_APPLE && canImport(os) +#if SWT_TARGET_OS_APPLE && !SWT_NO_OS_UNFAIR_LOCK _storage = .create(minimumCapacity: 1, makingHeaderWith: { _ in rawValue }) _storage.withUnsafeMutablePointerToElements { lock in lock.initialize(to: .init()) @@ -62,9 +66,11 @@ extension Locked: RawRepresentable { _storage.withUnsafeMutablePointerToElements { lock in _ = pthread_mutex_init(lock, nil) } -#else +#elseif canImport(Synchronization) nonisolated(unsafe) let rawValue = rawValue _storage = _Storage(rawValue) +#else +#error("Platform-specific misconfiguration: no mutex or lock type available") #endif } @@ -91,7 +97,7 @@ extension Locked { /// concurrency tools. func withLock(_ body: (inout T) throws -> sending R) rethrows -> sending R where R: ~Copyable { nonisolated(unsafe) let result: R -#if SWT_TARGET_OS_APPLE && canImport(os) +#if SWT_TARGET_OS_APPLE && !SWT_NO_OS_UNFAIR_LOCK result = try _storage.withUnsafeMutablePointers { rawValue, lock in os_unfair_lock_lock(lock) defer { @@ -107,10 +113,12 @@ extension Locked { } return try body(&rawValue.pointee) } -#else +#elseif canImport(Synchronization) result = try _storage.mutex.withLock { rawValue in try body(&rawValue) } +#else +#error("Platform-specific misconfiguration: no mutex or lock type available") #endif return result } @@ -130,7 +138,7 @@ extension Locked { /// concurrency tools. func withLockIfAvailable(_ body: (inout T) throws -> sending R) rethrows -> sending R? where R: ~Copyable { nonisolated(unsafe) let result: R? -#if SWT_TARGET_OS_APPLE && canImport(os) +#if SWT_TARGET_OS_APPLE && !SWT_NO_OS_UNFAIR_LOCK result = try _storage.withUnsafeMutablePointers { rawValue, lock in guard os_unfair_lock_trylock(lock) else { return nil @@ -150,10 +158,12 @@ extension Locked { } return try body(&rawValue.pointee) } -#else +#elseif canImport(Synchronization) result = try _storage.mutex.withLockIfAvailable { rawValue in return try body(&rawValue) } +#else +#error("Platform-specific misconfiguration: no mutex or lock type available") #endif return result } diff --git a/Sources/Testing/Support/Serializer.swift b/Sources/Testing/Support/Serializer.swift index 96adfca7c..94f7d4f5b 100644 --- a/Sources/Testing/Support/Serializer.swift +++ b/Sources/Testing/Support/Serializer.swift @@ -10,9 +10,10 @@ private import _TestingInternals +#if !SWT_NO_UNSTRUCTURED_TASKS /// The number of CPU cores on the current system, or `nil` if that /// information is not available. -var cpuCoreCount: Int? { +private var _cpuCoreCount: Int? { #if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) return Int(sysconf(Int32(_SC_NPROCESSORS_CONF))) #elseif os(Windows) @@ -26,10 +27,11 @@ var cpuCoreCount: Int? { return nil #endif } +#endif /// The default parallelization width when parallelized testing is enabled. var defaultParallelizationWidth: Int { - // cpuCoreCount.map { max(1, $0) * 2 } ?? .max + // _cpuCoreCount.map { max(1, $0) * 2 } ?? .max .max } @@ -45,11 +47,13 @@ final actor Serializer { /// The maximum number of work items that may run concurrently. nonisolated let maximumWidth: Int +#if !SWT_NO_UNSTRUCTURED_TASKS /// The number of scheduled work items, including any currently running. private var _currentWidth = 0 /// Continuations for any scheduled work items that haven't started yet. private var _continuations = [CheckedContinuation]() +#endif init(maximumWidth: Int = 1) { precondition(maximumWidth >= 1, "Invalid serializer width \(maximumWidth).") @@ -65,6 +69,7 @@ final actor Serializer { /// /// - Throws: Whatever is thrown by `workItem`. func run(_ workItem: @isolated(any) @Sendable () async throws -> R) async rethrows -> R where R: Sendable { +#if !SWT_NO_UNSTRUCTURED_TASKS _currentWidth += 1 defer { // Resume the next scheduled closure. @@ -86,6 +91,7 @@ final actor Serializer { _continuations.append(continuation) } } +#endif return try await workItem() }