Skip to content

Commit d299211

Browse files
authored
Get or set the file caching mode (#340)
1 parent 47d5fc4 commit d299211

File tree

2 files changed

+110
-3
lines changed

2 files changed

+110
-3
lines changed

System/Posix/Fcntl.hsc

+82-3
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,34 @@
1616
-----------------------------------------------------------------------------
1717

1818
#include "HsUnix.h"
19+
#include <fcntl.h>
1920

2021
module System.Posix.Fcntl (
2122
-- * File allocation
2223
Advice(..), fileAdvise,
2324
fileAllocate,
25+
-- * File caching
26+
fileGetCaching,
27+
fileSetCaching,
2428
) where
2529

26-
#if HAVE_POSIX_FALLOCATE || HAVE_POSIX_FADVISE
2730
import Foreign.C
28-
#endif
2931
import System.Posix.Types
3032

31-
#if !HAVE_POSIX_FALLOCATE
33+
#if !HAVE_POSIX_FALLOCATE || !HAVE_O_DIRECT
3234
import System.IO.Error ( ioeSetLocation )
3335
import GHC.IO.Exception ( unsupportedOperation )
3436
#endif
3537

38+
#if HAVE_O_DIRECT
39+
import Data.Bits (complement, (.&.), (.|.))
40+
import System.Posix.Internals (c_fcntl_read)
41+
#endif
42+
43+
#if HAVE_O_DIRECT || HAVE_F_NOCACHE
44+
import System.Posix.Internals (c_fcntl_write)
45+
#endif
46+
3647
-- -----------------------------------------------------------------------------
3748
-- File control
3849

@@ -101,3 +112,71 @@ foreign import capi safe "fcntl.h posix_fallocate"
101112
fileAllocate _ _ _ = ioError (ioeSetLocation unsupportedOperation
102113
"fileAllocate")
103114
#endif
115+
116+
-- -----------------------------------------------------------------------------
117+
-- File caching
118+
119+
-- | Performs the @fcntl(2)@ operation on a file-desciptor to get the cache mode.
120+
--
121+
-- If the cache mode is 'False', then cache effects for file system reads and
122+
-- writes are minimised or otherwise eliminated. If the cache mode is 'True',
123+
-- then cache effects occur like normal.
124+
--
125+
-- On Linux, FreeBSD, and NetBSD this checks whether the @O_DIRECT@ file flag is
126+
-- set.
127+
--
128+
-- Throws 'IOError' (\"unsupported operation\") if platform does not support
129+
-- getting the cache mode.
130+
--
131+
-- Use @#if HAVE_O_DIRECT@ CPP guard to detect availability. Use @#include
132+
-- "HsUnix.h"@ to bring @HAVE_O_DIRECT@ into scope.
133+
--
134+
-- @since 2.8.x.y
135+
fileGetCaching :: Fd -> IO Bool
136+
#if HAVE_O_DIRECT
137+
fileGetCaching (Fd fd) = do
138+
r <- throwErrnoIfMinus1 "fileGetCaching" (c_fcntl_read fd #{const F_GETFL})
139+
return ((r .&. opt_val) == 0)
140+
where
141+
opt_val = #{const O_DIRECT}
142+
#else
143+
{-# WARNING fileGetCaching
144+
"operation will throw 'IOError' \"unsupported operation\" (CPP guard: @#if HAVE_O_DIRECT@)" #-}
145+
fileGetCaching _ = ioError (ioeSetLocation unsupportedOperation "fileGetCaching")
146+
#endif
147+
148+
-- | Performs the @fcntl(2)@ operation on a file-desciptor to set the cache
149+
-- mode.
150+
--
151+
-- If the cache mode is 'False', then cache effects for file system reads and
152+
-- writes are minimised or otherwise eliminated. If the cache mode is 'True',
153+
-- then cache effects occur like normal.
154+
--
155+
-- On Linux, FreeBSD, and NetBSD this sets the @O_DIRECT@ file flag. On OSX,
156+
-- this sets the @F_NOCACHE@ @fcntl@ flag.
157+
--
158+
-- Throws 'IOError' (\"unsupported operation\") if platform does not support
159+
-- setting the cache mode.
160+
--
161+
-- Use @#if HAVE_O_DIRECT || HAVE_F_NOCACHE@ CPP guard to detect availability.
162+
-- Use @#include "HsUnix.h"@ to bring @HAVE_O_DIRECT@ and @HAVE_F_NOCACHE@ into
163+
-- scope.
164+
--
165+
-- @since 2.8.x.y
166+
fileSetCaching :: Fd -> Bool -> IO ()
167+
#if HAVE_O_DIRECT
168+
fileSetCaching (Fd fd) val = do
169+
r <- throwErrnoIfMinus1 "fileSetCaching" (c_fcntl_read fd #{const F_GETFL})
170+
let r' | val = fromIntegral r .&. complement opt_val
171+
| otherwise = fromIntegral r .|. opt_val
172+
throwErrnoIfMinus1_ "fileSetCaching" (c_fcntl_write fd #{const F_SETFL} r')
173+
where
174+
opt_val = #{const O_DIRECT}
175+
#elif HAVE_F_NOCACHE
176+
fileSetCaching (Fd fd) val = do
177+
throwErrnoIfMinus1_ "fileSetCaching" (c_fcntl_write fd #{const F_NOCACHE} (if val then 0 else 1))
178+
#else
179+
{-# WARNING fileSetCaching
180+
"operation will throw 'IOError' \"unsupported operation\" (CPP guard: @#if HAVE_O_DIRECT || HAVE_F_NOCACHE @)" #-}
181+
fileSetCaching _ _ = ioError (ioeSetLocation unsupportedOperation "fileSetCaching")
182+
#endif

configure.ac

+28
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,34 @@ AC_EGREP_CPP(yes,
120120
AC_MSG_RESULT(no)
121121
])
122122

123+
AC_MSG_CHECKING(for O_DIRECT open flag)
124+
AC_EGREP_CPP(yes,
125+
[
126+
#include <fcntl.h>
127+
#ifdef O_DIRECT
128+
yes
129+
#endif
130+
], [
131+
AC_MSG_RESULT(yes)
132+
AC_DEFINE([HAVE_O_DIRECT], [1], [Define to 1 if O_DIRECT open flag is available.])
133+
], [
134+
AC_MSG_RESULT(no)
135+
])
136+
137+
AC_MSG_CHECKING(for F_NOCACHE from fcntl.h)
138+
AC_EGREP_CPP(yes,
139+
[
140+
#include <fcntl.h>
141+
#ifdef F_NOCACHE
142+
yes
143+
#endif
144+
], [
145+
AC_MSG_RESULT(yes)
146+
AC_DEFINE([HAVE_F_NOCACHE], [1], [Define to 1 if F_NOCACHE available.])
147+
], [
148+
AC_MSG_RESULT(no)
149+
])
150+
123151
dnl not available on android so check for it
124152
AC_CANONICAL_TARGET
125153
AS_CASE([$target_os],[*-android*],[],[AC_CHECK_FUNCS([telldir seekdir])])

0 commit comments

Comments
 (0)