Skip to content

Commit 628b4e5

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 628b4e5

File tree

3 files changed

+111
-31
lines changed

3 files changed

+111
-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: 95 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@
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)
@@ -43,66 +47,114 @@ import wasi_pthread
4347
#error("Unsupported runtime")
4448
#endif
4549

46-
/// A threading lock based on `libpthread` instead of `libdispatch`.
50+
51+
/// A reader/writer threading lock based on `libpthread` instead of `libdispatch`.
4752
///
48-
/// This object provides a lock on top of a single `pthread_mutex_t`. This kind
53+
/// This object provides a lock on top of a single `pthread_rwlock_t`. This kind
4954
/// 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)
55+
/// one used by NIO. On Windows, the lock is based on the substantially similar
56+
/// `SRWLOCK` type.
57+
internal final class ReadWriteLock: @unchecked Sendable {
58+
#if canImport(WASILibc)
59+
// WASILibc is single threaded, provides no locks
60+
#elseif os(Windows)
61+
fileprivate let rwlock: UnsafeMutablePointer<SRWLOCK> =
62+
UnsafeMutablePointer.allocate(capacity: 1)
63+
fileprivate var shared: Bool = true
64+
#else
65+
fileprivate let rwlock: UnsafeMutablePointer<pthread_rwlock_t> =
66+
UnsafeMutablePointer.allocate(capacity: 1)
67+
#endif
5468

5569
/// Create a new lock.
5670
public init() {
71+
#if canImport(WASILibc)
72+
// WASILibc is single threaded, provides no locks
73+
#elseif os(Windows)
74+
InitializeSRWLock(self.rwlock)
75+
#else
5776
let err = pthread_rwlock_init(self.rwlock, nil)
58-
precondition(err == 0, "pthread_rwlock_init failed with error \(err)")
77+
precondition(err == 0, "\(#function) failed in pthread_rwlock with error \(err)")
78+
#endif
5979
}
6080

6181
deinit {
82+
#if canImport(WASILibc)
83+
// WASILibc is single threaded, provides no locks
84+
#elseif os(Windows)
85+
// SRWLOCK does not need to be free'd
86+
self.rwlock.deallocate()
87+
#else
6288
let err = pthread_rwlock_destroy(self.rwlock)
63-
precondition(err == 0, "pthread_rwlock_destroy failed with error \(err)")
89+
precondition(err == 0, "\(#function) failed in pthread_rwlock with error \(err)")
6490
self.rwlock.deallocate()
91+
#endif
6592
}
6693

6794
/// Acquire a reader lock.
6895
///
69-
/// Whenever possible, consider using `withLock` instead of this method and
70-
/// `unlock`, to simplify lock handling.
71-
public func lockRead() {
96+
/// Whenever possible, consider using `withReaderLock` instead of this
97+
/// method and `unlock`, to simplify lock handling.
98+
fileprivate func lockRead() {
99+
#if canImport(WASILibc)
100+
// WASILibc is single threaded, provides no locks
101+
#elseif os(Windows)
102+
AcquireSRWLockShared(self.rwlock)
103+
self.shared = true
104+
#else
72105
let err = pthread_rwlock_rdlock(self.rwlock)
73-
precondition(err == 0, "pthread_rwlock_rdlock failed with error \(err)")
106+
precondition(err == 0, "\(#function) failed in pthread_rwlock with error \(err)")
107+
#endif
74108
}
75109

76110
/// Acquire a writer lock.
77111
///
78-
/// Whenever possible, consider using `withLock` instead of this method and
79-
/// `unlock`, to simplify lock handling.
80-
public func lockWrite() {
112+
/// Whenever possible, consider using `withWriterLock` instead of this
113+
/// method and `unlock`, to simplify lock handling.
114+
fileprivate func lockWrite() {
115+
#if canImport(WASILibc)
116+
// WASILibc is single threaded, provides no locks
117+
#elseif os(Windows)
118+
AcquireSRWLockExclusive(self.rwlock)
119+
self.shared = false
120+
#else
81121
let err = pthread_rwlock_wrlock(self.rwlock)
82-
precondition(err == 0, "pthread_rwlock_wrlock failed with error \(err)")
122+
precondition(err == 0, "\(#function) failed in pthread_rwlock with error \(err)")
123+
#endif
83124
}
84125

85126
/// Release the lock.
86127
///
87-
/// Whenever possible, consider using `withLock` instead of this method and
88-
/// `lock`, to simplify lock handling.
89-
public func unlock() {
128+
/// Whenever possible, consider using `withReaderLock` and `withWriterLock`
129+
/// instead of this method and `lockRead` and `lockWrite`, to simplify lock
130+
/// handling.
131+
fileprivate func unlock() {
132+
#if canImport(WASILibc)
133+
// WASILibc is single threaded, provides no locks
134+
#elseif os(Windows)
135+
if self.shared {
136+
ReleaseSRWLockShared(self.rwlock)
137+
} else {
138+
ReleaseSRWLockExclusive(self.rwlock)
139+
}
140+
#else
90141
let err = pthread_rwlock_unlock(self.rwlock)
91-
precondition(err == 0, "pthread_rwlock_unlock failed with error \(err)")
142+
precondition(err == 0, "\(#function) failed in pthread_rwlock with error \(err)")
143+
#endif
92144
}
93145
}
94146

95147
extension ReadWriteLock {
96148
/// Acquire the reader lock for the duration of the given block.
97149
///
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.
150+
/// This convenience method should be preferred to `lockRead` and `unlock`
151+
/// in most situations, as it ensures that the lock will be released
152+
/// regardless of how `body` exits.
101153
///
102-
/// - Parameter body: The block to execute while holding the lock.
154+
/// - Parameter body: The block to execute while holding the reader lock.
103155
/// - Returns: The value returned by the block.
104156
@inlinable
105-
public func withReaderLock<T>(_ body: () throws -> T) rethrows -> T {
157+
internal func withReaderLock<T>(_ body: () throws -> T) rethrows -> T {
106158
self.lockRead()
107159
defer {
108160
self.unlock()
@@ -112,20 +164,32 @@ extension ReadWriteLock {
112164

113165
/// Acquire the writer lock for the duration of the given block.
114166
///
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.
167+
/// This convenience method should be preferred to `lockWrite` and `unlock`
168+
/// in most situations, as it ensures that the lock will be released
169+
/// regardless of how `body` exits.
118170
///
119-
/// - Parameter body: The block to execute while holding the lock.
171+
/// - Parameter body: The block to execute while holding the writer lock.
120172
/// - Returns: The value returned by the block.
121173
@inlinable
122-
public func withWriterLock<T>(_ body: () throws -> T) rethrows -> T {
174+
internal func withWriterLock<T>(_ body: () throws -> T) rethrows -> T {
123175
self.lockWrite()
124176
defer {
125177
self.unlock()
126178
}
127179
return try body()
128180
}
181+
182+
// specialise Void return (for performance)
183+
@inlinable
184+
internal func withReaderLockVoid(_ body: () throws -> Void) rethrows {
185+
try self.withReaderLock(body)
186+
}
187+
188+
// specialise Void return (for performance)
189+
@inlinable
190+
internal func withWriterLockVoid(_ body: () throws -> Void) rethrows {
191+
try self.withWriterLock(body)
192+
}
129193
}
130194

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

0 commit comments

Comments
 (0)