@@ -57,6 +57,8 @@ response ctx mgr tconf tickle strm sq s h strmbdy = do
58 runStream ctx OResponse tickle strm sq s h strmbdy
58 runStream ctx OResponse tickle strm sq s h strmbdy
60+-- | Set up a waiter thread and run the stream body with functions to enqueue
61+-- 'Sequence's on the stream's queue.
60runStream :: Context
62runStream :: Context
61 -> (Stream -> H.Status -> H.ResponseHeaders -> Aux -> Output)
63 -> (Stream -> H.Status -> H.ResponseHeaders -> Aux -> Output)
62 -> Respond
64 -> Respond
@@ -68,14 +70,17 @@ runStream Context{outputQ} mkOutput tickle strm sq s h strmbdy = do
68 -- queue is not empty.
70 -- queue is not empty.
69 void $ forkIO $ waiter tvar sq strm outputQ
71 void $ forkIO $ waiter tvar sq strm outputQ
70 atomically $ writeTVar tvar (SyncNext out)
72 atomically $ writeTVar tvar (SyncNext out)
71− let push chunk = do
73+ let write chunk = do
72 atomically $ writeTBQueue sq $ case chunk of
74 atomically $ writeTBQueue sq $ case chunk of
73 BuilderChunk b -> SBuilder b
75 BuilderChunk b -> SBuilder b
74 FileChunk path part -> SFile path part
76 FileChunk path part -> SFile path part
76 flush = atomically $ writeTBQueue sq SFlush
78 flush = atomically $ writeTBQueue sq SFlush
77− strmbdy push flush
79+ strmbdy write flush
81+-- | Set up a queue for the stream and use the given 'Respond' to actually run
82+-- it. This will be 'response' for client-initiated streams and just plain
83+-- 'runStream' for pushed streams.
79runResponder :: Responder -> Respond -> IO () -> Stream -> IO ()
84runResponder :: Responder -> Respond -> IO () -> Stream -> IO ()
80runResponder responder respond tickle strm = do
85runResponder responder respond tickle strm = do
81 -- Since 'Body' is loop, we cannot control it.
86 -- Since 'Body' is loop, we cannot control it.
@@ -84,6 +89,8 @@ runResponder responder respond tickle strm = do
84 trailers <- responder $ respond tickle strm sq
89 trailers <- responder $ respond tickle strm sq
85 atomically $ writeTBQueue sq $ SFinish trailers
90 atomically $ writeTBQueue sq $ SFinish trailers
92+-- | Handle abnormal termination of a stream: mark it as closed, send a reset
93+-- frame, and call the user's 'settingsOnException' handler if applicable.
87cleanupStream :: Context -> S.Settings -> Stream -> Maybe Request -> Maybe SomeException -> IO ()
94cleanupStream :: Context -> S.Settings -> Stream -> Maybe Request -> Maybe SomeException -> IO ()
88cleanupStream Context{outputQ} set strm req me = do
95cleanupStream Context{outputQ} set strm req me = do
89 closed strm Killed
96 closed strm Killed
@@ -199,6 +206,11 @@ worker ctx@Context{inputQ} set tm app respond = do
199 cleanupStream ctx set strm (Just req) me
206 cleanupStream ctx set strm (Just req) me
200 clearStreamInfo sinfo
207 clearStreamInfo sinfo
209+-- | A dedicated waiter thread to re-enqueue the stream in the priority tree
210+-- whenever output becomes available. When the sender drains the queue and
211+-- moves on to another stream, it drops a message in the 'TVar', and this
212+-- thread wakes up, waits for more output to become available, and re-enqueues
202waiter :: TVar Sync -> TBQueue Sequence -> Stream -> PriorityTree Output -> IO ()
214waiter :: TVar Sync -> TBQueue Sequence -> Stream -> PriorityTree Output -> IO ()
203waiter tvar sq strm outQ = do
215waiter tvar sq strm outQ = do
204 -- waiting for actions other than SyncNone
216 -- waiting for actions other than SyncNone