diff --git a/.gitignore b/.gitignore index 231b23df..e5640f6c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ DerivedData .SourceKitten/ docs/ + +.*.sw? diff --git a/Sources/Logging/Locks.swift b/Sources/Logging/Locks.swift index 69918174..86f4f1bd 100644 --- a/Sources/Logging/Locks.swift +++ b/Sources/Logging/Locks.swift @@ -28,6 +28,8 @@ #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) import Darwin +#elseif os(Windows) +import WinSDK #else import Glibc #endif @@ -38,17 +40,31 @@ import Glibc /// of lock is safe to use with `libpthread`-based threading models, such as the /// one used by NIO. internal final class Lock { - fileprivate let mutex: UnsafeMutablePointer = UnsafeMutablePointer.allocate(capacity: 1) + #if os(Windows) + fileprivate let mutex: UnsafeMutablePointer = + UnsafeMutablePointer.allocate(capacity: 1) + #else + fileprivate let mutex: UnsafeMutablePointer = + UnsafeMutablePointer.allocate(capacity: 1) + #endif /// Create a new lock. public init() { + #if os(Windows) + InitializeSRWLock(self.mutex) + #else let err = pthread_mutex_init(self.mutex, nil) precondition(err == 0) + #endif } deinit { + #if os(Windows) + // SRWLOCK does not need to be free'd + #else let err = pthread_mutex_destroy(self.mutex) precondition(err == 0) + #endif self.mutex.deallocate() } @@ -57,8 +73,12 @@ internal final class Lock { /// Whenever possible, consider using `withLock` instead of this method and /// `unlock`, to simplify lock handling. public func lock() { + #if os(Windows) + AcquireSRWLockExclusive(self.mutex) + #else let err = pthread_mutex_lock(self.mutex) precondition(err == 0) + #endif } /// Release the lock. @@ -66,8 +86,12 @@ internal final class Lock { /// Whenever possible, consider using `withLock` instead of this method and /// `lock`, to simplify lock handling. public func unlock() { + #if os(Windows) + ReleaseSRWLockExclusive(self.mutex) + #else let err = pthread_mutex_unlock(self.mutex) precondition(err == 0) + #endif } } @@ -102,17 +126,32 @@ extension Lock { /// of lock is safe to use with `libpthread`-based threading models, such as the /// one used by NIO. internal final class ReadWriteLock { - fileprivate let rwlock: UnsafeMutablePointer = UnsafeMutablePointer.allocate(capacity: 1) + #if os(Windows) + fileprivate let rwlock: UnsafeMutablePointer = + UnsafeMutablePointer.allocate(capacity: 1) + fileprivate var shared: Bool = true + #else + fileprivate let rwlock: UnsafeMutablePointer = + UnsafeMutablePointer.allocate(capacity: 1) + #endif /// Create a new lock. public init() { + #if os(Windows) + InitializeSRWLock(self.rwlock) + #else let err = pthread_rwlock_init(self.rwlock, nil) precondition(err == 0) + #endif } deinit { + #if os(Windows) + // SRWLOCK does not need to be free'd + #else let err = pthread_rwlock_destroy(self.rwlock) precondition(err == 0) + #endif self.rwlock.deallocate() } @@ -121,8 +160,13 @@ internal final class ReadWriteLock { /// Whenever possible, consider using `withLock` instead of this method and /// `unlock`, to simplify lock handling. public func lockRead() { + #if os(Windows) + AcquireSRWLockShared(self.rwlock) + self.shared = true + #else let err = pthread_rwlock_rdlock(self.rwlock) precondition(err == 0) + #endif } /// Acquire a writer lock. @@ -130,8 +174,13 @@ internal final class ReadWriteLock { /// Whenever possible, consider using `withLock` instead of this method and /// `unlock`, to simplify lock handling. public func lockWrite() { + #if os(Windows) + AcquireSRWLockExclusive(self.rwlock) + self.shared = true + #else let err = pthread_rwlock_wrlock(self.rwlock) precondition(err == 0) + #endif } /// Release the lock. @@ -139,8 +188,16 @@ internal final class ReadWriteLock { /// Whenever possible, consider using `withLock` instead of this method and /// `lock`, to simplify lock handling. public func unlock() { + #if os(Windows) + if self.shared { + ReleaseSRWLockShared(self.rwlock) + } else { + ReleaseSRWLockExclusive(self.rwlock) + } + #else let err = pthread_rwlock_unlock(self.rwlock) precondition(err == 0) + #endif } } diff --git a/Sources/Logging/Logging.swift b/Sources/Logging/Logging.swift index 7a528d9d..ff77447f 100644 --- a/Sources/Logging/Logging.swift +++ b/Sources/Logging/Logging.swift @@ -14,6 +14,8 @@ #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) import Darwin +#elseif os(Windows) +import MSVCRT #else import Glibc #endif @@ -528,9 +530,17 @@ internal struct StdioOutputStream: TextOutputStream { internal func write(_ string: String) { string.withCString { ptr in + #if os(Windows) + _lock_file(self.file) + #else flockfile(self.file) + #endif defer { + #if os(Windows) + _unlock_file(self.file) + #else funlockfile(self.file) + #endif } _ = fputs(ptr, self.file) if case .always = self.flushMode { @@ -559,6 +569,9 @@ internal struct StdioOutputStream: TextOutputStream { #if os(macOS) || os(tvOS) || os(iOS) || os(watchOS) let systemStderr = Darwin.stderr let systemStdout = Darwin.stdout +#elseif os(Windows) +let systemStderr = MSVCRT.stderr +let systemStdout = MSVCRT.stdout #else let systemStderr = Glibc.stderr! let systemStdout = Glibc.stdout!