Skip to content

Commit 8a43fcb

Browse files
committed
Linux build (#37)
Import Locking.swift from upstream AsyncAlgorithms to enable non-Darwin builds
1 parent 3442d3d commit 8a43fcb

File tree

2 files changed

+152
-45
lines changed

2 files changed

+152
-45
lines changed

Sources/Supporting/Locking.swift

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Async Algorithms open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
#if canImport(Darwin)
13+
@_implementationOnly import Darwin
14+
#elseif canImport(Glibc)
15+
@_implementationOnly import Glibc
16+
#elseif canImport(WinSDK)
17+
@_implementationOnly import WinSDK
18+
#endif
19+
20+
internal struct Lock {
21+
#if canImport(Darwin)
22+
typealias Primitive = os_unfair_lock
23+
#elseif canImport(Glibc)
24+
typealias Primitive = pthread_mutex_t
25+
#elseif canImport(WinSDK)
26+
typealias Primitive = SRWLOCK
27+
#endif
28+
29+
typealias PlatformLock = UnsafeMutablePointer<Primitive>
30+
let platformLock: PlatformLock
31+
32+
private init(_ platformLock: PlatformLock) {
33+
self.platformLock = platformLock
34+
}
35+
36+
fileprivate static func initialize(_ platformLock: PlatformLock) {
37+
#if canImport(Darwin)
38+
platformLock.initialize(to: os_unfair_lock())
39+
#elseif canImport(Glibc)
40+
let result = pthread_mutex_init(platformLock, nil)
41+
precondition(result == 0, "pthread_mutex_init failed")
42+
#elseif canImport(WinSDK)
43+
InitializeSRWLock(platformLock)
44+
#endif
45+
}
46+
47+
fileprivate static func deinitialize(_ platformLock: PlatformLock) {
48+
#if canImport(Glibc)
49+
let result = pthread_mutex_destroy(platformLock)
50+
precondition(result == 0, "pthread_mutex_destroy failed")
51+
#endif
52+
platformLock.deinitialize(count: 1)
53+
}
54+
55+
fileprivate static func lock(_ platformLock: PlatformLock) {
56+
#if canImport(Darwin)
57+
os_unfair_lock_lock(platformLock)
58+
#elseif canImport(Glibc)
59+
pthread_mutex_lock(platformLock)
60+
#elseif canImport(WinSDK)
61+
AcquireSRWLockExclusive(platformLock)
62+
#endif
63+
}
64+
65+
fileprivate static func unlock(_ platformLock: PlatformLock) {
66+
#if canImport(Darwin)
67+
os_unfair_lock_unlock(platformLock)
68+
#elseif canImport(Glibc)
69+
let result = pthread_mutex_unlock(platformLock)
70+
precondition(result == 0, "pthread_mutex_unlock failed")
71+
#elseif canImport(WinSDK)
72+
ReleaseSRWLockExclusive(platformLock)
73+
#endif
74+
}
75+
76+
static func allocate() -> Lock {
77+
let platformLock = PlatformLock.allocate(capacity: 1)
78+
initialize(platformLock)
79+
return Lock(platformLock)
80+
}
81+
82+
func deinitialize() {
83+
Lock.deinitialize(platformLock)
84+
}
85+
86+
func lock() {
87+
Lock.lock(platformLock)
88+
}
89+
90+
func unlock() {
91+
Lock.unlock(platformLock)
92+
}
93+
94+
/// Acquire the lock for the duration of the given block.
95+
///
96+
/// This convenience method should be preferred to `lock` and `unlock` in
97+
/// most situations, as it ensures that the lock will be released regardless
98+
/// of how `body` exits.
99+
///
100+
/// - Parameter body: The block to execute while holding the lock.
101+
/// - Returns: The value returned by the block.
102+
func withLock<T>(_ body: () throws -> T) rethrows -> T {
103+
self.lock()
104+
defer {
105+
self.unlock()
106+
}
107+
return try body()
108+
}
109+
110+
// specialise Void return (for performance)
111+
func withLockVoid(_ body: () throws -> Void) rethrows -> Void {
112+
try self.withLock(body)
113+
}
114+
}
115+
116+
struct ManagedCriticalState<State> {
117+
private final class LockedBuffer: ManagedBuffer<State, Lock.Primitive> {
118+
deinit {
119+
withUnsafeMutablePointerToElements { Lock.deinitialize($0) }
120+
}
121+
}
122+
123+
private let buffer: ManagedBuffer<State, Lock.Primitive>
124+
125+
init(_ initial: State) {
126+
buffer = LockedBuffer.create(minimumCapacity: 1) { buffer in
127+
buffer.withUnsafeMutablePointerToElements { Lock.initialize($0) }
128+
return initial
129+
}
130+
}
131+
132+
@discardableResult
133+
func withCriticalRegion<R>(_ critical: (inout State) throws -> R) rethrows -> R {
134+
try buffer.withUnsafeMutablePointers { header, lock in
135+
Lock.lock(lock)
136+
defer { Lock.unlock(lock) }
137+
return try critical(&header.pointee)
138+
}
139+
}
140+
141+
func apply(criticalState newState: State) {
142+
self.withCriticalRegion { actual in
143+
actual = newState
144+
}
145+
}
146+
147+
var criticalState: State {
148+
self.withCriticalRegion { $0 }
149+
}
150+
}
151+
152+
extension ManagedCriticalState: @unchecked Sendable where State: Sendable { }

Sources/Supporting/ManagedCriticalState.swift

Lines changed: 0 additions & 45 deletions
This file was deleted.

0 commit comments

Comments
 (0)