{-# LINE 1 "src/System/Xen/Mid.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LINE 2 "src/System/Xen/Mid.hsc" #-}
{-# LANGUAGE FlexibleContexts #-}

-- | Mid-level interface to @XenCtrl@. Functions that provided by this module are
-- version-independent from @Xen@ and raise real exceptions instead of confusing
-- error codes and @errno@.

module System.Xen.Mid
    ( interfaceOpen
    , interfaceClose
    , domainGetInfo
    ) where


{-# LINE 15 "src/System/Xen/Mid.hsc" #-}

import Control.Monad (void, when, forM)
import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.Storable (peekElemOff, sizeOf)

import Control.Exception.Lifted (throwIO)
import Control.Monad.Base (MonadBase(liftBase))

import System.Xen.Errors (DomainGetInfoError(..), XcHandleOpenError(..), getErrno)
import System.Xen.Low (xc_interface_open, xc_interface_close, xc_domain_getinfo)
import System.Xen.Types (XcHandle(..), DomId(..), DomainInfo)

-- | Open the connection to the hypervisor interface, can fail with
-- 'System.Xen.Errors.XcHandleOpenError'.
interfaceOpen :: MonadBase IO m => m XcHandle
interfaceOpen = liftBase $ do

{-# LINE 32 "src/System/Xen/Mid.hsc" #-}
    i@(XcHandle ptr) <- xc_interface_open 0 0 0
    when (ptr `elem` [-1, 0]) $ getErrno >>= throwIO . XcHandleOpenError

{-# LINE 38 "src/System/Xen/Mid.hsc" #-}
    return i

-- | Close an open hypervisor interface, ignores all possible errors but all the
-- same can fail with segfault or sutin.
interfaceClose :: MonadBase IO m => XcHandle -> m ()
interfaceClose = void . liftBase . xc_interface_close

-- | Returns a list of currently runing domains, 1024 maximum, can fail with
-- 'System.Xen.Errors.InvalidDomainShutdownReason' and
-- 'System.Xen.Errors.DomainGetInfoError'.
domainGetInfo :: MonadBase IO m => XcHandle -> m [DomainInfo]
domainGetInfo handle = liftBase $ allocaBytes size $ \ptr -> do
     wrote <- fmap fromIntegral $ xc_domain_getinfo handle (dom0) count ptr
     when (wrote == -1) $ getErrno >>= throwIO . DomainGetInfoError
     forM [0 .. wrote - 1] $ peekElemOff ptr
  where
    dom0 = DomId 0
    count :: Num a => a
    count = 1024
    size = count * sizeOf (undefined :: DomainInfo)