Skip to content

Commit

Permalink
Merge pull request #1744 from ahoppen/6.0/atomic-instead-of-queue
Browse files Browse the repository at this point in the history
[6.0] Use an `AtomicInt32` to count `pendingUnitCount` instead of using `AsyncQueue`
  • Loading branch information
ahoppen authored Oct 9, 2024
2 parents 8b3275e + 44a095c commit 8f9aaed
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 29 deletions.
26 changes: 26 additions & 0 deletions Sources/CAtomics/include/CAtomics.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,30 @@ static inline void atomic_uint32_destroy(CAtomicUInt32 *_Nonnull atomic) {
free(atomic);
}

typedef struct {
_Atomic(int32_t) value;
} CAtomicInt32;

static inline CAtomicInt32 *_Nonnull atomic_int32_create(int32_t initialValue) {
CAtomicInt32 *atomic = malloc(sizeof(CAtomicInt32));
atomic->value = initialValue;
return atomic;
}

static inline int32_t atomic_int32_get(CAtomicInt32 *_Nonnull atomic) {
return atomic->value;
}

static inline void atomic_int32_set(CAtomicInt32 *_Nonnull atomic, int32_t newValue) {
atomic->value = newValue;
}

static inline int32_t atomic_int32_fetch_and_increment(CAtomicInt32 *_Nonnull atomic) {
return atomic->value++;
}

static inline void atomic_int32_destroy(CAtomicInt32 *_Nonnull atomic) {
free(atomic);
}

#endif // SOURCEKITLSP_CATOMICS_H
25 changes: 25 additions & 0 deletions Sources/SKSupport/Atomics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,28 @@ public final class AtomicUInt32: Sendable {
return atomic_uint32_fetch_and_increment(atomic)
}
}

public final class AtomicInt32: Sendable {
private nonisolated(unsafe) let atomic: UnsafeMutablePointer<CAtomicInt32>

public init(initialValue: Int32) {
self.atomic = atomic_int32_create(initialValue)
}

public var value: Int32 {
get {
atomic_int32_get(atomic)
}
set {
atomic_int32_set(atomic, newValue)
}
}

deinit {
atomic_int32_destroy(atomic)
}

public func fetchAndIncrement() -> Int32 {
return atomic_int32_fetch_and_increment(atomic)
}
}
46 changes: 17 additions & 29 deletions Sources/SourceKitLSP/SourceKitIndexDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,60 +19,48 @@ import SwiftExtensions

/// `IndexDelegate` for the SourceKit workspace.
actor SourceKitIndexDelegate: IndexDelegate {

let queue = AsyncQueue<Serial>()

/// Registered `MainFilesDelegate`s to notify when main files change.
var mainFilesChangedCallbacks: [@Sendable () async -> Void] = []

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

public init() {}

nonisolated public func processingAddedPending(_ count: Int) {
queue.async {
await self.addPending(count)
}
}

private func addPending(_ count: Int) {
pendingUnitCount += count
pendingUnitCount.value += Int32(count)
}

nonisolated public func processingCompleted(_ count: Int) {
queue.async {
await self.processCompleted(count)
}
}

private func processCompleted(_ count: Int) {
pendingUnitCount -= count
if pendingUnitCount == 0 {
indexChanged()
pendingUnitCount.value -= Int32(count)
if pendingUnitCount.value == 0 {
Task {
await indexChanged()
}
}

if pendingUnitCount < 0 {
assertionFailure("pendingUnitCount = \(pendingUnitCount) < 0")
pendingUnitCount = 0
indexChanged()
if pendingUnitCount.value < 0 {
// Technically this is not data race safe because `pendingUnitCount` might change between the check and us setting
// it to 0. But then, this should never happen anyway, so it's fine.
logger.fault("pendingUnitCount dropped below zero: \(self.pendingUnitCount.value)")
pendingUnitCount.value = 0
Task {
await indexChanged()
}
}
}

private func indexChanged() {
private func indexChanged() async {
logger.debug("IndexStoreDB changed")
for callback in mainFilesChangedCallbacks {
queue.async {
await callback()
}
await callback()
}
}

/// Register a delegate to receive notifications when main files change.
public func addMainFileChangedCallback(_ callback: @escaping @Sendable () async -> Void) {
mainFilesChangedCallbacks.append(callback)
}

}

0 comments on commit 8f9aaed

Please sign in to comment.