Permalink
Browse files

Add exclusive file_share option

  • Loading branch information...
1 parent 2275d84 commit 23380eec2a6e8a6969dcf0b3c6190936a7e582f7 @mturk mturk committed Apr 21, 2012
View
1 modules/ashiaro-common-native/src/main/native/include/acu/darwin
@@ -110,5 +110,6 @@
#define HAVE_SOCK_CLOEXEC 0
#define HAVE_O_CLOEXEC 0
#define HAVE_WRITEV 1
+#define HAVE_FCNTL_LOCK 1
#endif /* _ACU_DARWIN_H */
View
36 modules/ashiaro-common-native/src/main/native/include/acu/file.h
@@ -104,13 +104,18 @@ ACU_END_ENUM
ACU_BEGIN_ENUM(file_share)
- none = 0, /**< No sharing.
+ none = 0, /**< No sharing protection.
This flag is valid only for file share mode */
read = 1, /**< Read lock. It prevents
writers from establishing an
- exclusive lock. */
- write = 2, /**< Write lock. */
- rw = 3 /**< Convinience for Read | Write */
+ exclusive lock. If specified files requesting write
+ operation will fail */
+ write = 2, /**< Write lock. Another open will success for both read and
+ write oprations. */
+ exclusive = 3 /**< Exclusive lock.
+ All successive open requests will fail until this
+ file is closed. Note that this is guarantee on windows
+ and on other systems only if our open method is used. */
ACU_END_ENUM
@@ -320,7 +325,7 @@ struct file_stream
int _blksize; /**< stat.st_blksize (may be != _bf._size) */
int _timeout; /**< timeout in milliseconds */
int _type; /**< cached file type */
- int _orientation; /**< orientation for fwide() */
+ int _fl_count; /**< recursive file lock count */
acu_off_t _offset; /**< current lseek offset */
mutex *_mutex; /**< used for MT-safety */
/* Public low-level api */
@@ -334,12 +339,6 @@ struct file_stream
const file_share& shr_ = file_share::read,
const file_options& opts_ = file_options::no_inherit,
const file_permissions& perms_ = file_permissions::os_default);
- static file_stream *open(fd_t fd_,
- const file_access& acc_ = file_access::read,
- const file_mode& mode_ = file_mode::open_existing,
- const file_share& shr_ = file_share::read,
- const file_options& opts_ = file_options::no_inherit,
- const file_permissions& perms_ = file_permissions::os_default);
/**
* Opens a file_stream.
* Uses extended stdio fopen mode.
@@ -375,14 +374,21 @@ struct file_stream
* N+ Turn on non-blocking mode.
* I- Turn off file inheritance. File will not be inherited by child process.
* C- Do not close os descriptor on close().
- *
+ * X+ Open and lock exclusively. This flag will put advisory lock and prevent
+ * further open operations until this file is closed.
*/
static file_stream *open(const path& path_,
const char *mode_,
const file_permissions& perms_ = file_permissions::os_default);
- static file_stream *open(fd_t fd_,
- const char *mode_,
- const file_permissions& perms_ = file_permissions::os_default);
+ static file_stream *fdopen(fd_t fd_,
+ const file_access& acc_ = file_access::read,
+ const file_mode& mode_ = file_mode::open_existing,
+ const file_share& shr_ = file_share::read,
+ const file_options& opts_ = file_options::no_inherit,
+ const file_permissions& perms_ = file_permissions::os_default);
+ static file_stream *fdopen(fd_t fd_,
+ const char *mode_,
+ const file_permissions& perms_ = file_permissions::os_default);
static int close(file_stream *fs_);
static int sync(file_stream *fs_, bool sync_meta_ = false);
View
2 modules/ashiaro-common-native/src/main/native/include/acu/io.h
@@ -39,7 +39,7 @@ typedef int socket_t;
# define __ERRFD -1
#endif
-#define ACU_FILE_BUFFERSIZE 4096 /**< Default file buffer size */
+#define ACU_FILE_BUFFERSIZE 1024 /**< Default file buffer size */
ACU_BEGIN_NAMESPACE
ACU_BEGIN_IO_NS
View
1 modules/ashiaro-common-native/src/main/native/include/acu/linux
@@ -106,5 +106,6 @@
#define HAVE_SOCK_CLOEXEC 1
#define HAVE_O_CLOEXEC 1
#define HAVE_WRITEV 1
+#define HAVE_FCNTL_LOCK 1
#endif /* _ACU_LINUX_H */
View
1 modules/ashiaro-common-native/src/main/native/include/acu/solaris
@@ -99,6 +99,7 @@
#define HAVE_SOCK_CLOEXEC 0
#define HAVE_O_CLOEXEC 0
#define HAVE_WRITEV 1
+#define HAVE_FCNTL_LOCK 1
#define DT_UNKNOWN 0
#define DT_FIFO 1
View
25 modules/ashiaro-common-native/src/main/native/shared/fileioc.cc
@@ -39,14 +39,6 @@
(fp)->_lb_base = 0; \
}
-/*
- * Set the orientation for a stream. If o > 0, the stream has wide-
- * orientation. If o < 0, the stream has byte-orientation.
- */
-#define ORIENT(fp, o) \
- if ((fp)->_orientation == 0) \
- (fp)->_orientation = (o)
-
#define POS_ERR (-ACU_I64_C(1))
/* Forward declarations
@@ -153,7 +145,6 @@ __prepwrite(file_stream *fp)
static int
__srsetup(file_stream *fp)
{
- ORIENT(fp, -1);
fp->_r = 0;
/* SysV does not make this test; take it out for compatibility */
@@ -278,7 +269,7 @@ __slbexpand(file_stream *fp, int newsize)
}
static file_stream*
-__fsopen(const path& path_, fd_t desc_, const char *mode_,
+__fsopen(const path& path_, fd_t fd_, const char *mode_,
const file_permissions& perms_)
{
int a = 0;
@@ -333,6 +324,12 @@ __fsopen(const path& path_, fd_t desc_, const char *mode_,
int f = 0;
int c = *mode_++;
bool d = *mode_ == '-';
+ if (c == 'X') {
+ s = d ? file_share::none : file_share::exclusive;
+ if (*mode_ == '+' || *mode_ == '-')
+ mode_++;
+ continue;
+ }
/* Check for extra flags */
switch (c) {
case 'B':
@@ -367,8 +364,8 @@ __fsopen(const path& path_, fd_t desc_, const char *mode_,
if (*mode_ == '+' || *mode_ == '-')
mode_++;
}
- if (desc_ != __ERRFD)
- return file_stream::open(desc_, a, m, s, o, perms_);
+ if (fd_ != __ERRFD)
+ return file_stream::fdopen(fd_, a, m, s, o, perms_);
else
return file_stream::open(path_, a, m, s, o, perms_);
}
@@ -381,8 +378,8 @@ file_stream::open(const path& path_, const char *mode_,
}
file_stream *
-file_stream::open(fd_t desc_, const char *mode_,
- const file_permissions& perms_)
+file_stream::fdopen(fd_t desc_, const char *mode_,
+ const file_permissions& perms_)
{
return __fsopen(null_value<path>(), desc_, mode_, perms_);
}
View
14 modules/ashiaro-common-native/src/main/native/shared/fileioi.cc
@@ -86,9 +86,6 @@ __swrchr(file_stream *fp, int c)
if (__prepwrite(fp))
return -1;
b = static_cast<byte>(c);
- /* Orient for writting */
- ORIENT(fp, -1);
-
/*
* If it is completely full, flush it out. Then, in any case,
* stuff c into the buffer. If this causes the buffer to fill
@@ -577,7 +574,6 @@ __fread(file_stream *fp, void *buf, size_t size)
*/
resid = static_cast<int>(size);
p = reinterpret_cast<char *>(buf);
- ORIENT(fp, -1);
if (fp->_r < 0)
fp->_r = 0;
total = resid;
@@ -941,7 +937,6 @@ __sgetln(file_stream *fp)
int len;
int off;
- ORIENT(fp, -1);
/* make sure there is input */
if (fp->_r <= 0 && __srefill(fp))
return 0;
@@ -1394,7 +1389,6 @@ file_stream::write(file_stream *fp, const void *buf, size_t size)
n = static_cast<int>(size);
_mt_file_enter(fp);
- ORIENT(fp, -1);
n = __sfwrite(fp, buf, n);
_mt_file_leave(fp);
return n;
@@ -1418,7 +1412,6 @@ file_stream::write(file_stream *fp, const char *s)
if (IS_EMPTY_STR(s))
return 0;
_mt_file_enter(fp);
- ORIENT(fp, -1);
ret = __sfwrite(fp, s, static_cast<int>(::strlen(s)));
_mt_file_leave(fp);
return ret;
@@ -1455,7 +1448,6 @@ file_stream::writev(file_stream *fp, const struct iovec *iov, int iovcnt)
uio.uio_resid = n;
_mt_file_enter(fp);
- ORIENT(fp, -1);
if (__sfvwrite(fp, &uio) != 0)
n = n - uio.uio_resid;
_mt_file_leave(fp);
@@ -1475,7 +1467,6 @@ file_stream::vprintf(file_stream *fp, const char *fmt, va_list ap)
return -1;
}
_mt_file_enter(fp);
- ORIENT(fp, -1);
n = __vprintf(fp, fmt, ap);
_mt_file_leave(fp);
return n;
@@ -1492,9 +1483,7 @@ file_stream::fprintf(file_stream *fp, const char *fmt, ...)
return -1;
}
_mt_file_enter(fp);
- ORIENT(fp, -1);
va_start(ap, fmt);
-
n = __vprintf(fp, fmt, ap);
va_end(ap);
_mt_file_leave(fp);
@@ -1528,7 +1517,6 @@ file_stream::ungetc(file_stream *fp, int ch_)
{
int ret;
_mt_file_enter(fp);
- ORIENT(fp, -1);
ret = __ungetc(fp, ch_);
_mt_file_leave(fp);
return ret;
@@ -1554,8 +1542,6 @@ file_stream::getdelim(file_stream *fp, char **linep, int *linecapp, int delim)
int nolncap = 0;
_mt_file_enter(fp);
- ORIENT(fp, -1);
-
if (linep == 0) {
ACU_SET_OS_ERROR(ACU_EINVAL);
goto error;
View
100 modules/ashiaro-common-native/src/main/native/unix/fileio.cc
@@ -27,6 +27,80 @@
ACU_BEGIN_NAMESPACE
#include "shared/fileioc.cc"
+static int
+__fdlock(int fd, int type)
+{
+
+ int rc;
+#if HAVE_FCNTL_LOCK
+ struct flock l = { 0 };
+ int fc;
+
+ l.l_whence = SEEK_SET; /* lock from current point */
+ l.l_start = 0; /* begin lock at this offset */
+ l.l_len = 0; /* lock to end of file */
+ if (type & O_EXCL)
+ l.l_type = F_WRLCK;
+ else
+ l.l_type = F_RDLCK;
+
+ fc = (type & O_NONBLOCK) ? F_SETLK : F_SETLKW;
+
+ /* keep trying if fcntl() gets interrupted (by a signal)
+ */
+ RESTARTABLE_CALL(rc, ::fcntl(fd, fc, &l));
+ if (rc == EACCES) {
+ /* on some Unix boxes (e.g., Tru64), we get EACCES instead
+ * of EAGAIN; we don't want APR_STATUS_IS_EAGAIN() matching EACCES
+ * since that breaks other things, so fix up the retcode here
+ */
+ rc = EAGAIN;
+ }
+#else
+ int ltype;
+
+ if (type & O_EXCL)
+ ltype = LOCK_EX;
+ else
+ ltype = LOCK_SH;
+ if (type & O_NONBLOCK)
+ ltype |= LOCK_NB;
+
+ /* keep trying if flock() gets interrupted (by a signal) */
+ RESTARTABLE_CALL(rc, ::flock(fd, ltype));
+#endif
+ return rc;
+}
+
+static int
+__fdunlock(int fd)
+{
+ int rc;
+
+#if HAVE_FCNTL_LOCK
+ struct flock l = { 0 };
+
+ l.l_whence = SEEK_SET; /* lock from current point */
+ l.l_start = 0; /* begin lock at this offset */
+ l.l_len = 0; /* lock to end of file */
+ l.l_type = F_UNLCK;
+
+ /* keep trying if fcntl() gets interrupted (by a signal) */
+ RESTARTABLE_CALL(rc, ::fcntl(fd, F_SETLKW, &l));
+ if (rc == EACCES) {
+ /* on some Unix boxes (e.g., Tru64), we get EACCES instead
+ * of EAGAIN; we don't want APR_STATUS_IS_EAGAIN() matching EACCES
+ * since that breaks other things, so fix up the retcode here
+ */
+ rc = EAGAIN;
+ }
+#else
+ /* keep trying if flock() gets interrupted (by a signal) */
+ RESTARTABLE_CALL(rc, ::flock(fd, LOCK_UN));
+#endif
+ return rc;
+}
+
static inline int
__oflags(int acc_, int mode_, int opts_, int *oflags, int *fflags)
{
@@ -134,6 +208,11 @@ file_stream::open(const path& path_,
int od = ::open(path_, oflags, mode);
if (od == -1)
return 0;
+ if (shr_ == file_share::exclusive) {
+ if ((rc = __fdlock(od, O_EXCL | O_NONBLOCK)) != 0)
+ goto failed;
+ fflags |= __A_SLCK;
+ }
#ifndef O_CLOEXEC
if (opts_ & file_options::no_inherit) {
if ((rc = set_fd_close_on_exec(od, true)) != 0)
@@ -172,6 +251,8 @@ file_stream::open(const path& path_,
fp->_flags = fflags;
if (fp->_flags & __A_SNBL)
fp->_timeout = -1;
+ if (fp->_flags & __A_SLCK)
+ fp->_fl_count = 1;
return fp;
failed:
@@ -181,12 +262,12 @@ file_stream::open(const path& path_,
}
file_stream*
-file_stream::open(fd_t fd_,
- const file_access& acc_,
- const file_mode& mode_,
- const file_share& shr_,
- const file_options& opts_,
- const file_permissions& perms_)
+file_stream::fdopen(fd_t fd_,
+ const file_access& acc_,
+ const file_mode& mode_,
+ const file_share& shr_,
+ const file_options& opts_,
+ const file_permissions& perms_)
{
int rc = 0;
int oflags = 0;
@@ -211,6 +292,11 @@ file_stream::open(fd_t fd_,
rc = EINVAL;
goto failed;
}
+ if (shr_ == file_share::exclusive) {
+ if ((rc = __fdlock(fd_, O_EXCL | O_NONBLOCK)) != 0)
+ goto failed;
+ fflags |= __A_SLCK;
+ }
#ifndef O_CLOEXEC
if (fdflags & FD_CLOEXEC) {
fflags |= __A_SNOI;
@@ -517,6 +603,8 @@ file_stream::close(file_stream *fp)
__sflush(fp);
acu::swap(fp->_flags, ff);
acu::swap(fp->_file, fd);
+ if (ff & __A_SLCK)
+ __fdunlock(fd);
if (ff & __A_SNOC)
r = 0;
else
View
80 modules/ashiaro-common-native/src/main/native/win32/fileio.cc
@@ -191,13 +191,15 @@ file_stream::open(const path& path_,
break;
case file_share::read:
sflags = FILE_SHARE_READ;
+ fflags |= __A_SLCK;
break;
case file_share::write:
- sflags = FILE_SHARE_WRITE;
- break;
- case file_share::rw:
sflags = FILE_SHARE_READ | FILE_SHARE_WRITE;
break;
+ case file_share::exclusive:
+ sflags = 0;
+ fflags |= __A_SLCK;
+ break;
default:
ACU_SET_OS_ERROR(ACU_EINVAL);
return 0;
@@ -384,17 +386,22 @@ wait_for_io(file_stream *fp, DWORD timeout, DWORD *nbytes)
}
static int
-do_lock_file(file_stream *fp, bool exclusive)
+__sflock(file_stream *fp, bool exclusive)
{
int rc = 0;
DWORD flags = exclusive ? LOCKFILE_EXCLUSIVE_LOCK : LOCKFILE_FAIL_IMMEDIATELY;
+ if (0 != fp->_fl_count++) {
+ /* Already locked by this process.
+ */
+ SetLastError(ACU_EALREADY);
+ return -1;
+ }
if (fp->_flags & __A_SLCK) {
- /* Already locked.
- * We should newer get here cause this call should be
- * protected by a thread mutex.
+ /* We already own write or exclusive lock.
+ * Making another onew is pointless.
*/
- return ACU_EALREADY;
+ return 0;
}
fp->_ow.overlap.Offset = 0;
fp->_ow.overlap.OffsetHigh = 0;
@@ -427,29 +434,43 @@ do_lock_file(file_stream *fp, bool exclusive)
} while (rc == ACU_EINTR);
}
}
- if (rc == 0) {
- /* Set the locked flag */
- fp->_flags |= __A_SLCK;
+ if (rc != 0) {
+ /* Decrement lock counter */
+ fp->_fl_count--;
+ return 0;
+ }
+ else {
+ SetLastError(rc);
+ return -1;
}
- return rc;
}
static int
-do_unlk_file(file_stream *fp)
+__sfunlock(file_stream *fp)
{
- int rc = 0;
OVERLAPPED opp;
- if ((fp->_flags & __A_SLCK) == 0) {
- /* Nothing to do if not locked.
+ if (--fp->_fl_count != 0) {
+ /* Nothing to do if still locked.
+ */
+ if (fp->_fl_count < 0) {
+ /* unmatched unlock count */
+ SetLastError(ACU_EDEADLK);
+ fp->_fl_count = 0;
+ return -1;
+ }
+ return 0;
+ }
+ if (fp->_flags & __A_SLCK) {
+ /* File wasn't really locked
*/
return 0;
}
memset(&opp, 0, sizeof(OVERLAPPED));
if (::UnlockFileEx(fp->_fh, 0, UINT_MAX, UINT_MAX, &opp) == 0)
- rc = ::GetLastError();
- fp->_flags &= ~__A_SLCK;
- return rc;
+ return -1;
+ else
+ return 0;
}
static inline acu_off_t
@@ -483,6 +504,7 @@ __sfsopt(file_stream *fp)
static int
__swhatbuf(file_stream *fp, int *bufsize, int *couldbetty)
{
+ *couldbetty = 0;
if (IS_INVALID_HANDLE(fp->_fh))
goto snpt;
if (fp->_type == 0) {
@@ -491,12 +513,12 @@ __swhatbuf(file_stream *fp, int *bufsize, int *couldbetty)
}
/* could be a tty iff it is a character device */
*couldbetty = fp->_type == FILE_TYPE_CHAR;
- fp->_blksize = os::pagesize();
- *bufsize = fp->_blksize;
- return fp->_type == FILE_TYPE_DISK ? __A_SOPT : __A_SNPT;
+ if (fp->_type == FILE_TYPE_DISK) {
+ *bufsize = fp->_blksize = os::pagesize();
+ return __A_SOPT;
+ }
snpt:
- *couldbetty = 0;
- *bufsize = ACU_FS_BUFSIZ;
+ *bufsize = fp->_blksize = ACU_FS_BUFSIZ;
return __A_SNPT;
}
@@ -581,16 +603,14 @@ __swrite(file_stream *fp, const void *buf, int n)
LPOVERLAPPED op = 0;
if (fp->_flags & __A_SAPP) {
- /* _do_lock_file will mutex the file across processes.
+ /* ___sflock will mutex the file across processes.
*/
- if ((rc = do_lock_file(fp, true)) != 0) {
- ACU_SET_OS_ERROR(rc);
+ if (__sflock(fp, true))
return -1;
- }
/* Set the position to the file end
*/
if (__sseek(fp, 0, SEEK_END) == POS_ERR && (fp->_flags & __A_SOPT) != 0) {
- ACU_ERROR_SAVED(do_unlk_file(fp));
+ ACU_ERROR_SAVED(__sfunlock(fp));
return -1;
}
}
@@ -609,7 +629,7 @@ __swrite(file_stream *fp, const void *buf, int n)
break;
}
}
- do_unlk_file(fp);
+ __sfunlock(fp);
if (rc != 0) {
fp->_flags &= ~__A_SOFF;
return -1;
View
16 modules/ashiaro-common-native/src/test/native/testfile.cc
@@ -138,13 +138,13 @@ __UNIT(file)
#else
fd_t fd = 1;
#endif
- file_stream *fp = file_stream::open(fd,
- file_access::write,
- file_mode::open_existing,
- file_share::read,
- file_options::no_inherit |
- file_options::no_close |
- file_options::buffered);
+ file_stream *fp = file_stream::fdopen(fd,
+ file_access::write,
+ file_mode::open_existing,
+ file_share::read,
+ file_options::no_inherit |
+ file_options::no_close |
+ file_options::buffered);
__ASSERT_NOTNULL(fp);
__ASSERT_EQUALS(32, file_stream::write(fp, "file -> stdout (7) : SUCCESS\n"));
__ASSERT_EQUALS(0, file_stream::close(fp));
@@ -157,7 +157,7 @@ __UNIT(file)
#else
fd_t fd = 1;
#endif
- file_stream *fp = file_stream::open(fd, "w,B C-");
+ file_stream *fp = file_stream::fdopen(fd, "w,B C-");
__ASSERT_NOTNULL(fp);
__ASSERT_EQUALS(32, file_stream::write(fp, "file -> stdout (8) : SUCCESS\n"));
__ASSERT_EQUALS(0, file_stream::close(fp));

0 comments on commit 23380ee

Please sign in to comment.