Skip to content

Commit 4cc9f11

Browse files
authored
Merge branch 'main' into continuation-test-helpers
2 parents e6e4981 + ce04df0 commit 4cc9f11

File tree

1 file changed

+30
-13
lines changed

1 file changed

+30
-13
lines changed

Sources/AsyncHTTPClient/AsyncAwait/Transaction.swift

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,26 +105,43 @@ final class Transaction:
105105

106106
struct BreakTheWriteLoopError: Swift.Error {}
107107

108-
// FIXME: Refactor this to not use `self.state.unsafe`.
109108
private func writeRequestBodyPart(_ part: ByteBuffer) async throws {
110-
self.state.unsafe.lock()
111-
switch self.state.unsafe.withValueAssumingLockIsAcquired({ state in state.writeNextRequestPart() }) {
109+
let action = self.state.withLockedValue { state in
110+
state.writeNextRequestPart()
111+
}
112+
113+
switch action {
112114
case .writeAndContinue(let executor):
113-
self.state.unsafe.unlock()
114115
executor.writeRequestBodyPart(.byteBuffer(part), request: self, promise: nil)
115-
116-
case .writeAndWait(let executor):
116+
case .writeAndWait:
117+
// Holding the lock here *should* be safe but because of a bug in the runtime
118+
// it isn't, so drop the lock, create the continuation and try again.
119+
//
120+
// See https://github.com/swiftlang/swift/issues/85668
117121
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
118-
self.state.unsafe.withValueAssumingLockIsAcquired({ state in
119-
state.waitForRequestBodyDemand(continuation: continuation)
120-
})
121-
self.state.unsafe.unlock()
122+
let action = self.state.withLockedValue { state in
123+
// Check that nothing has changed between dropping and re-acquiring the lock.
124+
let action = state.writeNextRequestPart()
125+
switch action {
126+
case .writeAndContinue, .fail:
127+
()
128+
case .writeAndWait:
129+
state.waitForRequestBodyDemand(continuation: continuation)
130+
}
131+
return action
132+
}
122133

123-
executor.writeRequestBodyPart(.byteBuffer(part), request: self, promise: nil)
134+
switch action {
135+
case .writeAndContinue(let executor):
136+
executor.writeRequestBodyPart(.byteBuffer(part), request: self, promise: nil)
137+
continuation.resume()
138+
case .writeAndWait(let executor):
139+
executor.writeRequestBodyPart(.byteBuffer(part), request: self, promise: nil)
140+
case .fail:
141+
continuation.resume(throwing: BreakTheWriteLoopError())
142+
}
124143
}
125-
126144
case .fail:
127-
self.state.unsafe.unlock()
128145
throw BreakTheWriteLoopError()
129146
}
130147
}

0 commit comments

Comments
 (0)