Skip to content

Commit 2b4f602

Browse files
authored
Add a primitive storage for managing critical state and platform abstracted locking (#7)
1 parent 361c792 commit 2b4f602

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
pthread_mutex_init(platformLock, nil)
41+
#elseif canImport(WinSDK)
42+
InitializeSRWLock(platformLock)
43+
#endif
44+
}
45+
46+
fileprivate static func deinitialize(_ platformLock: PlatformLock) {
47+
#if canImport(Glibc)
48+
pthread_mutex_destroy(platformLock)
49+
#endif
50+
platformLock.deinitialize(count: 1)
51+
}
52+
53+
fileprivate static func lock(_ platformLock: PlatformLock) {
54+
#if canImport(Darwin)
55+
os_unfair_lock_lock(platformLock)
56+
#elseif canImport(Glibc)
57+
pthread_mutex_lock(platformLock)
58+
#elseif canImport(WinSDK)
59+
AcquireSRWLockExclusive(platformLock)
60+
#endif
61+
}
62+
63+
fileprivate static func unlock(_ platformLock: PlatformLock) {
64+
#if canImport(Darwin)
65+
os_unfair_lock_unlock(platformLock)
66+
#elseif canImport(Glibc)
67+
pthread_mutex_unlock(platformLock)
68+
#elseif canImport(WinSDK)
69+
ReleaseSRWLockExclusive(platformLock)
70+
#endif
71+
}
72+
73+
static func allocate() -> Lock {
74+
let platformLock = PlatformLock.allocate(capacity: 1)
75+
initialize(platformLock)
76+
return Lock(platformLock)
77+
}
78+
79+
func deinitialize() {
80+
Lock.deinitialize(platformLock)
81+
}
82+
83+
func lock() {
84+
Lock.lock(platformLock)
85+
}
86+
87+
func unlock() {
88+
Lock.unlock(platformLock)
89+
}
90+
}
91+
92+
struct ManagedCriticalState<State> {
93+
private final class LockedBuffer: ManagedBuffer<State, Lock.Primitive> {
94+
deinit {
95+
withUnsafeMutablePointerToElements { Lock.deinitialize($0) }
96+
}
97+
}
98+
99+
private let buffer: ManagedBuffer<State, Lock.Primitive>
100+
101+
init(_ initial: State) {
102+
buffer = LockedBuffer.create(minimumCapacity: 1) { buffer in
103+
buffer.withUnsafeMutablePointerToElements { Lock.initialize($0) }
104+
return initial
105+
}
106+
}
107+
108+
func withCriticalRegion<R>(_ critical: (inout State) throws -> R) rethrows -> R {
109+
try buffer.withUnsafeMutablePointers { header, lock in
110+
Lock.lock(lock)
111+
defer { Lock.unlock(lock) }
112+
return try critical(&header.pointee)
113+
}
114+
}
115+
}
116+
117+
extension ManagedCriticalState: @unchecked Sendable where State: Sendable { }

0 commit comments

Comments
 (0)