Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions Sources/Testing/Support/Locked.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -24,7 +26,7 @@ private import Synchronization
/// This type is not part of the public interface of the testing library.
struct Locked<T> {
/// 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<T, os_unfair_lock_s>
#elseif !SWT_FIXED_85448 && (os(Linux) || os(Android))
private final class _Storage: ManagedBuffer<T, pthread_mutex_t> {
Expand All @@ -34,14 +36,16 @@ struct Locked<T> {
}
}
}
#else
#elseif canImport(Synchronization)
private final class _Storage {
let mutex: Mutex<T>

init(_ rawValue: consuming sending T) {
mutex = Mutex(rawValue)
}
}
#else
#error("Platform-specific misconfiguration: no mutex or lock type available")
#endif

/// Storage for the underlying lock and wrapped value.
Expand All @@ -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())
Expand All @@ -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
}

Expand All @@ -91,7 +97,7 @@ extension Locked {
/// concurrency tools.
func withLock<R>(_ 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 {
Expand All @@ -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
}
Expand All @@ -130,7 +138,7 @@ extension Locked {
/// concurrency tools.
func withLockIfAvailable<R>(_ 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
Expand All @@ -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
}
Expand Down
10 changes: 8 additions & 2 deletions Sources/Testing/Support/Serializer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
}

Expand All @@ -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<Void, Never>]()
#endif

init(maximumWidth: Int = 1) {
precondition(maximumWidth >= 1, "Invalid serializer width \(maximumWidth).")
Expand All @@ -65,6 +69,7 @@ final actor Serializer {
///
/// - Throws: Whatever is thrown by `workItem`.
func run<R>(_ 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.
Expand All @@ -86,6 +91,7 @@ final actor Serializer {
_continuations.append(continuation)
}
}
#endif

return try await workItem()
}
Expand Down