File tree 4 files changed +30
-5
lines changed
4 files changed +30
-5
lines changed Original file line number Diff line number Diff line change @@ -46,7 +46,7 @@ import Musl
46
46
/// of lock is safe to use with `libpthread`-based threading models, such as the
47
47
/// one used by NIO. On Windows, the lock is based on the substantially similar
48
48
/// `SRWLOCK` type.
49
- internal final class Lock : Sendable {
49
+ internal final class Lock {
50
50
#if os(Windows)
51
51
fileprivate let mutex : UnsafeMutablePointer < SRWLOCK > =
52
52
UnsafeMutablePointer . allocate ( capacity: 1 )
@@ -131,6 +131,8 @@ extension Lock {
131
131
}
132
132
}
133
133
134
+ extension Lock : @unchecked Sendable { }
135
+
134
136
/// A reader/writer threading lock based on `libpthread` instead of `libdispatch`.
135
137
///
136
138
/// This object provides a lock on top of a single `pthread_rwlock_t`. This kind
@@ -273,3 +275,5 @@ extension ReadWriteLock {
273
275
try self . withWriterLock ( body)
274
276
}
275
277
}
278
+
279
+ extension ReadWriteLock : @unchecked Sendable { }
Original file line number Diff line number Diff line change @@ -600,7 +600,8 @@ public enum MetricsSystem {
600
600
return try self . _factory. withWriterLock ( body)
601
601
}
602
602
603
- private final class FactoryBox {
603
+ // This can be `@unchecked Sendable` because we're manually gating access to mutable state with a lock.
604
+ private final class FactoryBox : @unchecked Sendable {
604
605
private let lock = ReadWriteLock ( )
605
606
fileprivate var _underlying : MetricsFactory
606
607
private var initialized = false
Original file line number Diff line number Diff line change @@ -60,6 +60,16 @@ extension Timer {
60
60
/// - duration: The duration to record.
61
61
@inlinable
62
62
public func record( _ duration: DispatchTimeInterval ) {
63
+ // This wrapping in a optional is a workaround because DispatchTimeInterval
64
+ // is a non-frozen public enum and Dispatch is built with library evolution
65
+ // mode turned on.
66
+ // This means we should have an `@unknown default` case, but this breaks
67
+ // on non-Darwin platforms.
68
+ // Switching over an optional means that the `.none` case will map to
69
+ // `default` (which means we'll always have a valid case to go into
70
+ // the default case), but in reality this case will never exist as this
71
+ // optional will never be nil.
72
+ let duration = Optional ( duration)
63
73
switch duration {
64
74
case . nanoseconds( let value) :
65
75
self . recordNanoseconds ( value)
@@ -71,7 +81,7 @@ extension Timer {
71
81
self . recordSeconds ( value)
72
82
case . never:
73
83
self . record ( 0 )
74
- @ unknown default :
84
+ default :
75
85
self . record ( 0 )
76
86
}
77
87
}
Original file line number Diff line number Diff line change @@ -185,7 +185,17 @@ class MetricsExtensionsTests: XCTestCase {
185
185
// https://bugs.swift.org/browse/SR-6310
186
186
extension DispatchTimeInterval {
187
187
func nano( ) -> Int {
188
- switch self {
188
+ // This wrapping in a optional is a workaround because DispatchTimeInterval
189
+ // is a non-frozen public enum and Dispatch is built with library evolution
190
+ // mode turned on.
191
+ // This means we should have an `@unknown default` case, but this breaks
192
+ // on non-Darwin platforms.
193
+ // Switching over an optional means that the `.none` case will map to
194
+ // `default` (which means we'll always have a valid case to go into
195
+ // the default case), but in reality this case will never exist as this
196
+ // optional will never be nil.
197
+ let interval = Optional ( self )
198
+ switch interval {
189
199
case . nanoseconds( let value) :
190
200
return value
191
201
case . microseconds( let value) :
@@ -196,7 +206,7 @@ extension DispatchTimeInterval {
196
206
return value * 1_000_000_000
197
207
case . never:
198
208
return 0
199
- @ unknown default :
209
+ default :
200
210
return 0
201
211
}
202
212
}
You can’t perform that action at this time.
0 commit comments