Skip to content

Commit 2cc7815

Browse files
committed
feat: add OnceFlag class for thread-safe single execution of closures
1 parent b3e28fd commit 2cc7815

File tree

1 file changed

+26
-4
lines changed

1 file changed

+26
-4
lines changed

Sources/ast-grep-mcp-swift/ast_grep_mcp_swift.swift

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ final class OutputBuffer: @unchecked Sendable {
9494
}
9595
}
9696

97+
/// Thread-safe helper to ensure a completion handler is called exactly once.
98+
final class OnceFlag: @unchecked Sendable {
99+
private let lock = NSLock()
100+
private var completed = false
101+
102+
/// Executes the given closure only on the first call; subsequent calls are no-ops.
103+
func callOnce(_ action: () -> Void) {
104+
lock.withLock {
105+
guard !completed else { return }
106+
completed = true
107+
action()
108+
}
109+
}
110+
}
111+
97112
private func runCommand(_ args: [String], input: String? = nil) throws -> CommandResult {
98113
let process = Process()
99114
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
@@ -117,12 +132,17 @@ private func runCommand(_ args: [String], input: String? = nil) throws -> Comman
117132
let stderrBuffer = OutputBuffer()
118133

119134
let group = DispatchGroup()
135+
let stdoutOnce = OnceFlag()
136+
let stderrOnce = OnceFlag()
137+
120138
group.enter()
121139
stdoutPipe.fileHandleForReading.readabilityHandler = { handle in
122140
let data = handle.availableData
123141
if data.isEmpty {
124-
handle.readabilityHandler = nil
125-
group.leave()
142+
stdoutOnce.callOnce {
143+
handle.readabilityHandler = nil
144+
group.leave()
145+
}
126146
return
127147
}
128148
stdoutBuffer.append(data)
@@ -132,8 +152,10 @@ private func runCommand(_ args: [String], input: String? = nil) throws -> Comman
132152
stderrPipe.fileHandleForReading.readabilityHandler = { handle in
133153
let data = handle.availableData
134154
if data.isEmpty {
135-
handle.readabilityHandler = nil
136-
group.leave()
155+
stderrOnce.callOnce {
156+
handle.readabilityHandler = nil
157+
group.leave()
158+
}
137159
return
138160
}
139161
stderrBuffer.append(data)

0 commit comments

Comments
 (0)