Skip to content

Get or set the file caching mode #340

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 79 additions & 3 deletions System/Posix/Fcntl.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,34 @@
-----------------------------------------------------------------------------

#include "HsUnix.h"
#include <fcntl.h>

module System.Posix.Fcntl (
-- * File allocation
Advice(..), fileAdvise,
fileAllocate,
-- * File caching
fileGetCaching,
fileSetCaching,
) where

#if HAVE_POSIX_FALLOCATE || HAVE_POSIX_FADVISE
import Foreign.C
#endif
import System.Posix.Types

#if !HAVE_POSIX_FALLOCATE
#if !HAVE_POSIX_FALLOCATE || !HAVE_O_DIRECT
import System.IO.Error ( ioeSetLocation )
import GHC.IO.Exception ( unsupportedOperation )
#endif

#if HAVE_O_DIRECT
import Data.Bits (complement, (.&.), (.|.))
import System.Posix.Internals (c_fcntl_read)
#endif

#if HAVE_O_DIRECT || HAVE_F_NOCACHE
import System.Posix.Internals (c_fcntl_write)
#endif

-- -----------------------------------------------------------------------------
-- File control

Expand Down Expand Up @@ -101,3 +112,68 @@ foreign import capi safe "fcntl.h posix_fallocate"
fileAllocate _ _ _ = ioError (ioeSetLocation unsupportedOperation
"fileAllocate")
#endif

-- -----------------------------------------------------------------------------
-- File caching

-- | Performs the @fcntl(2)@ operation on a file-desciptor to get the cache mode.
--
-- If the cache mode is 'False', then cache effects for file system reads and
-- writes are minimised or otherwise eliminated. If the cache mode is 'True',
-- then cache effects occur like normal.
--
-- On Linux, FreeBSD, and NetBSD this checks whether the @O_DIRECT@ file flag is
-- set.
--
-- Throws 'IOError' (\"unsupported operation\") if platform does not support
-- reading the cache mode.
--
-- (use @#if HAVE_O_DIRECT@ CPP guard to detect availability).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this macro available to a user though?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be through HsUnix.h

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer the documentation to say so explicitly, otherwise people will be left wondering who defines them.

--
-- @since 2.8.x.y
fileGetCaching :: Fd -> IO Bool
#if HAVE_O_DIRECT
fileGetCaching (Fd fd) = do
r <- throwErrnoIfMinus1 "fileGetCaching" (c_fcntl_read fd #{const F_GETFL})
return ((r .&. opt_val) == 0)
where
opt_val = #{const O_DIRECT}
#else
{-# WARNING fileGetCaching
"operation will throw 'IOError' \"unsupported operation\" (CPP guard: @#if HAVE_O_DIRECT@)" #-}
fileGetCaching _ = ioError (ioeSetLocation unsupportedOperation "fileGetCaching")
#endif

-- | Performs the @fcntl(2)@ operation on a file-desciptor to set the cache
-- mode.
--
-- If the cache mode is 'False', then cache effects for file system reads and
-- writes are minimised or otherwise eliminated. If the cache mode is 'True',
-- then cache effects occur like normal.
--
-- On Linux, FreeBSD, and NetBSD this sets the @O_DIRECT@ file flag. On OSX,
-- this sets the @F_NOCACHE@ @fcntl@ flag.
--
-- Throws 'IOError' (\"unsupported operation\") if platform does not support
-- reading the cache mode.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading or writing?

--
-- (use @#if HAVE_O_DIRECT || HAVE_F_NOCACHE@ CPP guard to detect availability).
--
-- @since 2.8.x.y
fileSetCaching :: Fd -> Bool -> IO ()
#if HAVE_O_DIRECT
fileSetCaching (Fd fd) val = do
r <- throwErrnoIfMinus1 "fileSetCaching" (c_fcntl_read fd #{const F_GETFL})
let r' | val = fromIntegral r .&. complement opt_val
| otherwise = fromIntegral r .|. opt_val
throwErrnoIfMinus1_ "fileSetCaching" (c_fcntl_write fd #{const F_SETFL} r')
where
opt_val = #{const O_DIRECT}
#elif HAVE_F_NOCACHE
fileSetCaching (Fd fd) val = do
throwErrnoIfMinus1_ "fileSetCaching" (c_fcntl_write fd #{const F_NOCACHE} (if val then 0 else 1))
#else
{-# WARNING fileSetCaching
"operation will throw 'IOError' \"unsupported operation\" (CPP guard: @#if HAVE_O_DIRECT || HAVE_F_NOCACHE @)" #-}
fileSetCaching _ _ = ioError (ioeSetLocation unsupportedOperation "fileSetCaching")
#endif
28 changes: 28 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,34 @@ AC_EGREP_CPP(yes,
AC_MSG_RESULT(no)
])

AC_MSG_CHECKING(for O_DIRECT open flag)
AC_EGREP_CPP(yes,
[
#include <fcntl.h>
#ifdef O_DIRECT
yes
#endif
], [
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_O_DIRECT], [1], [Define to 1 if O_DIRECT open flag is available.])
], [
AC_MSG_RESULT(no)
])

AC_MSG_CHECKING(for F_NOCACHE from fcntl.h)
AC_EGREP_CPP(yes,
[
#include <fcntl.h>
#ifdef F_NOCACHE
yes
#endif
], [
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_F_NOCACHE], [1], [Define to 1 if F_NOCACHE available.])
], [
AC_MSG_RESULT(no)
])

dnl not available on android so check for it
AC_CANONICAL_TARGET
AS_CASE([$target_os],[*-android*],[],[AC_CHECK_FUNCS([telldir seekdir])])
Expand Down