packages feed

hen-0.0.3: src/System/Xen/Types.hsc

{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RecordWildCards #-}

-- | Types for working with 'XenCtrl' data and accoring 'Storable' instances.
module System.Xen.Types
    ( XcHandle(..)
    , DomId(..)
    , DomainFlag(..)
    , DomainShutdownReason(..)
    , DomainInfo(..)
    ) where

#include <xenctrl.h>
#include <xen/sched.h>

#let alignment t = "%lu", (unsigned long) offsetof(struct {char x__; t (y__); }, y__)

import Prelude hiding (elem, foldl)

import Control.Applicative ((<$>))
import Data.Bits (testBit, bit, (.|.))
import Data.Maybe (catMaybes)
import Data.Foldable (foldl)
import Data.Word (Word32, Word64)
import Foreign.C (CInt(..), CUInt(..))
#if XEN_SYSCTL_INTERFACE_VERSION == 8
import Foreign.C (CIntPtr(..))
#endif
import Foreign.Ptr (Ptr, castPtr)
import Foreign.Storable (Storable(..))

import Control.Exception.Lifted (throwIO)
import Data.UUID (UUID)
import Data.BitSet (BitSet)
import qualified Data.BitSet as BitSet

import System.Xen.Errors (InvalidDomainShutdownReason(..))

-- | Entry point of the hypervisor interface connection, it's a file descriptor
-- in xen 3 and pointer to corresponging structure in xen 4.
#if XEN_SYSCTL_INTERFACE_VERSION == 8
newtype XcHandle = XcHandle CIntPtr
#elif XEN_SYSCTL_INTERFACE_VERSION == 6
newtype XcHandle = XcHandle CInt
#endif
    deriving (Eq, Ord, Show, Storable)

-- | Domain id, wrapper around 'Word32'.
newtype DomId = DomId { unDomId :: Word32 }
    deriving (Eq, Ord, Show, Read, Storable)

-- | Domain flags. It's translated from xc_dominfo structure, so it's possible to
-- be mutual exclusion flags in one domain, e.g. 'DomainFlagShutdown' and
-- 'DomainFlagRunning'.
data DomainFlag = DomainFlagDying
                | DomainFlagCrashed
                | DomainFlagShutdown
                | DomainFlagPaused
                | DomainFlagBlocked
                | DomainFlagRunning
                | DomainFlagHVM
                | DomainFlagDebugged
    deriving (Enum, Eq, Ord, Show, Read)

-- | Domain shutdown reason it's only meaningful if domain has 'DomainFlagShutdown'
-- flag.
data DomainShutdownReason = DomainShutdownReasonPoweroff
                          | DomainShutdownReasonReboot
                          | DomainShutdownReasonSuspend
                          | DomainShutdownReasonCrash
                          | DomainShutdownReasonWatchdog
    deriving (Eq, Ord, Show, Read)

-- | Information about a single domain.
data DomainInfo = DomainInfo
    { domainInfoId                  :: {-# UNPACK #-} !DomId
    , domainInfoSsidRef             :: {-# UNPACK #-} !Word32
    , domainInfoFlags               :: BitSet DomainFlag
    , domainInfoShutdownReason      :: Maybe DomainShutdownReason
    , domainInfoNumberOfPages       :: {-# UNPACK #-} !Word32
#if XEN_SYSCTL_INTERFACE_VERSION == 8
    , domainInfoNumberOfSharedPages :: {-# UNPACK #-} !Word32
#endif
    , domainInfoSharedInfoFrame     :: {-# UNPACK #-} !Word32
    , domainInfoCpuTime             :: {-# UNPACK #-} !Word64
    , domainInfoMaxMemKb            :: {-# UNPACK #-} !Word32
    , domainInfoNubmerOfOnlineVcpus :: {-# UNPACK #-} !Word32
    , domainInfoMaxVcpuId           :: {-# UNPACK #-} !Word32
    , domainInfoDomHandle           :: {-# UNPACK #-} !UUID
#if XEN_SYSCTL_INTERFACE_VERSION == 8
    , domainInfoCpuPool             :: {-# UNPACK #-} !Word32
#endif
    } deriving (Eq, Ord, Show, Read)

-- | Constats used in this instance defined in <xen/sched.h>.
instance Storable DomainShutdownReason where
    sizeOf _ = sizeOf (undefined :: CInt)
    alignment _ = alignment (undefined :: CInt)
    peek ptr = peek (castPtr ptr :: Ptr CInt) >>= \i -> case i of
        #{const SHUTDOWN_poweroff} -> return DomainShutdownReasonPoweroff
        #{const SHUTDOWN_reboot}   -> return DomainShutdownReasonReboot
        #{const SHUTDOWN_suspend}  -> return DomainShutdownReasonSuspend
        #{const SHUTDOWN_crash}    -> return DomainShutdownReasonCrash
        #{const SHUTDOWN_watchdog} -> return DomainShutdownReasonWatchdog
        invalid           -> throwIO $ InvalidDomainShutdownReason invalid
    poke ptr a = poke (castPtr ptr :: Ptr CInt) $ case a of
        DomainShutdownReasonPoweroff -> #{const SHUTDOWN_poweroff}
        DomainShutdownReasonReboot   -> #{const SHUTDOWN_reboot}
        DomainShutdownReasonSuspend  -> #{const SHUTDOWN_suspend}
        DomainShutdownReasonCrash    -> #{const SHUTDOWN_crash}
        DomainShutdownReasonWatchdog -> #{const SHUTDOWN_watchdog}

instance Storable DomainInfo where
    sizeOf _ = #{size xc_dominfo_t}
    alignment _ = #{alignment xc_dominfo_t}
    peek ptr = do
        domainInfoId                  <- #{peek xc_dominfo_t, domid} ptr
        domainInfoSsidRef             <- #{peek xc_dominfo_t, ssidref} ptr
        domainInfoFlags               <- do
            b :: CUInt <- peekByteOff ptr $
                sizeOf domainInfoId + sizeOf domainInfoSsidRef
            let maybeBit n v = if testBit b n then Just v else Nothing
            return $ BitSet.fromList $ catMaybes
               [ maybeBit 0 DomainFlagDying
               , maybeBit 1 DomainFlagCrashed
               , maybeBit 2 DomainFlagShutdown
               , maybeBit 3 DomainFlagPaused
               , maybeBit 4 DomainFlagBlocked
               , maybeBit 5 DomainFlagRunning
               , maybeBit 6 DomainFlagHVM
               , maybeBit 7 DomainFlagDebugged
               ]
        domainInfoShutdownReason      <-
            if DomainFlagShutdown `BitSet.member` domainInfoFlags
            then Just <$> #{peek xc_dominfo_t, shutdown_reason} ptr
            else return Nothing
        domainInfoNumberOfPages       <- #{peek xc_dominfo_t, nr_pages} ptr
#if XEN_SYSCTL_INTERFACE_VERSION == 8
        domainInfoNumberOfSharedPages <- #{peek xc_dominfo_t, nr_shared_pages} ptr
#endif
        domainInfoSharedInfoFrame     <- #{peek xc_dominfo_t, shared_info_frame} ptr
        domainInfoCpuTime             <- #{peek xc_dominfo_t, cpu_time} ptr
        domainInfoMaxMemKb            <- #{peek xc_dominfo_t, max_memkb} ptr
        domainInfoNubmerOfOnlineVcpus <- #{peek xc_dominfo_t, nr_online_vcpus} ptr
        domainInfoMaxVcpuId           <- #{peek xc_dominfo_t, max_vcpu_id} ptr
        domainInfoDomHandle           <- #{peek xc_dominfo_t, handle} ptr
#if XEN_SYSCTL_INTERFACE_VERSION == 8
        domainInfoCpuPool             <- #{peek xc_dominfo_t, cpupool} ptr
#endif
        return $ DomainInfo { .. }
    poke ptr DomainInfo { .. } = do
        #{poke xc_dominfo_t, domid} ptr domainInfoId
        #{poke xc_dominfo_t, ssidref} ptr domainInfoSsidRef
        let off = sizeOf domainInfoId + sizeOf domainInfoSsidRef
        let flags :: CUInt = foldl (\a b -> a .|. bit (fromEnum b)) 0 domainInfoFlags
        pokeByteOff ptr off flags
        case domainInfoShutdownReason of
            Nothing -> return ()
            Just reason -> #{poke xc_dominfo_t, shutdown_reason} ptr reason
        #{poke xc_dominfo_t, nr_pages} ptr domainInfoNumberOfPages
#if XEN_SYSCTL_INTERFACE_VERSION == 8
        #{poke xc_dominfo_t, nr_shared_pages} ptr domainInfoNumberOfSharedPages
#endif
        #{poke xc_dominfo_t, shared_info_frame} ptr domainInfoSharedInfoFrame
        #{poke xc_dominfo_t, cpu_time} ptr domainInfoCpuTime
        #{poke xc_dominfo_t, max_memkb} ptr domainInfoMaxMemKb
        #{poke xc_dominfo_t, nr_online_vcpus} ptr domainInfoNubmerOfOnlineVcpus
        #{poke xc_dominfo_t, max_vcpu_id} ptr domainInfoMaxVcpuId
        #{poke xc_dominfo_t, handle} ptr domainInfoDomHandle
#if XEN_SYSCTL_INTERFACE_VERSION == 8
        #{poke xc_dominfo_t, cpupool} ptr domainInfoCpuPool
#endif