Skip to content

Commit 9b4a9b0

Browse files
authored
Merge pull request #1720 from ahoppen/atomic-instead-of-queue
Use an `AtomicInt32` to count `pendingUnitCount` instead of using `AsyncQueue`
2 parents b91f72f + 2c9436b commit 9b4a9b0

File tree

3 files changed

+68
-29
lines changed

3 files changed

+68
-29
lines changed

Sources/CAtomics/include/CAtomics.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,30 @@ static inline void atomic_uint32_destroy(CAtomicUInt32 *_Nonnull atomic) {
4444
free(atomic);
4545
}
4646

47+
typedef struct {
48+
_Atomic(int32_t) value;
49+
} CAtomicInt32;
50+
51+
static inline CAtomicInt32 *_Nonnull atomic_int32_create(int32_t initialValue) {
52+
CAtomicInt32 *atomic = malloc(sizeof(CAtomicInt32));
53+
atomic->value = initialValue;
54+
return atomic;
55+
}
56+
57+
static inline int32_t atomic_int32_get(CAtomicInt32 *_Nonnull atomic) {
58+
return atomic->value;
59+
}
60+
61+
static inline void atomic_int32_set(CAtomicInt32 *_Nonnull atomic, int32_t newValue) {
62+
atomic->value = newValue;
63+
}
64+
65+
static inline int32_t atomic_int32_fetch_and_increment(CAtomicInt32 *_Nonnull atomic) {
66+
return atomic->value++;
67+
}
68+
69+
static inline void atomic_int32_destroy(CAtomicInt32 *_Nonnull atomic) {
70+
free(atomic);
71+
}
72+
4773
#endif // SOURCEKITLSP_CATOMICS_H

Sources/SourceKitLSP/SourceKitIndexDelegate.swift

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,60 +18,48 @@ import SwiftExtensions
1818

1919
/// `IndexDelegate` for the SourceKit workspace.
2020
actor SourceKitIndexDelegate: IndexDelegate {
21-
22-
let queue = AsyncQueue<Serial>()
23-
2421
/// Registered `MainFilesDelegate`s to notify when main files change.
2522
var mainFilesChangedCallbacks: [@Sendable () async -> Void] = []
2623

2724
/// The count of pending unit events. Whenever this transitions to 0, it represents a time where
2825
/// the index finished processing known events. Of course, that may have already changed by the
2926
/// time we are notified.
30-
var pendingUnitCount: Int = 0
27+
let pendingUnitCount = AtomicInt32(initialValue: 0)
3128

3229
package init() {}
3330

3431
nonisolated package func processingAddedPending(_ count: Int) {
35-
queue.async {
36-
await self.addPending(count)
37-
}
38-
}
39-
40-
private func addPending(_ count: Int) {
41-
pendingUnitCount += count
32+
pendingUnitCount.value += Int32(count)
4233
}
4334

4435
nonisolated package func processingCompleted(_ count: Int) {
45-
queue.async {
46-
await self.processCompleted(count)
47-
}
48-
}
49-
50-
private func processCompleted(_ count: Int) {
51-
pendingUnitCount -= count
52-
if pendingUnitCount == 0 {
53-
indexChanged()
36+
pendingUnitCount.value -= Int32(count)
37+
if pendingUnitCount.value == 0 {
38+
Task {
39+
await indexChanged()
40+
}
5441
}
5542

56-
if pendingUnitCount < 0 {
57-
assertionFailure("pendingUnitCount = \(pendingUnitCount) < 0")
58-
pendingUnitCount = 0
59-
indexChanged()
43+
if pendingUnitCount.value < 0 {
44+
// Technically this is not data race safe because `pendingUnitCount` might change between the check and us setting
45+
// it to 0. But then, this should never happen anyway, so it's fine.
46+
logger.fault("pendingUnitCount dropped below zero: \(self.pendingUnitCount.value)")
47+
pendingUnitCount.value = 0
48+
Task {
49+
await indexChanged()
50+
}
6051
}
6152
}
6253

63-
private func indexChanged() {
54+
private func indexChanged() async {
6455
logger.debug("IndexStoreDB changed")
6556
for callback in mainFilesChangedCallbacks {
66-
queue.async {
67-
await callback()
68-
}
57+
await callback()
6958
}
7059
}
7160

7261
/// Register a delegate to receive notifications when main files change.
7362
package func addMainFileChangedCallback(_ callback: @escaping @Sendable () async -> Void) {
7463
mainFilesChangedCallbacks.append(callback)
7564
}
76-
7765
}

Sources/SwiftExtensions/Atomics.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,28 @@ package final class AtomicUInt32: Sendable {
8282
return atomic_uint32_fetch_and_increment(atomic)
8383
}
8484
}
85+
86+
package final class AtomicInt32: Sendable {
87+
private nonisolated(unsafe) let atomic: UnsafeMutablePointer<CAtomicInt32>
88+
89+
package init(initialValue: Int32) {
90+
self.atomic = atomic_int32_create(initialValue)
91+
}
92+
93+
package var value: Int32 {
94+
get {
95+
atomic_int32_get(atomic)
96+
}
97+
set {
98+
atomic_int32_set(atomic, newValue)
99+
}
100+
}
101+
102+
deinit {
103+
atomic_int32_destroy(atomic)
104+
}
105+
106+
package func fetchAndIncrement() -> Int32 {
107+
return atomic_int32_fetch_and_increment(atomic)
108+
}
109+
}

0 commit comments

Comments
 (0)