@@ -77,7 +77,7 @@ frameSender
77
77
x <- atomically $ dequeue off
78
78
case x of
79
79
C ctl -> flushN off >> control ctl >> loop 0
80
- O out -> outputOrEnqueueAgain out off >>= flushIfNecessary >>= loop
80
+ O out -> outputAndSync out off >>= flushIfNecessary >>= loop
81
81
Flush -> flushN off >> loop 0
82
82
83
83
-- Flush the connection buffer to the socket, where the first 'n' bytes of
@@ -139,29 +139,31 @@ frameSender
139
139
Just siz -> setLimitForEncoding siz encodeDynamicTable
140
140
141
141
----------------------------------------------------------------
142
- outputOrEnqueueAgain :: Output -> Offset -> IO Offset
143
- outputOrEnqueueAgain out@ (Output strm otyp sync) off = E. handle (\ e -> resetStream strm InternalError e >> return off) $ do
142
+ -- INVARIANT
143
+ --
144
+ -- Both the stream window and the connection window are open.
145
+ ----------------------------------------------------------------
146
+ outputAndSync :: Output -> Offset -> IO Offset
147
+ outputAndSync out@ (Output strm otyp sync) off = E. handle (\ e -> resetStream strm InternalError e >> return off) $ do
144
148
state <- readStreamState strm
145
149
if isHalfClosedLocal state
146
150
then return off
147
151
else case otyp of
148
- OHeader hdr mnext tlrmkr ->
149
- -- Send headers immediately, without waiting for data
150
- -- No need to check the streaming window (applies to DATA frames only)
151
- outputHeader strm hdr mnext tlrmkr sync off
152
+ OHeader hdr mnext tlrmkr -> do
153
+ (off', mout') <- outputHeader strm hdr mnext tlrmkr sync off
154
+ case mout' of
155
+ Nothing -> sync Done
156
+ Just out' -> sync $ Cont out'
157
+ return off'
152
158
_ -> do
153
- -- The 'sync' function usage constraints hold here: We
154
- -- just popped off the only 'Output' for this stream,
155
- -- and we only enqueue a new output (in 'output') if
156
- -- 'sync' returns 'True'
157
- ok <- sync $ Just otyp
158
- if ok
159
- then do
160
- sws <- getStreamWindowSize strm
161
- cws <- getConnectionWindowSize ctx -- not 0
162
- let lim = min cws sws
163
- output out off lim
164
- else return off
159
+ sws <- getStreamWindowSize strm
160
+ cws <- getConnectionWindowSize ctx -- not 0
161
+ let lim = min cws sws
162
+ (off', mout') <- output out off lim
163
+ case mout' of
164
+ Nothing -> sync Done
165
+ Just out' -> sync $ Cont out'
166
+ return off'
165
167
166
168
resetStream :: Stream -> ErrorCode -> E. SomeException -> IO ()
167
169
resetStream strm err e = do
@@ -175,9 +177,9 @@ frameSender
175
177
-> [Header ]
176
178
-> Maybe DynaNext
177
179
-> TrailersMaker
178
- -> (Maybe OutputType -> IO Bool )
180
+ -> (Sync -> IO () )
179
181
-> Offset
180
- -> IO Offset
182
+ -> IO ( Offset , Maybe Output )
181
183
outputHeader strm hdr mnext tlrmkr sync off0 = do
182
184
-- Header frame and Continuation frame
183
185
let sid = streamNumber strm
@@ -186,19 +188,19 @@ frameSender
186
188
off' <- headerContinue sid ths endOfStream off0
187
189
-- halfClosedLocal calls closed which removes
188
190
-- the stream from stream table.
189
- when endOfStream $ do
190
- halfClosedLocal ctx strm Finished
191
- void $ sync Nothing
192
191
off <- flushIfNecessary off'
193
192
case mnext of
194
- Nothing -> return off
193
+ Nothing -> do
194
+ -- endOfStream
195
+ halfClosedLocal ctx strm Finished
196
+ return (off, Nothing )
195
197
Just next -> do
196
198
let out' = Output strm (ONext next tlrmkr) sync
197
- outputOrEnqueueAgain out' off
199
+ return (off, Just out')
198
200
199
201
----------------------------------------------------------------
200
- output :: Output -> Offset -> WindowSize -> IO Offset
201
- output out@ (Output strm (ONext curr tlrmkr) sync ) off0 lim = do
202
+ output :: Output -> Offset -> WindowSize -> IO ( Offset , Maybe Output )
203
+ output out@ (Output strm (ONext curr tlrmkr) _ ) off0 lim = do
202
204
-- Data frame payload
203
205
buflim <- readIORef outputBufferLimit
204
206
let payloadOff = off0 + frameHeaderLength
@@ -208,13 +210,12 @@ frameSender
208
210
case next of
209
211
Next datPayloadLen reqflush mnext -> do
210
212
NextTrailersMaker tlrmkr' <- runTrailersMaker tlrmkr datBuf datPayloadLen
211
- fillDataHeaderEnqueueNext
213
+ fillDataHeader
212
214
strm
213
215
off0
214
216
datPayloadLen
215
217
mnext
216
218
tlrmkr'
217
- sync
218
219
out
219
220
reqflush
220
221
CancelNext mErr -> do
@@ -233,15 +234,14 @@ frameSender
233
234
resetStream strm InternalError err
234
235
Nothing ->
235
236
resetStream strm Cancel (E. toException CancelledStream )
236
- return off0
237
- output (Output strm (OPush ths pid) sync ) off0 _lim = do
237
+ return ( off0, Nothing )
238
+ output (Output strm (OPush ths pid) _ ) off0 _lim = do
238
239
-- Creating a push promise header
239
240
-- Frame id should be associated stream id from the client.
240
241
let sid = streamNumber strm
241
242
len <- pushPromise pid sid ths off0
242
243
off <- flushIfNecessary $ off0 + frameHeaderLength + len
243
- _ <- sync Nothing
244
- return off
244
+ return (off, Nothing )
245
245
output _ _ _ = undefined -- never reached
246
246
247
247
----------------------------------------------------------------
@@ -285,23 +285,21 @@ frameSender
285
285
continue off' ths' FrameContinuation
286
286
287
287
----------------------------------------------------------------
288
- fillDataHeaderEnqueueNext
288
+ fillDataHeader
289
289
:: Stream
290
290
-> Offset
291
291
-> Int
292
292
-> Maybe DynaNext
293
293
-> (Maybe ByteString -> IO NextTrailersMaker )
294
- -> (Maybe OutputType -> IO Bool )
295
294
-> Output
296
295
-> Bool
297
- -> IO Offset
298
- fillDataHeaderEnqueueNext
296
+ -> IO ( Offset , Maybe Output )
297
+ fillDataHeader
299
298
strm@ Stream {streamNumber}
300
299
off
301
300
datPayloadLen
302
301
Nothing
303
302
tlrmkr
304
- sync
305
303
_
306
304
reqflush = do
307
305
let buf = confWriteBuffer `plusPtr` off
@@ -321,41 +319,37 @@ frameSender
321
319
else
322
320
return off
323
321
off'' <- handleTrailers mtrailers off'
324
- _ <- sync Nothing
325
322
halfClosedLocal ctx strm Finished
326
323
if reqflush
327
324
then do
328
325
flushN off''
329
- return 0
330
- else return off''
326
+ return ( 0 , Nothing )
327
+ else return ( off'', Nothing )
331
328
where
332
329
handleTrailers Nothing off0 = return off0
333
330
handleTrailers (Just trailers) off0 = do
334
331
(ths, _) <- toTokenHeaderTable trailers
335
332
headerContinue streamNumber ths True {- endOfStream -} off0
336
- fillDataHeaderEnqueueNext
333
+ fillDataHeader
337
334
_
338
335
off
339
336
0
340
337
(Just next)
341
338
tlrmkr
342
- _
343
339
out
344
340
reqflush = do
345
341
let out' = out{outputType = ONext next tlrmkr}
346
- enqueueOutput outputQ out'
347
342
if reqflush
348
343
then do
349
344
flushN off
350
- return 0
351
- else return off
352
- fillDataHeaderEnqueueNext
345
+ return ( 0 , Just out')
346
+ else return ( off, Just out')
347
+ fillDataHeader
353
348
strm@ Stream {streamNumber}
354
349
off
355
350
datPayloadLen
356
351
(Just next)
357
352
tlrmkr
358
- _
359
353
out
360
354
reqflush = do
361
355
let buf = confWriteBuffer `plusPtr` off
@@ -364,12 +358,11 @@ frameSender
364
358
fillFrameHeader FrameData datPayloadLen streamNumber flag buf
365
359
decreaseWindowSize ctx strm datPayloadLen
366
360
let out' = out{outputType = ONext next tlrmkr}
367
- enqueueOutput outputQ out'
368
361
if reqflush
369
362
then do
370
363
flushN off'
371
- return 0
372
- else return off'
364
+ return ( 0 , Just out')
365
+ else return ( off', Just out')
373
366
374
367
----------------------------------------------------------------
375
368
pushPromise :: StreamId -> StreamId -> TokenHeaderList -> Offset -> IO Int
0 commit comments