Resource: Fix warning in case of no RLIM_SAVED_{CUR,MAX}
[packages/unix.git] / System / Posix / Resource.hsc
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
21 module System.Posix.Resource (
22     -- * Resource Limits
23     ResourceLimit(..), ResourceLimits(..), Resource(..),
24     getResourceLimit,
25     setResourceLimit,
26   ) where
27
28 #include "HsUnix.h"
29
30 import System.Posix.Types
31 import Foreign
32 import Foreign.C
33
34 -- -----------------------------------------------------------------------------
35 -- Resource limits
36
37 data 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
49 data ResourceLimits
50   = ResourceLimits { softLimit, hardLimit :: ResourceLimit }
51   deriving Eq
52
53 data ResourceLimit
54   = ResourceLimitInfinity
55   | ResourceLimitUnknown
56   | ResourceLimit Integer
57   deriving Eq
58
59 data {-# CTYPE "struct rlimit" #-} RLimit
60
61 foreign import capi unsafe "HsUnix.h getrlimit"
62   c_getrlimit :: CInt -> Ptr RLimit -> IO CInt
63
64 foreign import capi unsafe "HsUnix.h setrlimit"
65   c_setrlimit :: CInt -> Ptr RLimit -> IO CInt
66
67 getResourceLimit :: Resource -> IO ResourceLimits
68 getResourceLimit 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
79 setResourceLimit :: Resource -> ResourceLimits -> IO ()
80 setResourceLimit 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
88 packResource :: Resource -> CInt
89 packResource ResourceCoreFileSize  = (#const RLIMIT_CORE)
90 packResource ResourceCPUTime       = (#const RLIMIT_CPU)
91 packResource ResourceDataSize      = (#const RLIMIT_DATA)
92 packResource ResourceFileSize      = (#const RLIMIT_FSIZE)
93 packResource ResourceOpenFiles     = (#const RLIMIT_NOFILE)
94 packResource ResourceStackSize     = (#const RLIMIT_STACK)
95 #ifdef RLIMIT_AS
96 packResource ResourceTotalMemory   = (#const RLIMIT_AS)
97 #endif
98
99 unpackRLimit :: CRLim -> ResourceLimit
100 unpackRLimit (#const RLIM_INFINITY)  = ResourceLimitInfinity
101 unpackRLimit 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
112 packRLimit :: ResourceLimit -> Bool -> CRLim
113 packRLimit ResourceLimitInfinity _     = (#const RLIM_INFINITY)
114 #if defined(RLIM_SAVED_CUR)
115 packRLimit ResourceLimitUnknown  True  = (#const RLIM_SAVED_CUR)
116 #endif
117 #if defined(RLIM_SAVED_MAX)
118 packRLimit ResourceLimitUnknown  False = (#const RLIM_SAVED_MAX)
119 #endif
120 #if ! defined(RLIM_SAVED_MAX) && !defined(RLIM_SAVED_CUR)
121 packRLimit ResourceLimitUnknown  _     =
122     error
123       $ "System.Posix.Resource.packRLimit: " ++
124         "ResourceLimitUnknown but RLIM_SAVED_MAX/RLIM_SAVED_CUR not defined by platform"
125 #endif
126 packRLimit (ResourceLimit other) _     = fromIntegral other
127
128
129 -- -----------------------------------------------------------------------------
130 -- Test code
131
132 {-
133 import System.Posix
134 import Control.Monad
135
136 main = do
137  zipWithM_ (\r n -> setResourceLimit r ResourceLimits{
138                                         hardLimit = ResourceLimit n,
139                                         softLimit = ResourceLimit n })
140         allResources [1..]
141  showAll
142  mapM_ (\r -> setResourceLimit r ResourceLimits{
143                                         hardLimit = ResourceLimit 1,
144                                         softLimit = ResourceLimitInfinity })
145         allResources
146    -- should fail
147
148
149 showAll =
150   mapM_ (\r -> getResourceLimit r >>= (putStrLn . showRLims)) allResources
151
152 allResources =
153     [ResourceCoreFileSize, ResourceCPUTime, ResourceDataSize,
154         ResourceFileSize, ResourceOpenFiles, ResourceStackSize
155 #ifdef RLIMIT_AS
156         , ResourceTotalMemory
157 #endif
158         ]
159
160 showRLims ResourceLimits{hardLimit=h,softLimit=s}
161   = "hard: " ++ showRLim h ++ ", soft: " ++ showRLim s
162
163 showRLim ResourceLimitInfinity = "infinity"
164 showRLim ResourceLimitUnknown  = "unknown"
165 showRLim (ResourceLimit other)  = show other
166 -}