Skip to content

Commit 2f20b5c

Browse files
committed
Add Windows support by fixing Locks.swift to support windows
**Motivation:** Swift is cross platform, including Windows, we should support distributed tracing on any platform **Modifications:** Add windows CI and make necessary changes **Result:** Windows support <!-- After your change, what will change. -->
1 parent d9c3031 commit 2f20b5c

File tree

3 files changed

+105
-31
lines changed

3 files changed

+105
-31
lines changed

.github/workflows/main.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ jobs:
1818
linux_6_2_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
1919
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
2020
linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
21+
windows_6_0_enabled: true
22+
windows_6_1_enabled: true
23+
windows_nightly_next_enabled: true
24+
windows_nightly_main_enabled: true
25+
windows_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
26+
windows_6_1_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
27+
windows_nightly_next_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
28+
windows_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
2129

2230
benchmarks:
2331
name: Benchmarks

.github/workflows/pull_request.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ jobs:
4040
linux_6_2_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
4141
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
4242
linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
43+
windows_6_0_enabled: true
44+
windows_6_1_enabled: true
45+
windows_nightly_next_enabled: true
46+
windows_nightly_main_enabled: true
47+
windows_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
48+
windows_6_1_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
49+
windows_nightly_next_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
50+
windows_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
4351

4452
benchmarks:
4553
name: Benchmarks

Sources/Instrumentation/Locks.swift

Lines changed: 89 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,80 +26,126 @@
2626
//
2727
//===----------------------------------------------------------------------===//
2828

29-
#if canImport(Darwin)
29+
#if canImport(WASILibc)
30+
// No locking on WASILibc
31+
#elseif canImport(Darwin)
3032
import Darwin
33+
#elseif os(Windows)
34+
import WinSDK
3135
#elseif canImport(Glibc)
3236
import Glibc
3337
#elseif canImport(Android)
3438
import Android
3539
#elseif canImport(Musl)
3640
import Musl
37-
#elseif canImport(WASILibc)
38-
import WASILibc
39-
#if canImport(wasi_pthread)
40-
import wasi_pthread
41-
#endif
4241
#else
4342
#error("Unsupported runtime")
4443
#endif
4544

