1{-# LANGUAGE CApiFFI #-}
2#if __GLASGOW_HASKELL__ >= 709
3{-# LANGUAGE Safe #-}
4#else
5{-# LANGUAGE Trustworthy #-}
6#endif
7-----------------------------------------------------------------------------
8-- |
9-- Module      :  System.Posix.Resource
10-- Copyright   :  (c) The University of Glasgow 2003
11-- License     :  BSD-style (see the file libraries/base/LICENSE)
12--
13-- Maintainer  :  libraries@haskell.org
14-- Stability   :  provisional
15-- Portability :  non-portable (requires POSIX)
16--
17-- POSIX resource support
18--
19-----------------------------------------------------------------------------
20
21module System.Posix.Resource (
22    -- * Resource Limits
23    ResourceLimit(..), ResourceLimits(..), Resource(..),
24    getResourceLimit,
25    setResourceLimit,
26  ) where
27
28#include "HsUnix.h"
29
30import System.Posix.Types
31import Foreign
32import Foreign.C
33
34-- -----------------------------------------------------------------------------
35-- Resource limits
36
37data Resource
38  = ResourceCoreFileSize
39  | ResourceCPUTime
40  | ResourceDataSize
41  | ResourceFileSize
42  | ResourceOpenFiles
43  | ResourceStackSize
44#ifdef RLIMIT_AS
45  | ResourceTotalMemory
46#endif
47  deriving Eq
48
49data ResourceLimits
50  = ResourceLimits { softLimit, hardLimit :: ResourceLimit }
51  deriving Eq
52
53data ResourceLimit
54  = ResourceLimitInfinity
55  | ResourceLimitUnknown
56  | ResourceLimit Integer
57  deriving Eq
58
59data {-# CTYPE "struct rlimit" #-} RLimit
60
61foreign import capi unsafe "HsUnix.h getrlimit"
62  c_getrlimit :: CInt -> Ptr RLimit -> IO CInt
63
64foreign import capi unsafe "HsUnix.h setrlimit"
65  c_setrlimit :: CInt -> Ptr RLimit -> IO CInt
66
67getResourceLimit :: Resource -> IO ResourceLimits
68getResourceLimit res = do
69  allocaBytes (#const sizeof(struct rlimit)) $ \p_rlimit -> do
70    throwErrnoIfMinus1_ "getResourceLimit" $
71      c_getrlimit (packResource res) p_rlimit
72    soft <- (#peek struct rlimit, rlim_cur) p_rlimit
73    hard <- (#peek struct rlimit, rlim_max) p_rlimit
74    return (ResourceLimits {
75                softLimit = unpackRLimit soft,
76                hardLimit = unpackRLimit hard
77           })
78
79setResourceLimit :: Resource -> ResourceLimits -> IO ()
80setResourceLimit res ResourceLimits{softLimit=soft,hardLimit=hard} = do
81  allocaBytes (#const sizeof(struct rlimit)) $ \p_rlimit -> do
82    (#poke struct rlimit, rlim_cur) p_rlimit (packRLimit soft True)
83    (#poke struct rlimit, rlim_max) p_rlimit (packRLimit hard False)
84    throwErrnoIfMinus1_ "setResourceLimit" $
85        c_setrlimit (packResource res) p_rlimit
86    return ()
87
88packResource :: Resource -> CInt
89packResource ResourceCoreFileSize  = (#const RLIMIT_CORE)
90packResource ResourceCPUTime       = (#const RLIMIT_CPU)
91packResource ResourceDataSize      = (#const RLIMIT_DATA)
92packResource ResourceFileSize      = (#const RLIMIT_FSIZE)
93packResource ResourceOpenFiles     = (#const RLIMIT_NOFILE)
94packResource ResourceStackSize     = (#const RLIMIT_STACK)
95#ifdef RLIMIT_AS
96packResource ResourceTotalMemory   = (#const RLIMIT_AS)
97#endif
98
99unpackRLimit :: CRLim -> ResourceLimit
100unpackRLimit (#const RLIM_INFINITY)  = ResourceLimitInfinity
101unpackRLimit other
102#if defined(RLIM_SAVED_MAX)
103    | ((#const RLIM_SAVED_MAX) :: CRLim) /= (#const RLIM_INFINITY) &&
104      other == (#const RLIM_SAVED_MAX) = ResourceLimitUnknown
105#endif
106#if defined(RLIM_SAVED_CUR)
107    | ((#const RLIM_SAVED_CUR) :: CRLim) /= (#const RLIM_INFINITY) &&
108      other == (#const RLIM_SAVED_CUR) = ResourceLimitUnknown
109#endif
110    | otherwise = ResourceLimit (fromIntegral other)
111
112packRLimit :: ResourceLimit -> Bool -> CRLim
113packRLimit ResourceLimitInfinity _     = (#const RLIM_INFINITY)
114#ifdef RLIM_SAVED_CUR
115packRLimit ResourceLimitUnknown  True  = (#const RLIM_SAVED_CUR)
116#endif
117#ifdef RLIM_SAVED_MAX
118packRLimit ResourceLimitUnknown  False = (#const RLIM_SAVED_MAX)
119#endif
120packRLimit (ResourceLimit other) _     = fromIntegral other
121
122
123-- -----------------------------------------------------------------------------
124-- Test code
125
126{-
127import System.Posix
128import Control.Monad
129
130main = do
131 zipWithM_ (\r n -> setResourceLimit r ResourceLimits{
132                                        hardLimit = ResourceLimit n,
133                                        softLimit = ResourceLimit n })
134        allResources [1..]
135 showAll
136 mapM_ (\r -> setResourceLimit r ResourceLimits{
137                                        hardLimit = ResourceLimit 1,
138                                        softLimit = ResourceLimitInfinity })
139        allResources
140   -- should fail
141
142
143showAll =
144  mapM_ (\r -> getResourceLimit r >>= (putStrLn . showRLims)) allResources
145
146allResources =
147    [ResourceCoreFileSize, ResourceCPUTime, ResourceDataSize,
148        ResourceFileSize, ResourceOpenFiles, ResourceStackSize
149#ifdef RLIMIT_AS
150        , ResourceTotalMemory
151#endif
152        ]
153
154showRLims ResourceLimits{hardLimit=h,softLimit=s}
155  = "hard: " ++ showRLim h ++ ", soft: " ++ showRLim s
156
157showRLim ResourceLimitInfinity = "infinity"
158showRLim ResourceLimitUnknown  = "unknown"
159showRLim (ResourceLimit other)  = show other
160-}
161