diff options
author | Chris Wilson <chris+github@qwirx.com> | 2015-04-13 17:59:30 +0000 |
---|---|---|
committer | Chris Wilson <chris+github@qwirx.com> | 2015-04-13 17:59:30 +0000 |
commit | 324243fa90e199012a81bf08b232a9d523ce1fbf (patch) | |
tree | 53672f78e6aa533d02d111a045bfd50de7af8c49 | |
parent | f735627dd3e7c9ef6773afac671b7bf7ec4bf16c (diff) |
Fix file locking on Windows.
NamedLock simply didn't work before. This may cause test failures, but the
tests are already failing on Windows, and must be fixed.
-rw-r--r-- | lib/common/NamedLock.cpp | 39 | ||||
-rw-r--r-- | lib/common/NamedLock.h | 1 | ||||
-rw-r--r-- | test/common/testcommon.cpp | 12 |
3 files changed, 48 insertions, 4 deletions
diff --git a/lib/common/NamedLock.cpp b/lib/common/NamedLock.cpp index 3c2c99dd..fadf4df3 100644 --- a/lib/common/NamedLock.cpp +++ b/lib/common/NamedLock.cpp @@ -73,6 +73,8 @@ bool NamedLock::TryAndGetLock(const std::string& rFilename, int mode) THROW_EXCEPTION(CommonException, NamedLockAlreadyLockingSomething) } + mFileName = rFilename; + // See if the lock can be got #if HAVE_DECL_O_EXLOCK int fd = ::open(rFilename.c_str(), @@ -94,11 +96,28 @@ bool NamedLock::TryAndGetLock(const std::string& rFilename, int mode) return false; #else - int fd = ::open(rFilename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mode); + int flags = O_WRONLY | O_CREAT | O_TRUNC; + +# if !HAVE_DECL_F_SETLK && !defined HAVE_FLOCK + // We have no other way to get a lock, so all we can do is fail if + // the file already exists, and take the risk of stale locks. + flags |= O_EXCL; +# endif + + int fd = ::open(rFilename.c_str(), flags, mode); if(fd == -1) { - THROW_SYS_FILE_ERROR("Failed to open lockfile", rFilename, - CommonException, OSFileError); + if(errno == EEXIST && (flags & O_EXCL)) + { + // Lockfile already exists, and we tried to open it + // exclusively, which means we failed to lock it. + return false; + } + else + { + THROW_SYS_FILE_ERROR("Failed to open lockfile", + rFilename, CommonException, OSFileError); + } } #ifdef HAVE_FLOCK @@ -162,8 +181,20 @@ void NamedLock::ReleaseLock() // Close the file if(::close(mFileDescriptor) != 0) { - THROW_EXCEPTION(CommonException, OSFileError) + THROW_EMU_ERROR( + BOX_FILE_MESSAGE(mFileName, "Failed to close lockfile"), + CommonException, OSFileError); } + + // Delete the file + if(::unlink(mFileName.c_str()) != 0) + { + THROW_EMU_ERROR( + BOX_FILE_MESSAGE(mFileName, + "Failed to delete lockfile"), + CommonException, OSFileError); + } + // Mark as unlocked mFileDescriptor = -1; } diff --git a/lib/common/NamedLock.h b/lib/common/NamedLock.h index 534115db..09f5001a 100644 --- a/lib/common/NamedLock.h +++ b/lib/common/NamedLock.h @@ -35,6 +35,7 @@ public: private: int mFileDescriptor; + std::string mFileName; }; #endif // NAMEDLOCK__H diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 076099ad..fbdf8d9c 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -262,6 +262,18 @@ int test(int argc, const char *argv[]) TEST_THAT(!TestFileExists(tempfile.c_str())); } + // Test that named locks work as expected + { + NamedLock lock1; + TEST_THAT(lock1.TryAndGetLock("testfiles/locktest")); + // With a lock held, we should not be able to acquire another. + TEST_THAT(!NamedLock().TryAndGetLock("testfiles/locktest")); + } + { + // But with the lock released, we should be able to. + TEST_THAT(NamedLock().TryAndGetLock("testfiles/locktest")); + } + // Test that memory leak detection doesn't crash { char *test = new char[1024]; |