46-
/// A threading lock based on `libpthread` instead of `libdispatch`.
45+
/// A reader/writer threading lock based on `libpthread` instead of `libdispatch`.
4746
///
48-
/// This object provides a lock on top of a single `pthread_mutex_t`. This kind
47+
/// This object provides a lock on top of a single `pthread_rwlock_t`. This kind
4948
/// of lock is safe to use with `libpthread`-based threading models, such as the
50-
/// one used by NIO.
51-
@_spi(Locking) // Use the `package` access modifier once min Swift version is increased.
52-
public final class ReadWriteLock {
53-
private let rwlock: UnsafeMutablePointer<pthread_rwlock_t> = UnsafeMutablePointer.allocate(capacity: 1)
49+
/// one used by NIO. On Windows, the lock is based on the substantially similar
50+
/// `SRWLOCK` type.
51+
public final class ReadWriteLock: @unchecked Sendable {
52+
#if canImport(WASILibc)
53+
// WASILibc is single threaded, provides no locks
54+
#elseif os(Windows)
55+
fileprivate let rwlock: UnsafeMutablePointer<SRWLOCK> =
56+
UnsafeMutablePointer.allocate(capacity: 1)
57+
fileprivate var shared: Bool = true
58+
#else
59+
fileprivate let rwlock: UnsafeMutablePointer<pthread_rwlock_t> =
60+
UnsafeMutablePointer.allocate(capacity: 1)
61+
#endif
5462

5563
/// Create a new lock.
5664
public init() {
65+
#if canImport(WASILibc)
66+
// WASILibc is single threaded, provides no locks
67+
#elseif os(Windows)
68+
InitializeSRWLock(self.rwlock)
69+
#else
5770
let err = pthread_rwlock_init(self.rwlock, nil)
58-
precondition(err == 0, "pthread_rwlock_init failed with error \(err)")
71+
precondition(err == 0, "\(#function) failed in pthread_rwlock with error \(err)")
72+
#endif
5973
}
6074

6175
deinit {
76+
#if canImport(WASILibc)
77+
// WASILibc is single threaded, provides no locks
78+
#elseif os(Windows)
79+
// SRWLOCK does not need to be free'd
80+
self.rwlock.deallocate()
81+
#else
6282
let err = pthread_rwlock_destroy(self.rwlock)
63-
precondition(err == 0, "pthread_rwlock_destroy failed with error \(err)")
83+
precondition(err == 0, "\(#function) failed in pthread_rwlock with error \(err)")
6484
self.rwlock.deallocate()
85+
#endif
6586
}
6687

6788
/// Acquire a reader lock.
6889
///
69-
/// Whenever possible, consider using `withLock` instead of this method and
70-
/// `unlock`, to simplify lock handling.
90+
/// Whenever possible, consider using `withReaderLock` instead of this
91+
/// method and `unlock`, to simplify lock handling.
7192
public func lockRead() {
93+
#if canImport(WASILibc)
94+
// WASILibc is single threaded, provides no locks
95+
#elseif os(Windows)
96+
AcquireSRWLockShared(self.rwlock)
97+
self.shared = true
98+
#else
7299
let err = pthread_rwlock_rdlock(self.rwlock)
73-
precondition(err == 0, "pthread_rwlock_rdlock failed with error \(err)")
100+
precondition(err == 0, "\(#function) failed in pthread_rwlock with error \(err)")
101+
#endif
74102
}
75103

76104
/// Acquire a writer lock.
77105
///
78-
/// Whenever possible, consider using `withLock` instead of this method and
79-
/// `unlock`, to simplify lock handling.
106+
/// Whenever possible, consider using `withWriterLock` instead of this
107+
/// method and `unlock`, to simplify lock handling.
80108
public func lockWrite() {
109+
#if canImport(WASILibc)
110+
// WASILibc is single threaded, provides no locks
111+
#elseif os(Windows)
112+
AcquireSRWLockExclusive(self.rwlock)
113+
self.shared = false
114+
#else
81115
let err = pthread_rwlock_wrlock(self.rwlock)
82-
precondition(err == 0, "pthread_rwlock_wrlock failed with error \(err)")
116+
precondition(err == 0, "\(#function) failed in pthread_rwlock with error \(err)")
117+
#endif
83118
}
84119

85120
/// Release the lock.
86121
///
87-
/// Whenever possible, consider using `withLock` instead of this method and
88-
/// `lock`, to simplify lock handling.
122+
/// Whenever possible, consider using `withReaderLock` and `withWriterLock`
123+
/// instead of this method and `lockRead` and `lockWrite`, to simplify lock
124+
/// handling.
89125
public func unlock() {
126+
#if canImport(WASILibc)
127+
// WASILibc is single threaded, provides no locks
128+
#elseif os(Windows)
129+
if self.shared {
130+
ReleaseSRWLockShared(self.rwlock)
131+
} else {
132+
ReleaseSRWLockExclusive(self.rwlock)
133+
}
134+
#else
90135
let err = pthread_rwlock_unlock(self.rwlock)
91-
precondition(err == 0, "pthread_rwlock_unlock failed with error \(err)")
136+
precondition(err == 0, "\(#function) failed in pthread_rwlock with error \(err)")
137+
#endif
92138
}
93139
}
94140

95141
extension ReadWriteLock {
96142
/// Acquire the reader lock for the duration of the given block.
97143
///
98-
/// This convenience method should be preferred to `lock` and `unlock` in
99-
/// most situations, as it ensures that the lock will be released regardless
100-
/// of how `body` exits.
144+
/// This convenience method should be preferred to `lockRead` and `unlock`
145+
/// in most situations, as it ensures that the lock will be released
146+
/// regardless of how `body` exits.
101147
///
102-
/// - Parameter body: The block to execute while holding the lock.
148+
/// - Parameter body: The block to execute while holding the reader lock.
103149
/// - Returns: The value returned by the block.
104150
@inlinable
105151
public func withReaderLock<T>(_ body: () throws -> T) rethrows -> T {
@@ -112,11 +158,11 @@ extension ReadWriteLock {
112158

113159
/// Acquire the writer lock for the duration of the given block.
114160
///
115-
/// This convenience method should be preferred to `lock` and `unlock` in
116-
/// most situations, as it ensures that the lock will be released regardless
117-
/// of how `body` exits.
161+
/// This convenience method should be preferred to `lockWrite` and `unlock`
162+
/// in most situations, as it ensures that the lock will be released
163+
/// regardless of how `body` exits.
118164
///
119-
/// - Parameter body: The block to execute while holding the lock.
165+
/// - Parameter body: The block to execute while holding the writer lock.
120166
/// - Returns: The value returned by the block.
121167
@inlinable
122168
public func withWriterLock<T>(_ body: () throws -> T) rethrows -> T {
@@ -126,6 +172,18 @@ extension ReadWriteLock {
126172
}
127173
return try body()
128174
}
175+
176+
// specialise Void return (for performance)
177+
@inlinable
178+
internal func withReaderLockVoid(_ body: () throws -> Void) rethrows {
179+
try self.withReaderLock(body)
180+
}
181+
182+
// specialise Void return (for performance)
183+
@inlinable
184+
internal func withWriterLockVoid(_ body: () throws -> Void) rethrows {
185+
try self.withWriterLock(body)
186+
}
129187
}
130188

131189
/// A wrapper providing locked access to a value.

0 commit comments

Comments
 (0)