{-# LANGUAGE Trustworthy #-}

module Scheduler.Main ( MainScheduler
                      , getMainScheduler
                      , runMainScheduler
                      ) where

import Control.Concurrent
import Control.Concurrent.STM
import Data.IORef
import Scheduler
import Scheduler.Internal
import System.IO.Unsafe

-- | A scheduler which runs enqueued actions on the main thread.
newtype MainScheduler = MainScheduler (TQueue (ScheduledAction MainScheduler))

instance Scheduler MainScheduler where
    schedule (MainScheduler q) action = do
        (sa, d) <- newScheduledAction action
        atomically $ writeTQueue q sa
        return d

    schedulerMain s@(MainScheduler q) = do
        sa <- atomically $ readTQueue q
        executeScheduledAction s sa

-- ohai global variable
mainSchedulerRef :: IORef MainScheduler
{-# NOINLINE mainSchedulerRef #-}
mainSchedulerRef =
    unsafePerformIO $ do
        q <- atomically newTQueue
        newIORef $ MainScheduler q

-- | Returns a scheduler representing the main thread.
--
--   Note that 'runMainScheduler' must be called for enqueued actions to actually execute.
getMainScheduler :: IO MainScheduler
getMainScheduler = readIORef mainSchedulerRef

-- | Runs the main scheduler indefinitely using the current thread.
--   The current thread will be bound if possible.
runMainScheduler :: IO ()
runMainScheduler =
    let run = getMainScheduler >>= schedulerMain
    in if rtsSupportsBoundThreads
        then runInBoundThread run
        else run