Skip to content

Commit 5f576bb

Browse files
committed
Implement Lock.swift on Windows
1 parent e2084ae commit 5f576bb

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

Sources/Basic/Lock.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ enum ProcessLockError: Swift.Error {
3636
/// by mutiple instances of a process. The `FileLock` is not thread-safe.
3737
public final class FileLock {
3838
/// File descriptor to the lock file.
39+
#if os(Windows)
40+
private var h: HANDLE?
41+
#else
3942
private var fd: CInt?
43+
#endif
4044

4145
/// Path to the lock file.
4246
private let lockFile: AbsolutePath
@@ -53,6 +57,30 @@ public final class FileLock {
5357
///
5458
/// Note: This method can throw if underlying POSIX methods fail.
5559
public func lock() throws {
60+
#if os(Windows)
61+
if h == nil {
62+
let h = lockFile.pathString.withCString(encodedAs: UTF16.self, {
63+
CreateFileW($0,
64+
UInt32(GENERIC_READ) | UInt32(GENERIC_WRITE),
65+
0,
66+
nil,
67+
DWORD(OPEN_ALWAYS),
68+
DWORD(FILE_ATTRIBUTE_NORMAL),
69+
nil)
70+
})
71+
if h == INVALID_HANDLE_VALUE {
72+
throw FileSystemError(errno: Int32(GetLastError()))
73+
}
74+
self.h = h
75+
}
76+
var overlapped = OVERLAPPED()
77+
overlapped.Offset = 0
78+
overlapped.OffsetHigh = 0
79+
overlapped.hEvent = nil
80+
if FALSE == LockFileEx(h, DWORD(LOCKFILE_EXCLUSIVE_LOCK), 0, DWORD(INT_MAX), DWORD(INT_MAX), &overlapped) {
81+
throw ProcessLockError.unableToAquireLock(errno: Int32(GetLastError()))
82+
}
83+
#else
5684
// Open the lock file.
5785
if fd == nil {
5886
let fd = SPMLibc.open(lockFile.pathString, O_WRONLY | O_CREAT | O_CLOEXEC, 0o666)
@@ -70,17 +98,31 @@ public final class FileLock {
7098
if errno == EINTR { continue }
7199
throw ProcessLockError.unableToAquireLock(errno: errno)
72100
}
101+
#endif
73102
}
74103

75104
/// Unlock the held lock.
76105
public func unlock() {
106+
#if os(Windows)
107+
var overlapped = OVERLAPPED()
108+
overlapped.Offset = 0
109+
overlapped.OffsetHigh = 0
110+
overlapped.hEvent = nil
111+
UnlockFileEx(h, 0, DWORD(INT_MAX), DWORD(INT_MAX), &overlapped)
112+
#else
77113
guard let fd = fd else { return }
78114
flock(fd, LOCK_UN)
115+
#endif
79116
}
80117

81118
deinit {
119+
#if os(Windows)
120+
guard let h = h else { return }
121+
CloseHandle(h)
122+
#else
82123
guard let fd = fd else { return }
83124
close(fd)
125+
#endif
84126
}
85127

86128
/// Execute the given block while holding the lock.

Sources/SPMLibc/libc.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
#if os(Linux)
1212
@_exported import Glibc
13+
#elseif os(Windows)
14+
@_exported import MSVCRT
15+
@_exported import WinSDK
1316
#else
1417
@_exported import Darwin.C
1518
#endif

0 commit comments

Comments
 (0)