Skip to content

Commit 90aa7b5

Browse files
committed
Refactor ScopeGuard
Use pthread_mutex_t on Darwin platforms
1 parent 4782397 commit 90aa7b5

File tree

4 files changed

+89
-61
lines changed

4 files changed

+89
-61
lines changed

Sources/SwiftSyntax/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_library(SwiftSyntax STATIC
1010
AbsolutePosition.swift
1111
BumpPtrAllocator.swift
1212
IncrementalParseTransition.swift
13+
PlatformMutex.swift
1314
SourceLength.swift
1415
SourceLocation.swift
1516
SourcePresence.swift
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//===------ PlatformMutex.swift - Platform-specific Mutual Exclusion -----===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 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+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#if canImport(Darwin)
14+
@_implementationOnly import Darwin
15+
#elseif canImport(Glibc)
16+
@_implementationOnly import Glibc
17+
#elseif canImport(WinSDK)
18+
@_implementationOnly import WinSDK
19+
#endif
20+
21+
/// A protocol that platform-specific mutual exclusion primitives should conform to.
22+
struct PlatformMutex {
23+
// FIXME: Use os_unfair_lock when we bump to macOS 12.0 on Darwin
24+
#if canImport(Darwin) || canImport(Glibc)
25+
typealias Primitive = pthread_mutex_t
26+
#elseif canImport(WinSDK)
27+
typealias Primitive = SRWLOCK
28+
#endif
29+
typealias PlatformLock = UnsafeMutablePointer<Primitive>
30+
31+
private let lock: PlatformLock
32+
33+
/// Allocate memory for, and initialize, the mutex in a platform-specific fashion.
34+
///
35+
/// - Parameter allocator: An allocator
36+
init(allocator: BumpPtrAllocator) {
37+
let storage = allocator.allocate(Primitive.self, count: 1).baseAddress!
38+
storage.initialize(to: Primitive())
39+
#if canImport(Darwin) || canImport(Glibc)
40+
pthread_mutex_init(storage, nil)
41+
#elseif canImport(WinSDK)
42+
InitializeSRWLock(storage)
43+
#endif
44+
self.lock = storage
45+
}
46+
47+
/// Deinitialize the memory associated with the mutex.
48+
///
49+
/// - Warning: Do not call `.deallocate()` on any pointers allocated by the
50+
/// `BumpPtrAllocator` here.
51+
func deinitialize() {
52+
#if canImport(Darwin) || canImport(Glibc)
53+
pthread_mutex_destroy(self.lock)
54+
#endif
55+
self.lock.deinitialize(count: 1)
56+
}
57+
58+
/// Invoke the provided block under the protection of the mutex.
59+
func withGuard<T>(body: () throws -> T) rethrows -> T {
60+
Self.lock(self.lock)
61+
defer { Self.unlock(self.lock) }
62+
return try body()
63+
}
64+
}
65+
66+
extension PlatformMutex {
67+
private static func lock(_ platformLock: PlatformLock) {
68+
#if canImport(Darwin) || canImport(Glibc)
69+
pthread_mutex_lock(platformLock)
70+
#elseif canImport(WinSDK)
71+
AcquireSRWLockExclusive(platformLock)
72+
#endif
73+
}
74+
75+
private static func unlock(_ platformLock: PlatformLock) {
76+
#if canImport(Darwin) || canImport(Glibc)
77+
pthread_mutex_unlock(platformLock)
78+
#elseif canImport(WinSDK)
79+
ReleaseSRWLockExclusive(platformLock)
80+
#endif
81+
}
82+
}

Sources/SwiftSyntax/SyntaxArena.swift

Lines changed: 4 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -10,67 +10,13 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#if canImport(Darwin)
14-
import Darwin
15-
16-
struct ScopeGuard {
17-
private let lock: os_unfair_lock_t
18-
init(allocator: BumpPtrAllocator) {
19-
let storage = allocator.allocate(os_unfair_lock.self, count: 1).baseAddress!
20-
storage.initialize(to: os_unfair_lock())
21-
self.lock = os_unfair_lock_t(storage)
22-
}
23-
24-
func deinitialize() {}
25-
26-
func withGuard<T>(body: () throws -> T) rethrows -> T {
27-
os_unfair_lock_lock(lock)
28-
defer { os_unfair_lock_unlock(lock)}
29-
return try body()
30-
}
31-
}
32-
33-
#elseif canImport(Glibc)
34-
import Glibc
35-
36-
struct ScopeGuard {
37-
private let lock: UnsafeMutablePointer<pthread_mutex_t>
38-
init(allocator: BumpPtrAllocator) {
39-
let storage = allocator.allocate(pthread_mutex_t.self, count: 1).baseAddress!
40-
storage.initialize(to: pthread_mutex_t())
41-
pthread_mutex_init(storage, nil)
42-
self.lock = storage
43-
}
44-
func deinitialize() {
45-
pthread_mutex_destroy(self.lock)
46-
}
47-
func withGuard<T>(body: () throws -> T) rethrows -> T {
48-
pthread_mutex_lock(self.lock)
49-
defer { pthread_mutex_unlock(self.lock) }
50-
return try body()
51-
}
52-
}
53-
54-
#else
55-
// FIXME: Support other platforms.
56-
57-
/// Dummy mutex that doesn't actually guard at all.
58-
class ScopeGuard {
59-
init() {}
60-
func deinitialize() {}
61-
func withGuard<T>(body: () throws -> T) rethrows -> T {
62-
return try body()
63-
}
64-
}
65-
#endif
66-
6713
public class SyntaxArena {
6814

6915
@_spi(RawSyntax)
7016
public typealias ParseTriviaFunction = (_ source: SyntaxText, _ position: TriviaPosition) -> [RawTriviaPiece]
7117

7218
/// Thread safe guard.
73-
private let lock: ScopeGuard
19+
private let lock: PlatformMutex
7420
private var singleThreadMode: Bool
7521

7622
/// Bump-pointer allocator for all "intern" methods.
@@ -89,7 +35,7 @@ public class SyntaxArena {
8935
@_spi(RawSyntax)
9036
public init(parseTriviaFunction: @escaping ParseTriviaFunction) {
9137
let allocator = BumpPtrAllocator()
92-
self.lock = ScopeGuard(allocator: allocator)
38+
self.lock = PlatformMutex(allocator: allocator)
9339
self.singleThreadMode = false
9440
self.allocator = allocator
9541
children = []
@@ -99,9 +45,8 @@ public class SyntaxArena {
9945
}
10046

10147
deinit {
102-
// NOTE: We don't make `ScopeGuard` a class and `deinit` in it to
103-
// deinitialize it because the actual lock value is in `allocator`, and we
104-
// want to make sure to deinitialize the lock before destroying the allocator.
48+
// Make sure we give the platform lock a chance to deinitialize any
49+
// memory it used.
10550
lock.deinitialize()
10651
}
10752

Sources/SwiftSyntax/SyntaxText.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#if canImport(Darwin)
14-
import Darwin
14+
@_implementationOnly import Darwin
1515
#elseif canImport(Glibc)
16-
import Glibc
16+
@_implementationOnly import Glibc
1717
#endif
1818

1919
/// Represent a string.

0 commit comments

Comments
 (0)