@@ -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