packages feed

warp-3.4.18: Network/Wai/Handler/Warp/Counter.hs

{-# LANGUAGE RankNTypes #-}

module Network.Wai.Handler.Warp.Counter (
    Counter,
    newCounter,
    HasDecreased (..),
    waitForZero,
    forkConnection,
    waitForDecreased,
    getCount,
    getCountSTM,
    threadManager,
) where

import Control.Concurrent.STM
import System.ThreadManager (
    ThreadManager,
    countManaged,
    forkManagedBy,
    newThreadManager,
    waitUntilAllGone,
 )

-- | The connections of a server: how many there are, and which threads
--   are serving them.
--
--   Both come from the 'ThreadManager', which counts a connection from
--   when the accept loop keeps a place for it -- before the thread that
--   will serve it has been scheduled, which is too late for a graceful
--   shutdown to notice it.
newtype Counter = Counter ThreadManager

newCounter :: IO Counter
newCounter = Counter <$> newThreadManager

-- | The manager owning the connections, for supervising them.
threadManager :: Counter -> ThreadManager
threadManager (Counter tm) = tm

waitForZero :: Counter -> IO ()
waitForZero (Counter tm) = waitUntilAllGone tm

data HasDecreased = HasDecreased | NoConnections
    deriving (Eq, Show)

waitForDecreased :: Counter -> IO HasDecreased
waitForDecreased (Counter tm) = do
    n0 <- atomically $ countManaged tm
    if n0 <= 0
        then pure NoConnections
        else atomically $ do
            n <- countManaged tm
            check (n < n0)
            pure HasDecreased

-- | Serving a connection on a thread made by the given fork.  The
--   connection is counted from here rather than from when that thread
--   starts: the accept loop does not wait for it, and a connection which
--   has been accepted must not look to 'waitForZero' like one that is
--   gone.
forkConnection
    :: Counter
    -> (((forall x. IO x -> IO x) -> IO ()) -> IO ())
    -- ^ The fork from the settings
    -> ((forall x. IO x -> IO x) -> IO ())
    -- ^ Serving the connection
    -> IO ()
forkConnection (Counter tm) fork io = forkManagedBy tm fork "Warp just forked" io

-- | Get the current count of open connections.
--
-- @since 3.4.11
getCount :: Counter -> IO Int
getCount = atomically . getCountSTM

-- | Get the current count in an 'STM' transaction.
--
-- @since 3.4.13
getCountSTM :: Counter -> STM Int
getCountSTM (Counter tm) = countManaged tm