summaryrefslogtreecommitdiffhomepage
path: root/src/Xmobar/Plugins/Monitors/Top/FreeBSD.hsc
blob: cb822ef542bb50ece4cfcb9879fb1124b3467df9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
{-# LANGUAGE CPP                      #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CApiFFI #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Plugins.Monitors.Top.FreeBSD
-- Copyright   :  (c) 2010, 2011, 2012, 2013, 2014, 2018 Jose A Ortega Ruiz
-- License     :  BSD-style (see LICENSE)
--
-- Maintainer  :  Jose A Ortega Ruiz <jao@gnu.org>
-- Stability   :  unstable
-- Portability :  unportable
--
--  Process activity and memory consumption monitors
--
-----------------------------------------------------------------------------

module Xmobar.Plugins.Monitors.Top.FreeBSD (
  timeMemEntries
  , meminfos
  , scale) where

import Foreign
import Foreign.C.Types
import Foreign.C.String

import Xmobar.Plugins.Monitors.Top.Common (MemInfo, TimeEntry)

#include <unistd.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <libprocstat.h>

foreign import ccall "unistd.h getpagesize" c_getpagesize :: CInt
foreign import ccall unsafe "libprocstat.h procstat_open_sysctl" c_procstat_open_sysctl :: IO (Ptr PROCSTAT)
foreign import ccall "&procstat_close" c_procstat_close :: FinalizerPtr PROCSTAT
foreign import ccall "&procstat_freeprocs" c_procstat_freeprocs :: FinalizerEnvPtr PROCSTAT KINFO_PROC
foreign import ccall unsafe "libprocstat.h procstat_getprocs" c_procstat_getprocs :: Ptr PROCSTAT -> CInt -> CInt -> Ptr CUInt -> IO (Ptr KINFO_PROC)

data PROCSTAT
data ProcStat = ProcStat !(ForeignPtr PROCSTAT)
  deriving (Eq, Ord, Show)

data KINFO_PROC
data KinfoProc = KinfoProc [ProcData] Int
  deriving (Eq, Show)

data ProcData = ProcData {
  pname :: String
  , cpu :: Float
  , tdflags :: CULong
  , flag :: CULong
  , stat :: CUChar
  , rss :: Float
  , pid :: Int
  , runtime :: Float
  }
  deriving (Show, Read, Eq)

instance Storable ProcData where
  alignment _ = #{alignment struct kinfo_proc}
  sizeOf _    = #{size struct kinfo_proc}
  peek ptr    = do
       c <- #{peek struct kinfo_proc, ki_pctcpu} ptr
       ctdflags <- #{peek struct kinfo_proc, ki_tdflags} ptr
       cflag <- #{peek struct kinfo_proc, ki_flag} ptr
       cstat <- #{peek struct kinfo_proc, ki_stat} ptr
       cruntime <- #{peek struct kinfo_proc, ki_runtime} ptr :: IO CULong
       crss <- #{peek struct kinfo_proc, ki_rssize} ptr :: IO CULong
       cname <- peekCString (ptr `plusPtr` (#offset struct kinfo_proc, ki_comm))
       cpid <- #{peek struct kinfo_proc, ki_pid} ptr
       let crssf = (fromIntegral . toInteger) crss
       let cruntimef = ((fromIntegral . toInteger) cruntime  + 500000) / 10000
       return $ ProcData {
         pname = cname
         , cpu = (pctdouble c) * 100
         , tdflags = ctdflags
         , stat = cstat
         , flag = cflag
         , rss = crssf * pageSize
         , pid = cpid
         , runtime = cruntimef}

  poke _ _    = pure ()

pctdouble :: Int -> Float
pctdouble p = (fromIntegral p) / #{const FSCALE}


pageSize :: Float
pageSize = fromIntegral c_getpagesize / 1024


getProcStat:: IO ProcStat
getProcStat = do
    proc_ptr <- c_procstat_open_sysctl
    ptr <- newForeignPtr c_procstat_close proc_ptr
    return $ ProcStat ptr


getProcessesInfo :: ProcStat -> IO [ProcData]
getProcessesInfo (ProcStat ps_fp) = do
  withForeignPtr ps_fp $ \ps_ptr -> do
    alloca $ \n_ptr -> do
      kinfo_proc_ptr <- c_procstat_getprocs ps_ptr #{const KERN_PROC_PROC} 0 n_ptr
      newForeignPtrEnv c_procstat_freeprocs ps_ptr kinfo_proc_ptr
      num <- peek (n_ptr :: Ptr CUInt)
      pds <- peekArray (fromIntegral num) $ castPtr kinfo_proc_ptr :: IO [ProcData]

      return $ [p | p <- pds, flag p .&. #{const P_SYSTEM} == 0]


processes :: IO [ProcData]
processes = do
  proc_stat <- getProcStat
  getProcessesInfo proc_stat

handleProcesses :: (ProcData -> a) -> IO [a]
handleProcesses f = do
  ps <- processes
  return $ fmap (\pd -> f pd) ps

meminfo :: ProcData -> MemInfo
meminfo pd = (pname pd, rss pd)

meminfos :: IO [MemInfo]
meminfos = handleProcesses meminfo

timeMemEntry :: ProcData -> (TimeEntry, MemInfo)
timeMemEntry pd = ((p, (n, t)), (n, r))
  where p = pid pd
        n = pname pd
        t = runtime pd
        (_, r) = meminfo pd

timeMemEntries :: IO [(TimeEntry, MemInfo)]
timeMemEntries = handleProcesses timeMemEntry

scale :: IO Float
scale = return 1