Skip to content

Commit a1a778c

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

File tree

2 files changed

+154
-45
lines changed

2 files changed

+154
-45
lines changed

Sources/Supporting/Locking.swift

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
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+
import Darwin
14+
#elseif canImport(Glibc)
15+
import Glibc
16+
#elseif canImport(WinSDK)
17+
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+
#else
28+
typealias Primitive = Int
29+
#endif
30+
31+
typealias PlatformLock = UnsafeMutablePointer<Primitive>
32+
let platformLock: PlatformLock
33+
34+
private init(_ platformLock: PlatformLock) {
35+
self.platformLock = platformLock
36+
}
37+
38+
fileprivate static func initialize(_ platformLock: PlatformLock) {
39+
#if canImport(Darwin)
40+
platformLock.initialize(to: os_unfair_lock())
41+
#elseif canImport(Glibc)
42+
let result = pthread_mutex_init(platformLock, nil)
43+
precondition(result == 0, "pthread_mutex_init failed")
44+
#elseif canImport(WinSDK)
45+
InitializeSRWLock(platformLock)
46+
#endif
47+
}
48+
49+
fileprivate static func deinitialize(_ platformLock: PlatformLock) {
50+
#if canImport(Glibc)
51+
let result = pthread_mutex_destroy(platformLock)
52+
precondition(result == 0, "pthread_mutex_destroy failed")
53+
#endif
54+
platformLock.deinitialize(count: 1)
55+
}
56+
57+
fileprivate static func lock(_ platformLock: PlatformLock) {
58+
#if canImport(Darwin)
59+
os_unfair_lock_lock(platformLock)
60+
#elseif canImport(Glibc)
61+
pthread_mutex_lock(platformLock)
62+
#elseif canImport(WinSDK)
63+
AcquireSRWLockExclusive(platformLock)
64+
#endif
65+
}
66+
67+
fileprivate static func unlock(_ platformLock: PlatformLock) {
68+
#if canImport(Darwin)
69+
os_unfair_lock_unlock(platformLock)
70+
#elseif canImport(Glibc)
71+
let result = pthread_mutex_unlock(platformLock)
72+
precondition(result == 0, "pthread_mutex_unlock failed")
73+
#elseif canImport(WinSDK)
74+
ReleaseSRWLockExclusive(platformLock)
75+
#endif
76+
}
77+
78+
static func allocate() -> Lock {
79+
let platformLock = PlatformLock.allocate(capacity: 1)
80+
initialize(platformLock)
81+
return Lock(platformLock)
82+
}
83+
84+
func deinitialize() {
85+
Lock.deinitialize(platformLock)
86+
}
87+
88+
func lock() {
89+
Lock.lock(platformLock)
90+
}
91+
92+
func unlock() {
93+
Lock.unlock(platformLock)
94+
}
95+
96+
/// Acquire the lock for the duration of the given block.
97+
///
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.
101+
///
102+
/// - Parameter body: The block to execute while holding the lock.
103+
/// - Returns: The value returned by the block.
104+
func withLock<T>(_ body: () throws -> T) rethrows -> T {
105+
self.lock()
106+
defer {
107+
self.unlock()
108+
}
109+
return try body()
110+
}
111+
112+
// specialise Void return (for performance)
113+
func withLockVoid(_ body: () throws -> Void) rethrows -> Void {
114+
try self.withLock(body)
115+
}
116+
}
117+
118+
struct ManagedCriticalState<State> {
119+
private final class LockedBuffer: ManagedBuffer<State, Lock.Primitive> {
120+
deinit {
121+
withUnsafeMutablePointerToElements { Lock.deinitialize($0) }
122+
}
123+
}
124+
125+
private let buffer: ManagedBuffer<State, Lock.Primitive>
126+
127+
init(_ initial: State) {
128+
buffer = LockedBuffer.create(minimumCapacity: 1) { buffer in
129+
buffer.withUnsafeMutablePointerToElements { Lock.initialize($0) }
130+
return initial
131+
}
132+
}
133+
134+
@discardableResult
135+
func withCriticalRegion<R>(_ critical: (inout State) throws -> R) rethrows -> R {
136+
try buffer.withUnsafeMutablePointers { header, lock in
137+
Lock.lock(lock)
138+
defer { Lock.unlock(lock) }
139+
return try critical(&header.pointee)
140+
}
141+
}
142+
143+
func apply(criticalState newState: State) {
144+
self.withCriticalRegion { actual in
145+
actual = newState
146+
}
147+
}
148+
149+
var criticalState: State {
150+
self.withCriticalRegion { $0 }
151+
}
152+
}
153+
154+
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)