According to the documentation, the Haskell implementation of Handle
should implement single writer/multiple readers locking but the current
implementation doesn't work under Windows. This commit fixes this using
'_sopen' function instead of 'open'. The former allows to implement system
level locking on Windows. The changes doesn't affect other platforms.
fillReadBuffer, fillReadBufferWithoutBlocking,
readRawBuffer, readRawBufferPtr,
writeRawBuffer, writeRawBufferPtr,
fillReadBuffer, fillReadBufferWithoutBlocking,
readRawBuffer, readRawBufferPtr,
writeRawBuffer, writeRawBufferPtr,
+
+#ifndef mingw32_TARGET_OS
ioe_closedHandle, ioe_EOF, ioe_notReadable, ioe_notWritable,
stdin, stdout, stderr,
ioe_closedHandle, ioe_EOF, ioe_notReadable, ioe_notWritable,
stdin, stdout, stderr,
ReadWriteMode -> rw_flags
AppendMode -> append_flags
ReadWriteMode -> rw_flags
AppendMode -> append_flags
- truncate | WriteMode <- mode = True
- | otherwise = False
-
binary_flags
| binary = o_BINARY
| otherwise = 0
binary_flags
| binary = o_BINARY
| otherwise = 0
throwErrnoIfMinus1Retry "openFile"
(c_open f (fromIntegral oflags) 0o666)
throwErrnoIfMinus1Retry "openFile"
(c_open f (fromIntegral oflags) 0o666)
- openFd fd Nothing False filepath mode binary truncate
+ openFd fd Nothing False filepath mode binary
`catchException` \e -> do c_close (fromIntegral fd); throw e
-- NB. don't forget to close the FD if openFd fails, otherwise
-- this FD leaks.
`catchException` \e -> do c_close (fromIntegral fd); throw e
-- NB. don't forget to close the FD if openFd fails, otherwise
-- this FD leaks.
std_flags = o_NONBLOCK .|. o_NOCTTY
output_flags = std_flags .|. o_CREAT
read_flags = std_flags .|. o_RDONLY
std_flags = o_NONBLOCK .|. o_NOCTTY
output_flags = std_flags .|. o_CREAT
read_flags = std_flags .|. o_RDONLY
-write_flags = output_flags .|. o_WRONLY
+write_flags = output_flags .|. o_WRONLY .|. o_TRUNC
rw_flags = output_flags .|. o_RDWR
append_flags = write_flags .|. o_APPEND
-- ---------------------------------------------------------------------------
-- openFd
rw_flags = output_flags .|. o_RDWR
append_flags = write_flags .|. o_APPEND
-- ---------------------------------------------------------------------------
-- openFd
-openFd :: FD -> Maybe FDType -> Bool -> FilePath -> IOMode -> Bool -> Bool -> IO Handle
-openFd fd mb_fd_type is_socket filepath mode binary truncate = do
+openFd :: FD -> Maybe FDType -> Bool -> FilePath -> IOMode -> Bool -> IO Handle
+openFd fd mb_fd_type is_socket filepath mode binary = do
-- turn on non-blocking mode
setNonBlockingFD fd
-- turn on non-blocking mode
setNonBlockingFD fd
-- regular files need to be locked
RegularFile -> do
-- regular files need to be locked
RegularFile -> do
+#ifndef mingw32_TARGET_OS
r <- lockFile (fromIntegral fd) (fromBool write) 1{-exclusive-}
when (r == -1) $
ioException (IOError Nothing ResourceBusy "openFile"
"file is locked" Nothing)
r <- lockFile (fromIntegral fd) (fromBool write) 1{-exclusive-}
when (r == -1) $
ioException (IOError Nothing ResourceBusy "openFile"
"file is locked" Nothing)
-
- -- truncate the file if necessary
- when truncate (fileTruncate filepath)
-
mkFileHandle fd is_socket filepath ha_type binary
mkFileHandle fd is_socket filepath ha_type binary
fdToHandle fd = do
mode <- fdGetMode fd
let fd_str = "<file descriptor: " ++ show fd ++ ">"
fdToHandle fd = do
mode <- fdGetMode fd
let fd_str = "<file descriptor: " ++ show fd ++ ">"
- openFd fd Nothing False{-XXX!-} fd_str mode True{-bin mode-} False{-no truncate-}
+ openFd fd Nothing False{-XXX!-} fd_str mode True{-bin mode-}
+
+#ifndef mingw32_TARGET_OS
foreign import ccall unsafe "lockFile"
lockFile :: CInt -> CInt -> CInt -> IO CInt
foreign import ccall unsafe "unlockFile"
unlockFile :: CInt -> IO CInt
foreign import ccall unsafe "lockFile"
lockFile :: CInt -> CInt -> CInt -> IO CInt
foreign import ccall unsafe "unlockFile"
unlockFile :: CInt -> IO CInt
mkStdHandle :: FD -> FilePath -> HandleType -> IORef Buffer -> BufferMode
-> IO Handle
mkStdHandle :: FD -> FilePath -> HandleType -> IORef Buffer -> BufferMode
-> IO Handle
-- free the spare buffers
writeIORef (haBuffers handle_) BufferListNil
-- free the spare buffers
writeIORef (haBuffers handle_) BufferListNil
+#ifndef mingw32_TARGET_OS
-- unlock it
unlockFile c_fd
-- unlock it
unlockFile c_fd
-- we must set the fd to -1, because the finalizer is going
-- to run eventually and try to close/unlock it.
return (handle_{ haFD = -1,
-- we must set the fd to -1, because the finalizer is going
-- to run eventually and try to close/unlock it.
return (handle_{ haFD = -1,
ioe_unknownfiletype = IOError Nothing UnsupportedOperation "fdType"
"unknown file type" Nothing
ioe_unknownfiletype = IOError Nothing UnsupportedOperation "fdType"
"unknown file type" Nothing
--- It isn't clear whether ftruncate is POSIX or not (I've read several
--- manpages and they seem to conflict), so we truncate using open/2.
-fileTruncate :: FilePath -> IO ()
-fileTruncate file = do
- let flags = o_WRONLY .|. o_TRUNC
- withCString file $ \file_cstr -> do
- fd <- fromIntegral `liftM`
- throwErrnoIfMinus1Retry "fileTruncate"
- (c_open file_cstr (fromIntegral flags) 0o666)
- c_close fd
- return ()
-
#if defined(mingw32_TARGET_OS) || defined(__MINGW32__)
closeFd :: Bool -> CInt -> IO CInt
closeFd isStream fd
#if defined(mingw32_TARGET_OS) || defined(__MINGW32__)
closeFd :: Bool -> CInt -> IO CInt
closeFd isStream fd
fd <- peek pfd
openFd fd (Just Stream)
False{-not a socket-}
fd <- peek pfd
openFd fd (Just Stream)
False{-not a socket-}
- ("fd:" ++ show fd) mode True{-binary-} False{-no truncate-}
+ ("fd:" ++ show fd) mode True{-binary-}
-- ----------------------------------------------------------------------------
-- waitForProcess
-- ----------------------------------------------------------------------------
-- waitForProcess
* (c) The GRASP/AQUA Project, Glasgow University, 1994-2004
*
* (c) The GRASP/AQUA Project, Glasgow University, 1994-2004
*
- * $Id: lockFile.c,v 1.3 2004/06/02 12:35:11 simonmar Exp $
+ * $Id: lockFile.c,v 1.4 2005/01/01 23:59:59 krasimir Exp $
*
* stdin/stout/stderr Runtime Support
*/
*
* stdin/stout/stderr Runtime Support
*/
+#ifndef mingw32_TARGET_OS
+
#include "HsBase.h"
#include "Rts.h"
#include "../../ghc/rts/RtsUtils.h" // for barf()
#include "HsBase.h"
#include "Rts.h"
#include "../../ghc/rts/RtsUtils.h" // for barf()
-#ifdef mingw32_TARGET_OS
- // The Win32 C runtime has a max of 2048 file descriptors (see
- // _NHANDLE_ in the crt sources), but mingw defines FD_SETSIZE to
- // 64.
-# define NUM_FDS 2048
-#else
-# ifndef FD_SETSIZE
-# error No FD_SETSIZE defined!
-# else
-# define NUM_FDS FD_SETSIZE
-# endif
-#endif
-
typedef struct {
dev_t device;
ino_t inode;
int fd;
} Lock;
typedef struct {
dev_t device;
ino_t inode;
int fd;
} Lock;
-static Lock readLock[NUM_FDS];
-static Lock writeLock[NUM_FDS];
+static Lock readLock[FD_SETSIZE];
+static Lock writeLock[FD_SETSIZE];
static int readLocks = 0;
static int writeLocks = 0;
static int readLocks = 0;
static int writeLocks = 0;
barf("lockFile: fd out of range");
}
while (fstat(fd, &sb) < 0) {
barf("lockFile: fd out of range");
}
while (fstat(fd, &sb) < 0) {
- if (errno != EINTR) {
-#ifndef _WIN32
-#else
- /* fstat()ing socket fd's seems to fail with CRT's fstat(),
- so let's just silently return and hope for the best..
- */
- return 0;
-#endif
- }
}
if (for_writing) {
/* opening a file for writing, check to see whether
we don't have any read locks on it already.. */
for (i = 0; i < readLocks; i++) {
}
if (for_writing) {
/* opening a file for writing, check to see whether
we don't have any read locks on it already.. */
for (i = 0; i < readLocks; i++) {
- if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
-#ifndef __MINGW32__
+ if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev)
-#else
- break;
-#endif
- }
}
/* If we're determined that there is only a single
writer to the file, check to see whether the file
}
/* If we're determined that there is only a single
writer to the file, check to see whether the file
if (exclusive) {
for (i = 0; i < writeLocks; i++) {
if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
if (exclusive) {
for (i = 0; i < writeLocks; i++) {
if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
writeLock[i].inode = sb.st_ino;
writeLock[i].fd = fd;
return 0;
writeLock[i].inode = sb.st_ino;
writeLock[i].fd = fd;
return 0;
/* For reading, it's simpler - just check to see
that there's no-one writing to the underlying file. */
for (i = 0; i < writeLocks; i++) {
/* For reading, it's simpler - just check to see
that there's no-one writing to the underlying file. */
for (i = 0; i < writeLocks; i++) {
- if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
-#ifndef __MINGW32__
+ if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev)
-#else
- break;
-#endif
- }
}
/* Fit in new entry, reusing an existing table entry, if possible. */
for (i = 0; i < readLocks; i++) {
}
/* Fit in new entry, reusing an existing table entry, if possible. */
for (i = 0; i < readLocks; i++) {
/* Signal that we did not find an entry */
return 1;
}
/* Signal that we did not find an entry */
return 1;
}
#include <fcntl.h>
#include "timeUtils.h"
#include <shlobj.h>
#include <fcntl.h>
#include "timeUtils.h"
#include <shlobj.h>
#endif
#if HAVE_SYS_SELECT_H
#endif
#if HAVE_SYS_SELECT_H
#endif /* mingw32_TARGET_OS */
#endif /* mingw32_TARGET_OS */
+INLINE int __hscore_open(char *file, int how, mode_t mode) {
+#ifdef mingw32_TARGET_OS
+ if ((how & O_WRONLY) || (how & O_RDWR) || (how & O_APPEND))
+ return _sopen(file,how,_SH_DENYRW,mode);
+ else
+ return _sopen(file,how,_SH_DENYWR,mode);
+#else
+ return open(file,how,mode);
+#endif
+}
+
// These are wrapped because on some OSs (eg. Linux) they are
// macros which redirect to the 64-bit-off_t versions when large file
// support is enabled.
//
// These are wrapped because on some OSs (eg. Linux) they are
// macros which redirect to the 64-bit-off_t versions when large file
// support is enabled.
//
-INLINE int __hscore_open(char *file, int how, mode_t mode) {
- return (open(file,how,mode));
-}
-
INLINE off_t __hscore_lseek(int fd, off_t off, int whence) {
return (lseek(fd,off,whence));
}
INLINE off_t __hscore_lseek(int fd, off_t off, int whence) {
return (lseek(fd,off,whence));
}
INLINE HsInt sizeofTimeVal(void) { return sizeof(struct timeval); }
INLINE HsInt getTicksOfDay(void)
INLINE HsInt sizeofTimeVal(void) { return sizeof(struct timeval); }
INLINE HsInt getTicksOfDay(void)
struct timeval tv;
gettimeofday(&tv, (struct timezone *) NULL);
return (tv.tv_sec * TICK_FREQ +
struct timeval tv;
gettimeofday(&tv, (struct timezone *) NULL);
return (tv.tv_sec * TICK_FREQ +
* (c) The University of Glasgow 2001
*
* (c) The University of Glasgow 2001
*
- * $Id: lockFile.h,v 1.1 2001/06/28 14:15:04 simonmar Exp $
+ * $Id: lockFile.h,v 1.2 2005/01/02 00:00:00 krasimir Exp $
+#ifndef mingw32_TARGET_OS
+
int lockFile(int fd, int for_writing, int exclusive);
int unlockFile(int fd);
int lockFile(int fd, int for_writing, int exclusive);
int unlockFile(int fd);