Skip to content

Commit 1b5f8a5

Browse files
compnerdweissi
andauthored
Logging: port to Windows (#118)
This adjusts the APIs to enable building swift-log on Windows. Co-authored-by: Johannes Weiss <[email protected]>
1 parent 01ce295 commit 1b5f8a5

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

Sources/Logging/Locks.swift

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828

2929
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
3030
import Darwin
31+
#elseif os(Windows)
32+
import WinSDK
3133
#else
3234
import Glibc
3335
#endif
@@ -38,17 +40,31 @@ import Glibc
3840
/// of lock is safe to use with `libpthread`-based threading models, such as the
3941
/// one used by NIO.
4042
internal final class Lock {
41-
fileprivate let mutex: UnsafeMutablePointer<pthread_mutex_t> = UnsafeMutablePointer.allocate(capacity: 1)
43+
#if os(Windows)
44+
fileprivate let mutex: UnsafeMutablePointer<SRWLOCK> =
45+
UnsafeMutablePointer.allocate(capacity: 1)
46+
#else
47+
fileprivate let mutex: UnsafeMutablePointer<pthread_mutex_t> =
48+
UnsafeMutablePointer.allocate(capacity: 1)
49+
#endif
4250

4351
/// Create a new lock.
4452
public init() {
53+
#if os(Windows)
54+
InitializeSRWLock(self.mutex)
55+
#else
4556
let err = pthread_mutex_init(self.mutex, nil)
4657
precondition(err == 0)
58+
#endif
4759
}
4860

4961
deinit {
62+
#if os(Windows)
63+
// SRWLOCK does not need to be free'd
64+
#else
5065
let err = pthread_mutex_destroy(self.mutex)
5166
precondition(err == 0)
67+
#endif
5268
self.mutex.deallocate()
5369
}
5470

@@ -57,17 +73,25 @@ internal final class Lock {
5773
/// Whenever possible, consider using `withLock` instead of this method and
5874
/// `unlock`, to simplify lock handling.
5975
public func lock() {
76+
#if os(Windows)
77+
AcquireSRWLockExclusive(self.mutex)
78+
#else
6079
let err = pthread_mutex_lock(self.mutex)
6180
precondition(err == 0)
81+
#endif
6282
}
6383

6484
/// Release the lock.
6585
///
6686
/// Whenever possible, consider using `withLock` instead of this method and
6787
/// `lock`, to simplify lock handling.
6888
public func unlock() {
89+
#if os(Windows)
90+
ReleaseSRWLockExclusive(self.mutex)
91+
#else
6992
let err = pthread_mutex_unlock(self.mutex)
7093
precondition(err == 0)
94+
#endif
7195
}
7296
}
7397

@@ -102,17 +126,32 @@ extension Lock {
102126
/// of lock is safe to use with `libpthread`-based threading models, such as the
103127
/// one used by NIO.
104128
internal final class ReadWriteLock {
105-
fileprivate let rwlock: UnsafeMutablePointer<pthread_rwlock_t> = UnsafeMutablePointer.allocate(capacity: 1)
129+
#if os(Windows)
130+
fileprivate let rwlock: UnsafeMutablePointer<SRWLOCK> =
131+
UnsafeMutablePointer.allocate(capacity: 1)
132+
fileprivate var shared: Bool = true
133+
#else
134+
fileprivate let rwlock: UnsafeMutablePointer<pthread_rwlock_t> =
135+
UnsafeMutablePointer.allocate(capacity: 1)
136+
#endif
106137

107138
/// Create a new lock.
108139
public init() {
140+
#if os(Windows)
141+
InitializeSRWLock(self.rwlock)
142+
#else
109143
let err = pthread_rwlock_init(self.rwlock, nil)
110144
precondition(err == 0)
145+
#endif
111146
}
112147

113148
deinit {
149+
#if os(Windows)
150+
// SRWLOCK does not need to be free'd
151+
#else
114152
let err = pthread_rwlock_destroy(self.rwlock)
115153
precondition(err == 0)
154+
#endif
116155
self.rwlock.deallocate()
117156
}
118157

@@ -121,26 +160,44 @@ internal final class ReadWriteLock {
121160
/// Whenever possible, consider using `withLock` instead of this method and
122161
/// `unlock`, to simplify lock handling.
123162
public func lockRead() {
163+
#if os(Windows)
164+
AcquireSRWLockShared(self.rwlock)
165+
self.shared = true
166+
#else
124167
let err = pthread_rwlock_rdlock(self.rwlock)
125168
precondition(err == 0)
169+
#endif
126170
}
127171

128172
/// Acquire a writer lock.
129173
///
130174
/// Whenever possible, consider using `withLock` instead of this method and
131175
/// `unlock`, to simplify lock handling.
132176
public func lockWrite() {
177+
#if os(Windows)
178+
AcquireSRWLockExclusive(self.rwlock)
179+
self.shared = true
180+
#else
133181
let err = pthread_rwlock_wrlock(self.rwlock)
134182
precondition(err == 0)
183+
#endif
135184
}
136185

137186
/// Release the lock.
138187
///
139188
/// Whenever possible, consider using `withLock` instead of this method and
140189
/// `lock`, to simplify lock handling.
141190
public func unlock() {
191+
#if os(Windows)
192+
if self.shared {
193+
ReleaseSRWLockShared(self.rwlock)
194+
} else {
195+
ReleaseSRWLockExclusive(self.rwlock)
196+
}
197+
#else
142198
let err = pthread_rwlock_unlock(self.rwlock)
143199
precondition(err == 0)
200+
#endif
144201
}
145202
}
146203

Sources/Logging/Logging.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
1616
import Darwin
17+
#elseif os(Windows)
18+
import MSVCRT
1719
#else
1820
import Glibc
1921
#endif
@@ -528,9 +530,17 @@ internal struct StdioOutputStream: TextOutputStream {
528530

529531
internal func write(_ string: String) {
530532
string.withCString { ptr in
533+
#if os(Windows)
534+
_lock_file(self.file)
535+
#else
531536
flockfile(self.file)
537+
#endif
532538
defer {
539+
#if os(Windows)
540+
_unlock_file(self.file)
541+
#else
533542
funlockfile(self.file)
543+
#endif
534544
}
535545
_ = fputs(ptr, self.file)
536546
if case .always = self.flushMode {
@@ -559,6 +569,9 @@ internal struct StdioOutputStream: TextOutputStream {
559569
#if os(macOS) || os(tvOS) || os(iOS) || os(watchOS)
560570
let systemStderr = Darwin.stderr
561571
let systemStdout = Darwin.stdout
572+
#elseif os(Windows)
573+
let systemStderr = MSVCRT.stderr
574+
let systemStdout = MSVCRT.stdout
562575
#else
563576
let systemStderr = Glibc.stderr!
564577
let systemStdout = Glibc.stdout!

0 commit comments

Comments
 (0)