@@ -19,7 +19,9 @@ import NIOHTTP1
19
19
import NIOSSL
20
20
21
21
@available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
22
- @usableFromInline final class Transaction : @unchecked Sendable {
22
+ @usableFromInline final class Transaction :
23
+ // until NIOLockedValueBox learns `sending` because StateMachine cannot be Sendable
24
+ @unchecked Sendable {
23
25
let logger : Logger
24
26
25
27
let request : HTTPClientRequest . Prepared
@@ -28,8 +30,7 @@ import NIOSSL
28
30
let preferredEventLoop : EventLoop
29
31
let requestOptions : RequestOptions
30
32
31
- private let stateLock = NIOLock ( )
32
- private var state : StateMachine
33
+ private let state : NIOLockedValueBox < StateMachine >
33
34
34
35
init (
35
36
request: HTTPClientRequest . Prepared ,
@@ -44,7 +45,7 @@ import NIOSSL
44
45
self . logger = logger
45
46
self . connectionDeadline = connectionDeadline
46
47
self . preferredEventLoop = preferredEventLoop
47
- self . state = StateMachine ( responseContinuation)
48
+ self . state = NIOLockedValueBox ( StateMachine ( responseContinuation) )
48
49
}
49
50
50
51
func cancel( ) {
@@ -56,8 +57,8 @@ import NIOSSL
56
57
private func writeOnceAndOneTimeOnly( byteBuffer: ByteBuffer ) {
57
58
// This method is synchronously invoked after sending the request head. For this reason we
58
59
// can make a number of assumptions, how the state machine will react.
59
- let writeAction = self . stateLock . withLock {
60
- self . state. writeNextRequestPart ( )
60
+ let writeAction = self . state . withLockedValue { state in
61
+ state. writeNextRequestPart ( )
61
62
}
62
63
63
64
switch writeAction {
@@ -99,30 +100,33 @@ import NIOSSL
99
100
100
101
struct BreakTheWriteLoopError : Swift . Error { }
101
102
103
+ // FIXME: Refactor this to not use `self.state.unsafe`.
102
104
private func writeRequestBodyPart( _ part: ByteBuffer ) async throws {
103
- self . stateLock . lock ( )
104
- switch self . state. writeNextRequestPart ( ) {
105
+ self . state . unsafe . lock ( )
106
+ switch self . state. unsafe . withValueAssumingLockIsAcquired ( { state in state . writeNextRequestPart ( ) } ) {
105
107
case . writeAndContinue( let executor) :
106
- self . stateLock . unlock ( )
108
+ self . state . unsafe . unlock ( )
107
109
executor. writeRequestBodyPart ( . byteBuffer( part) , request: self , promise: nil )
108
110
109
111
case . writeAndWait( let executor) :
110
112
try await withCheckedThrowingContinuation { ( continuation: CheckedContinuation < Void , Error > ) in
111
- self . state. waitForRequestBodyDemand ( continuation: continuation)
112
- self . stateLock. unlock ( )
113
+ self . state. unsafe. withValueAssumingLockIsAcquired ( { state in
114
+ state. waitForRequestBodyDemand ( continuation: continuation)
115
+ } )
116
+ self . state. unsafe. unlock ( )
113
117
114
118
executor. writeRequestBodyPart ( . byteBuffer( part) , request: self , promise: nil )
115
119
}
116
120
117
121
case . fail:
118
- self . stateLock . unlock ( )
122
+ self . state . unsafe . unlock ( )
119
123
throw BreakTheWriteLoopError ( )
120
124
}
121
125
}
122
126
123
127
private func requestBodyStreamFinished( ) {
124
- let finishAction = self . stateLock . withLock {
125
- self . state. finishRequestBodyStream ( )
128
+ let finishAction = self . state . withLockedValue { state in
129
+ state. finishRequestBodyStream ( )
126
130
}
127
131
128
132
switch finishAction {
@@ -150,8 +154,8 @@ extension Transaction: HTTPSchedulableRequest {
150
154
var requiredEventLoop : EventLoop ? { nil }
151
155
152
156
func requestWasQueued( _ scheduler: HTTPRequestScheduler ) {
153
- self . stateLock . withLock {
154
- self . state. requestWasQueued ( scheduler)
157
+ self . state . withLockedValue { state in
158
+ state. requestWasQueued ( scheduler)
155
159
}
156
160
}
157
161
}
@@ -165,8 +169,8 @@ extension Transaction: HTTPExecutableRequest {
165
169
// MARK: Request
166
170
167
171
func willExecuteRequest( _ executor: HTTPRequestExecutor ) {
168
- let action = self . stateLock . withLock {
169
- self . state. willExecuteRequest ( executor)
172
+ let action = self . state . withLockedValue { state in
173
+ state. willExecuteRequest ( executor)
170
174
}
171
175
172
176
switch action {
@@ -183,8 +187,8 @@ extension Transaction: HTTPExecutableRequest {
183
187
func requestHeadSent( ) { }
184
188
185
189
func resumeRequestBodyStream( ) {
186
- let action = self . stateLock . withLock {
187
- self . state. resumeRequestBodyStream ( )
190
+ let action = self . state . withLockedValue { state in
191
+ state. resumeRequestBodyStream ( )
188
192
}
189
193
190
194
switch action {
@@ -214,16 +218,16 @@ extension Transaction: HTTPExecutableRequest {
214
218
}
215
219
216
220
func pauseRequestBodyStream( ) {
217
- self . stateLock . withLock {
218
- self . state. pauseRequestBodyStream ( )
221
+ self . state . withLockedValue { state in
222
+ state. pauseRequestBodyStream ( )
219
223
}
220
224
}
221
225
222
226
// MARK: Response
223
227
224
228
func receiveResponseHead( _ head: HTTPResponseHead ) {
225
- let action = self . stateLock . withLock {
226
- self . state. receiveResponseHead ( head, delegate: self )
229
+ let action = self . state . withLockedValue { state in
230
+ state. receiveResponseHead ( head, delegate: self )
227
231
}
228
232
229
233
switch action {
@@ -243,8 +247,8 @@ extension Transaction: HTTPExecutableRequest {
243
247
}
244
248
245
249
func receiveResponseBodyParts( _ buffer: CircularBuffer < ByteBuffer > ) {
246
- let action = self . stateLock . withLock {
247
- self . state. receiveResponseBodyParts ( buffer)
250
+ let action = self . state . withLockedValue { state in
251
+ state. receiveResponseBodyParts ( buffer)
248
252
}
249
253
switch action {
250
254
case . none:
@@ -260,8 +264,8 @@ extension Transaction: HTTPExecutableRequest {
260
264
}
261
265
262
266
func succeedRequest( _ buffer: CircularBuffer < ByteBuffer > ? ) {
263
- let succeedAction = self . stateLock . withLock {
264
- self . state. succeedRequest ( buffer)
267
+ let succeedAction = self . state . withLockedValue { state in
268
+ state. succeedRequest ( buffer)
265
269
}
266
270
switch succeedAction {
267
271
case . finishResponseStream( let source, let finalResponse) :
@@ -276,8 +280,8 @@ extension Transaction: HTTPExecutableRequest {
276
280
}
277
281
278
282
func fail( _ error: Error ) {
279
- let action = self . stateLock . withLock {
280
- self . state. fail ( error)
283
+ let action = self . state . withLockedValue { state in
284
+ state. fail ( error)
281
285
}
282
286
self . performFailAction ( action)
283
287
}
@@ -304,8 +308,8 @@ extension Transaction: HTTPExecutableRequest {
304
308
}
305
309
306
310
func deadlineExceeded( ) {
307
- let action = self . stateLock . withLock {
308
- self . state. deadlineExceeded ( )
311
+ let action = self . state . withLockedValue { state in
312
+ state. deadlineExceeded ( )
309
313
}
310
314
self . performDeadlineExceededAction ( action)
311
315
}
@@ -329,8 +333,8 @@ extension Transaction: HTTPExecutableRequest {
329
333
extension Transaction : NIOAsyncSequenceProducerDelegate {
330
334
@usableFromInline
331
335
func produceMore( ) {
332
- let action = self . stateLock . withLock {
333
- self . state. produceMore ( )
336
+ let action = self . state . withLockedValue { state in
337
+ state. produceMore ( )
334
338
}
335
339
switch action {
336
340
case . none:
0 commit comments