From 4414365ab25a0c8359578c9d43d319c3d2ad03e7 Mon Sep 17 00:00:00 2001 From: Alexander B Date: Mon, 16 Sep 2024 16:20:42 +0300 Subject: [PATCH 01/10] add RWLock implementation for file [posix] --- Foundation/include/Poco/FileStreamRWLock.h | 196 +++++++++++++++ .../include/Poco/FileStreamRWLock_POSIX.h | 115 +++++++++ Foundation/src/FileStreamRWLock.cpp | 39 +++ Foundation/src/FileStreamRWLock_POSIX.cpp | 36 +++ .../testsuite/src/FileStreamRWLockTest.cpp | 234 ++++++++++++++++++ .../testsuite/src/FileStreamRWLockTest.h | 39 +++ Foundation/testsuite/src/TestApp.cpp | 139 +++++++++++ .../testsuite/src/ThreadingTestSuite.cpp | 2 + 8 files changed, 800 insertions(+) create mode 100644 Foundation/include/Poco/FileStreamRWLock.h create mode 100644 Foundation/include/Poco/FileStreamRWLock_POSIX.h create mode 100644 Foundation/src/FileStreamRWLock.cpp create mode 100644 Foundation/src/FileStreamRWLock_POSIX.cpp create mode 100644 Foundation/testsuite/src/FileStreamRWLockTest.cpp create mode 100644 Foundation/testsuite/src/FileStreamRWLockTest.h diff --git a/Foundation/include/Poco/FileStreamRWLock.h b/Foundation/include/Poco/FileStreamRWLock.h new file mode 100644 index 0000000000..97c31e3ba0 --- /dev/null +++ b/Foundation/include/Poco/FileStreamRWLock.h @@ -0,0 +1,196 @@ +// +// FileStreamRWLock.h +// +// Library: Foundation +// Package: Threading +// Module: FileStreamRWLock +// +// Definition of the FileStreamRWLock class. +// +// Copyright (c) 2004-2024, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Foundation_FileStreamRWLock_INCLUDED +#define Foundation_FileStreamRWLock_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/Exception.h" +#include "Poco/FileStream.h" + + +#if defined(POCO_OS_FAMILY_WINDOWS) +#include "Poco/FileStreamRWLock_WIN32.h" +#else +#include "Poco/FileStreamRWLock_POSIX.h" +#endif + + +namespace Poco { + + +class ScopedFStreamRWLock; +class ScopedFStreamReadRWLock; +class ScopedFStreamWriteRWLock; + + +class Foundation_API FileStreamRWLock: private FileStreamRWLockImpl + /// A reader writer file lock allows multiple concurrent + /// readers or one exclusive writer. +{ +public: + using ScopedLock = ScopedFStreamRWLock; + using ScopedReadLock = ScopedFStreamReadRWLock; + using ScopedWriteLock = ScopedFStreamWriteRWLock; + + FileStreamRWLock(const FileStream &fs, Poco::UInt64 offset, Poco::UInt64 size); + /// Creates the Reader/Writer lock on the file region. + /// offset - from start of the file + /// size - size of the locker region + + ~FileStreamRWLock(); + /// Destroys the Reader/Writer lock on the file region. + + void readLock(); + /// Acquires a read lock. If another thread or process currently holds a write lock, + /// waits until the write lock is released. + + bool tryReadLock(); + /// Tries to acquire a read lock. Immediately returns true if successful, or + /// false if another thread or process currently holds a write lock. + + void writeLock(); + /// Acquires a write lock on the file region. If one or more other threads or processes currently hold + /// locks, waits until all locks are released. + + bool tryWriteLock(); + /// Tries to acquire a write lock on the file region. Immediately returns true if successful, + /// or false if one or more other threads or processes currently hold + /// locks. + + void unlock(); + /// Releases the read or write lock. + +private: + FileStreamRWLock(const FileStreamRWLock&); + FileStreamRWLock& operator = (const FileStreamRWLock&); +}; + + +class Foundation_API ScopedFStreamRWLock + /// A variant of ScopedLock for reader/writer locks. +{ +public: + ScopedFStreamRWLock(FileStreamRWLock& rwl, bool write = false); + ~ScopedFStreamRWLock(); + +private: + FileStreamRWLock& _rwl; + + ScopedFStreamRWLock(); + ScopedFStreamRWLock(const ScopedFStreamRWLock&); + ScopedFStreamRWLock& operator = (const ScopedFStreamRWLock&); +}; + + +class Foundation_API ScopedFStreamReadRWLock : public ScopedFStreamRWLock + /// A variant of ScopedLock for reader locks. +{ +public: + ScopedFStreamReadRWLock(FileStreamRWLock& rwl); + ~ScopedFStreamReadRWLock(); +}; + + +class Foundation_API ScopedFStreamWriteRWLock : public ScopedFStreamRWLock + /// A variant of ScopedLock for writer locks. +{ +public: + ScopedFStreamWriteRWLock(FileStreamRWLock& rwl); + ~ScopedFStreamWriteRWLock(); +}; + + +// +// inlines +// +inline void FileStreamRWLock::readLock() +{ + readLockImpl(); +} + + +inline bool FileStreamRWLock::tryReadLock() +{ + return tryReadLockImpl(); +} + + +inline void FileStreamRWLock::writeLock() +{ + writeLockImpl(); +} + + +inline bool FileStreamRWLock::tryWriteLock() +{ + return tryWriteLockImpl(); +} + + +inline void FileStreamRWLock::unlock() +{ + unlockImpl(); +} + + +inline ScopedFStreamRWLock::ScopedFStreamRWLock(FileStreamRWLock& rwl, bool write): _rwl(rwl) +{ + if (write) + _rwl.writeLock(); + else + _rwl.readLock(); +} + + +inline ScopedFStreamRWLock::~ScopedFStreamRWLock() +{ + try + { + _rwl.unlock(); + } + catch (...) + { + poco_unexpected(); + } +} + + +inline ScopedFStreamReadRWLock::ScopedFStreamReadRWLock(FileStreamRWLock& rwl): ScopedFStreamRWLock(rwl, false) +{ +} + + +inline ScopedFStreamReadRWLock::~ScopedFStreamReadRWLock() +{ +} + + +inline ScopedFStreamWriteRWLock::ScopedFStreamWriteRWLock(FileStreamRWLock& rwl): ScopedFStreamRWLock(rwl, true) +{ +} + + +inline ScopedFStreamWriteRWLock::~ScopedFStreamWriteRWLock() +{ +} + + +} // namespace Poco + + +#endif // Foundation_FileStreamRWLock_INCLUDED diff --git a/Foundation/include/Poco/FileStreamRWLock_POSIX.h b/Foundation/include/Poco/FileStreamRWLock_POSIX.h new file mode 100644 index 0000000000..6b7372732c --- /dev/null +++ b/Foundation/include/Poco/FileStreamRWLock_POSIX.h @@ -0,0 +1,115 @@ +// +// FileStreamRWLock_POSIX.h +// +// Library: Foundation +// Package: Threading +// Module: FileStreamRWLock +// +// Definition of the FileStreamRWLockImpl class for POSIX FileStream. +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Foundation_FileStreamRWLock_POSIX_INCLUDED +#define Foundation_FileStreamRWLock_POSIX_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/Exception.h" +#include "Poco/FileStream.h" +#include +#include + + +namespace Poco { + + +class Foundation_API FileStreamRWLockImpl +{ +protected: + FileStreamRWLockImpl(const FileStream::NativeHandle &fd, Poco::UInt64 offset, Poco::UInt64 size); + ~FileStreamRWLockImpl(); + void readLockImpl(); + bool tryReadLockImpl(); + void writeLockImpl(); + bool tryWriteLockImpl(); + void unlockImpl(); + +private: + FileStream::NativeHandle _fd; + struct flock _flock; + int _lockMode; +}; + + +// +// inlines +// +inline void FileStreamRWLockImpl::readLockImpl() +{ + _flock.l_type = F_RDLCK; + _lockMode = F_SETLKW; + int rc = fcntl(_fd, _lockMode, &_flock); + if (rc == -1 && errno == EDEADLK) + throw SystemException("cannot lock reader lock", errno); +} + + +inline bool FileStreamRWLockImpl::tryReadLockImpl() +{ + _flock.l_type = F_RDLCK; + _lockMode = F_SETLK; + int rc = fcntl(_fd, _lockMode, &_flock); + if (rc == 0) + return true; + else if (errno == EAGAIN || errno == EACCES) + return false; + else + throw SystemException("cannot lock reader lock", errno); + +} + + +inline void FileStreamRWLockImpl::writeLockImpl() +{ + _flock.l_type = F_WRLCK; + _lockMode = F_SETLKW; + int rc = fcntl(_fd, _lockMode, &_flock); + if (rc == -1 && errno == EDEADLK) + throw SystemException("cannot lock writer lock", EDEADLK); +} + + +inline bool FileStreamRWLockImpl::tryWriteLockImpl() +{ + _flock.l_type = F_WRLCK; + _lockMode = F_SETLK; + int rc = fcntl(_fd, _lockMode, &_flock); + if (rc != -1) + return true; + else if (errno == EAGAIN || errno == EACCES) + return false; + else + throw SystemException("cannot lock writer lock", errno); + +} + + +inline void FileStreamRWLockImpl::unlockImpl() +{ + _flock.l_type = F_UNLCK; + _lockMode = F_SETLKW; + int rc = fcntl(_fd, _lockMode, &_flock); + if (rc == -1 && errno == EDEADLK) + throw SystemException("cannot lock writer lock", EDEADLK); +} + + +} // namespace Poco + + +#endif // Foundation_FileStreamRWLock_POSIX_INCLUDED diff --git a/Foundation/src/FileStreamRWLock.cpp b/Foundation/src/FileStreamRWLock.cpp new file mode 100644 index 0000000000..8295992036 --- /dev/null +++ b/Foundation/src/FileStreamRWLock.cpp @@ -0,0 +1,39 @@ +// +// FileStreamRWLock.cpp +// +// Library: Foundation +// Package: Threading +// Module: FileStreamRWLock +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/FileStreamRWLock.h" + + +#if defined(POCO_OS_FAMILY_WINDOWS) +#include "FileStreamRWLock_WIN32.cpp" +#else +#include "FileStreamRWLock_POSIX.cpp" +#endif + + +namespace Poco { + + +FileStreamRWLock::FileStreamRWLock(const FileStream &fs, Poco::UInt64 offset, Poco::UInt64 size) : + FileStreamRWLockImpl(fs.nativeHandle(), offset, size) +{ +} + + +FileStreamRWLock::~FileStreamRWLock() +{ +} + + +} // namespace Poco diff --git a/Foundation/src/FileStreamRWLock_POSIX.cpp b/Foundation/src/FileStreamRWLock_POSIX.cpp new file mode 100644 index 0000000000..86a3441f9b --- /dev/null +++ b/Foundation/src/FileStreamRWLock_POSIX.cpp @@ -0,0 +1,36 @@ +// +// FileStreamRWLock_POSIX.cpp +// +// Library: Foundation +// Package: Threading +// Module: FileStreamRWLock +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/FileStreamRWLock_POSIX.h" + + +namespace Poco { + + +FileStreamRWLockImpl::FileStreamRWLockImpl(const FileStream::NativeHandle &fd, Poco::UInt64 offset, Poco::UInt64 size): + _fd(fd), _lockMode(0) +{ + _flock.l_whence = SEEK_SET; + _flock.l_start = offset; + _flock.l_len = size; + _flock.l_pid = 0; +} + + +FileStreamRWLockImpl::~FileStreamRWLockImpl() +{ +} + + +} // namespace Poco diff --git a/Foundation/testsuite/src/FileStreamRWLockTest.cpp b/Foundation/testsuite/src/FileStreamRWLockTest.cpp new file mode 100644 index 0000000000..0dc28be848 --- /dev/null +++ b/Foundation/testsuite/src/FileStreamRWLockTest.cpp @@ -0,0 +1,234 @@ +// +// FileStreamRWLockTest.cpp +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "FileStreamRWLockTest.h" +#include "CppUnit/TestCaller.h" +#include "CppUnit/TestSuite.h" +#include "Poco/FileStreamRWLock.h" +#include "Poco/FileStream.h" +#include "Poco/TemporaryFile.h" +#include "Poco/Thread.h" +#include "Poco/Runnable.h" +#include "Poco/ProcessRunner.h" +#include "Poco/Path.h" +#include "Poco/Stopwatch.h" + + +using Poco::FileStreamRWLock; +using Poco::Thread; +using Poco::Runnable; +using Poco::FileStream; +using Poco::TemporaryFile; +using Poco::ProcessRunner; +using Poco::Path; +using Poco::Stopwatch; + +class FileStreamRWLockRunnable: public Runnable +{ +public: + FileStreamRWLockRunnable(std::string fileLock): _fileLock(std::move(fileLock)) + { + std::string name("TestApp"); +#if defined(_DEBUG) + Poco::File testapp(name); + if (!testapp.exists()) + { + name += "d"; + } +#endif + _cmd = name; + + } + + void run() override + { + std::string pid = Poco::format("%spid%ld.file", Path::tempHome(), Thread::currentOsTid()); + std::vector args; + args.push_back(std::string("--lock-file=").append(_fileLock)); + args.push_back(std::string("--pidfile=").append(pid)); + ProcessRunner pr(_cmd, args, pid, 0, 10, true); + while (pr.running()) + { + Poco::Thread::sleep(100); + } + int result = pr.result(); + _ok = (result >= 0); + } + + bool ok() const + { + return _ok; + } + +private: + std::string _fileLock; + bool _ok{false}; + std::string _cmd; +}; + + +class FileStreamRWTryLockRunnable: public Runnable +{ +public: + + FileStreamRWTryLockRunnable(std::string fileLock): _fileLock(std::move(fileLock)) + { + std::string name("TestApp"); +#if defined(_DEBUG) + Poco::File testapp(name); + if (!testapp.exists()) + { + name += "d"; + } +#endif + _cmd = name; + + } + + void run() override + { + std::string pid = Poco::format("%spid%ld.file", Path::tempHome(), Thread::currentOsTid()); + std::vector args; + args.push_back(std::string("--trylock-file=").append(_fileLock)); + args.push_back(std::string("--pidfile=").append(pid)); + ProcessRunner pr(_cmd, args, pid, 0, 10, true); + while (pr.running()) + { + Poco::Thread::sleep(100); + } + int result = pr.result(); + _ok = (result >= 0); + } + + bool ok() const + { + return _ok; + } + +private: + std::string _fileLock; + bool _ok{false}; + std::string _cmd; +}; + + +FileStreamRWLockTest::FileStreamRWLockTest(const std::string& name): CppUnit::TestCase(name) +{ +} + + +FileStreamRWLockTest::~FileStreamRWLockTest() +{ +} + + +void FileStreamRWLockTest::testFSLock() +{ + TemporaryFile fl; + FileStream fs(fl.path(), std::ios::out | std::ios::in | std::ios::binary); + Poco::Int32 i32 = 0; + fs.seekp(0, std::ios::beg); + fs.write((const char *)&i32, sizeof(i32)); + fs.flushToDisk(); + + const auto &path = fl.path(); + FileStreamRWLockRunnable r1(path); + FileStreamRWLockRunnable r2(path); + FileStreamRWLockRunnable r3(path); + FileStreamRWLockRunnable r4(path); + FileStreamRWLockRunnable r5(path); + Thread t1; + Thread t2; + Thread t3; + Thread t4; + Thread t5; + t1.start(r1); + t2.start(r2); + t3.start(r3); + t4.start(r4); + t5.start(r5); + t1.join(); + t2.join(); + t3.join(); + t4.join(); + t5.join(); + + fs.seekp(0, std::ios::beg); + fs.read((char *)&i32, sizeof(i32)); + assertEquals(50000, i32); + assertTrue (r1.ok()); + assertTrue (r2.ok()); + assertTrue (r3.ok()); + assertTrue (r4.ok()); + assertTrue (r5.ok()); +} + + +void FileStreamRWLockTest::testFSTryLock() +{ + TemporaryFile fl; + FileStream fs(fl.path(), std::ios::out | std::ios::in | std::ios::binary); + Poco::Int32 i32 = 0; + fs.seekp(0, std::ios::beg); + fs.write((const char *)&i32, sizeof(i32)); + fs.flushToDisk(); + + const auto &path = fl.path(); + FileStreamRWTryLockRunnable r1(path); + FileStreamRWTryLockRunnable r2(path); + FileStreamRWTryLockRunnable r3(path); + FileStreamRWTryLockRunnable r4(path); + FileStreamRWTryLockRunnable r5(path); + Thread t1; + Thread t2; + Thread t3; + Thread t4; + Thread t5; + t1.start(r1); + t2.start(r2); + t3.start(r3); + t4.start(r4); + t5.start(r5); + t1.join(); + t2.join(); + t3.join(); + t4.join(); + t5.join(); + + fs.seekp(0, std::ios::beg); + fs.read((char *)&i32, sizeof(i32)); + assertTrue (i32 == 50000); + assertTrue (r1.ok()); + assertTrue (r2.ok()); + assertTrue (r3.ok()); + assertTrue (r4.ok()); + assertTrue (r5.ok()); +} + + +void FileStreamRWLockTest::setUp() +{ +} + + +void FileStreamRWLockTest::tearDown() +{ +} + + +CppUnit::Test* FileStreamRWLockTest::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FileStreamRWLockTest"); + + CppUnit_addLongTest(pSuite, FileStreamRWLockTest, testFSLock); + CppUnit_addLongTest(pSuite, FileStreamRWLockTest, testFSTryLock); + + return pSuite; +} diff --git a/Foundation/testsuite/src/FileStreamRWLockTest.h b/Foundation/testsuite/src/FileStreamRWLockTest.h new file mode 100644 index 0000000000..86d8421ffc --- /dev/null +++ b/Foundation/testsuite/src/FileStreamRWLockTest.h @@ -0,0 +1,39 @@ +// +// FileStreamRWLockTest.h +// +// Definition of the FileStreamRWLockTest class. +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef FileStreamRWLockTest_INCLUDED +#define FileStreamRWLockTest_INCLUDED + + +#include "Poco/Foundation.h" +#include "CppUnit/TestCase.h" + + +class FileStreamRWLockTest: public CppUnit::TestCase +{ +public: + FileStreamRWLockTest(const std::string& name); + ~FileStreamRWLockTest(); + + void testFSLock(); + void testFSTryLock(); + + void setUp(); + void tearDown(); + + static CppUnit::Test* suite(); + +private: +}; + + +#endif // FileStreamRWLockTest_INCLUDED diff --git a/Foundation/testsuite/src/TestApp.cpp b/Foundation/testsuite/src/TestApp.cpp index ff62cd6f21..8e576c54ee 100644 --- a/Foundation/testsuite/src/TestApp.cpp +++ b/Foundation/testsuite/src/TestApp.cpp @@ -19,6 +19,8 @@ #include #include +#include "Poco/FileStreamRWLock.h" + #if defined(POCO_OS_FAMILY_UNIX) #include "Poco/Thread.h" #include "Poco/Runnable.h" @@ -222,6 +224,143 @@ int main(int argc, char** argv) } } #endif + else if (argc > 2 && arg.find("--lock-file") != std::string::npos && std::string(argv[2]).find("--pidfile") != std::string::npos) + { + std::string pidfArg = std::string(argv[2]); + std::unique_ptr pidF; + size_t equals_pos = pidfArg.find('='); + if (equals_pos != std::string::npos) + { + std::string pidPath = pidfArg.substr(equals_pos + 1); + pidF = std::make_unique(pidPath, true); + } + if (pidF == nullptr) + { + return -1; + } + equals_pos = arg.find('='); + if (equals_pos != std::string::npos) + { + std::string fl = arg.substr(equals_pos + 1); + FileStream fs(fl, std::ios::out | std::ios::in | std::ios::binary); + Poco::Int32 ok = 1; + Poco::Int32 lastCount = 0; + Poco::Int32 counter = 0; + FileStreamRWLock lock(fs, 0, sizeof(counter)); + for (int i = 0; i < 10000; ++i) + { + lock.readLock(); + fs.seekg(0, std::ios::beg); + fs.read((char *)&counter, sizeof(counter)); + lastCount = counter; + for (int k = 0; k < 100; ++k) + { + if (counter != lastCount) ok = -1; + } + lock.unlock(); + lock.writeLock(); + for (int k = 0; k < 100; ++k) + { + counter = 0; + fs.seekg(0, std::ios::beg); + fs.read((char *)&counter, sizeof(counter)); + --counter; + fs.seekp(0, std::ios::beg); + fs.write((char *)&counter, sizeof(counter)); + fs.flushToDisk(); + } + for (int k = 0; k < 100; ++k) + { + fs.seekg(0, std::ios::beg); + fs.read((char *)&counter, sizeof(counter)); + ++counter; + fs.seekp(0, std::ios::beg); + fs.write((char *)&counter, sizeof(counter)); + fs.flushToDisk(); + } + fs.seekg(0, std::ios::beg); + fs.read((char *)&counter, sizeof(counter)); + ++counter; + fs.seekp(0, std::ios::beg); + fs.write((char *)&counter, sizeof(counter)); + fs.flushToDisk(); + if (counter <= lastCount) ok = -1; + lock.unlock(); + } + return ok * counter; + } + return -1; + } + else if (argc > 2 && arg.find("--trylock-file") != std::string::npos && std::string(argv[2]).find("--pidfile") != std::string::npos) + { + std::string pidfArg = std::string(argv[2]); + std::unique_ptr pidF; + size_t equals_pos = pidfArg.find('='); + if (equals_pos != std::string::npos) + { + std::string pidPath = pidfArg.substr(equals_pos + 1); + pidF = std::make_unique(pidPath, true); + } + if (pidF == nullptr) + { + return -1; + } + equals_pos = arg.find('='); + if (equals_pos != std::string::npos) + { + std::string fl = arg.substr(equals_pos + 1); + FileStream fs(fl, std::ios::out | std::ios::in | std::ios::binary); + Poco::Int32 ok = 1; + Poco::Int32 lastCount = 0; + Poco::Int32 counter = 0; + FileStreamRWLock lock(fs, 0, sizeof(counter)); + for (int i = 0; i < 10000; ++i) + { + while (!lock.tryReadLock()) Thread::yield(); + fs.seekg(0, std::ios::beg); + fs.read((char *)&counter, sizeof(counter)); + lastCount = counter; + for (int k = 0; k < 100; ++k) + { + if (counter != lastCount) ok = -1; + Thread::yield(); + } + lock.unlock(); + while (!lock.tryWriteLock()) Thread::yield(); + for (int k = 0; k < 100; ++k) + { + counter = 0; + fs.seekg(0, std::ios::beg); + fs.read((char *)&counter, sizeof(counter)); + --counter; + fs.seekp(0, std::ios::beg); + fs.write((char *)&counter, sizeof(counter)); + fs.flushToDisk(); + Thread::yield(); + } + for (int k = 0; k < 100; ++k) + { + fs.seekg(0, std::ios::beg); + fs.read((char *)&counter, sizeof(counter)); + ++counter; + fs.seekp(0, std::ios::beg); + fs.write((char *)&counter, sizeof(counter)); + fs.flushToDisk(); + Thread::yield(); + } + fs.seekg(0, std::ios::beg); + fs.read((char *)&counter, sizeof(counter)); + ++counter; + fs.seekp(0, std::ios::beg); + fs.write((char *)&counter, sizeof(counter)); + fs.flushToDisk(); + if (counter <= lastCount) ok = -1; + lock.unlock(); + } + return ok * counter; + } + return -1; + } } return argc - 1; } diff --git a/Foundation/testsuite/src/ThreadingTestSuite.cpp b/Foundation/testsuite/src/ThreadingTestSuite.cpp index 11936a86ea..5f74c0a486 100644 --- a/Foundation/testsuite/src/ThreadingTestSuite.cpp +++ b/Foundation/testsuite/src/ThreadingTestSuite.cpp @@ -20,6 +20,7 @@ #include "ActiveDispatcherTest.h" #include "ConditionTest.h" #include "ActiveThreadPoolTest.h" +#include "FileStreamRWLockTest.h" CppUnit::Test* ThreadingTestSuite::suite() @@ -37,6 +38,7 @@ CppUnit::Test* ThreadingTestSuite::suite() pSuite->addTest(ActiveDispatcherTest::suite()); pSuite->addTest(ConditionTest::suite()); pSuite->addTest(ActiveThreadPoolTest::suite()); + pSuite->addTest(FileStreamRWLockTest::suite()); return pSuite; } From 0875455c34cc560982efb3df4e0ebd4245181403 Mon Sep 17 00:00:00 2001 From: bas524 Date: Fri, 20 Sep 2024 13:05:06 +0200 Subject: [PATCH 02/10] add implementation FileStreamRWLock for windows replace FileStreamRWLock to the Process package --- Foundation/include/Poco/FileStreamRWLock.h | 2 +- .../include/Poco/FileStreamRWLock_POSIX.h | 6 +- .../include/Poco/FileStreamRWLock_WIN32.h | 134 ++++++++++++++++++ Foundation/src/FileStreamRWLock.cpp | 2 +- Foundation/src/FileStreamRWLock_POSIX.cpp | 2 +- Foundation/src/FileStreamRWLock_WIN32.cpp | 39 +++++ .../testsuite/src/FileStreamRWLockTest.cpp | 80 +++++++---- .../testsuite/src/ProcessesTestSuite.cpp | 2 + Foundation/testsuite/src/TestApp.cpp | 36 ++++- .../testsuite/src/ThreadingTestSuite.cpp | 2 - 10 files changed, 267 insertions(+), 38 deletions(-) create mode 100644 Foundation/include/Poco/FileStreamRWLock_WIN32.h create mode 100644 Foundation/src/FileStreamRWLock_WIN32.cpp diff --git a/Foundation/include/Poco/FileStreamRWLock.h b/Foundation/include/Poco/FileStreamRWLock.h index 97c31e3ba0..45e8f39cba 100644 --- a/Foundation/include/Poco/FileStreamRWLock.h +++ b/Foundation/include/Poco/FileStreamRWLock.h @@ -2,7 +2,7 @@ // FileStreamRWLock.h // // Library: Foundation -// Package: Threading +// Package: Processes // Module: FileStreamRWLock // // Definition of the FileStreamRWLock class. diff --git a/Foundation/include/Poco/FileStreamRWLock_POSIX.h b/Foundation/include/Poco/FileStreamRWLock_POSIX.h index 6b7372732c..44fc880854 100644 --- a/Foundation/include/Poco/FileStreamRWLock_POSIX.h +++ b/Foundation/include/Poco/FileStreamRWLock_POSIX.h @@ -2,7 +2,7 @@ // FileStreamRWLock_POSIX.h // // Library: Foundation -// Package: Threading +// Package: Processes // Module: FileStreamRWLock // // Definition of the FileStreamRWLockImpl class for POSIX FileStream. @@ -69,7 +69,7 @@ inline bool FileStreamRWLockImpl::tryReadLockImpl() else if (errno == EAGAIN || errno == EACCES) return false; else - throw SystemException("cannot lock reader lock", errno); + throw SystemException("cannot lock try-reader lock", errno); } @@ -105,7 +105,7 @@ inline void FileStreamRWLockImpl::unlockImpl() _lockMode = F_SETLKW; int rc = fcntl(_fd, _lockMode, &_flock); if (rc == -1 && errno == EDEADLK) - throw SystemException("cannot lock writer lock", EDEADLK); + throw SystemException("cannot unlock", EDEADLK); } diff --git a/Foundation/include/Poco/FileStreamRWLock_WIN32.h b/Foundation/include/Poco/FileStreamRWLock_WIN32.h new file mode 100644 index 0000000000..537b19ae2b --- /dev/null +++ b/Foundation/include/Poco/FileStreamRWLock_WIN32.h @@ -0,0 +1,134 @@ +// +// FileStreamRWLock_WIN32.h +// +// Library: Foundation +// Package: Processes +// Module: FileStreamRWLock +// +// Definition of the FileStreamRWLockImpl class for WIN32 FileStream. +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Foundation_FileStreamRWLock_WIN32_INCLUDED +#define Foundation_FileStreamRWLock_WIN32_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/Exception.h" +#include "Poco/FileStream.h" +#include + +namespace Poco { + +struct LockMode +{ + static constexpr DWORD READ = 0; + static constexpr DWORD WRITE = LOCKFILE_EXCLUSIVE_LOCK; + static constexpr DWORD TRY_READ = LOCKFILE_FAIL_IMMEDIATELY; + static constexpr DWORD TRY_WRITE = (LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY); +}; + +class Foundation_API FileStreamRWLockImpl +{ +protected: + FileStreamRWLockImpl(const FileStream::NativeHandle &fd, Poco::UInt64 offset, Poco::UInt64 size); + ~FileStreamRWLockImpl(); + void readLockImpl(); + bool tryReadLockImpl(); + void writeLockImpl(); + bool tryWriteLockImpl(); + void unlockImpl(); + +private: + FileStream::NativeHandle _fd; + OVERLAPPED _overlapped; + LARGE_INTEGER _size; +}; + + +// +// inlines +// +inline void FileStreamRWLockImpl::readLockImpl() +{ + BOOL fSuccess = LockFileEx(_fd, LockMode::READ, 0, _size.LowPart, _size.HighPart, &_overlapped); + if (!fSuccess) + { + throw SystemException("cannot lock reader lock", GetLastError()); + } +} + + +inline bool FileStreamRWLockImpl::tryReadLockImpl() +{ + BOOL fSuccess = LockFileEx(_fd, LockMode::TRY_READ, 0, _size.LowPart, _size.HighPart, &_overlapped); + if (fSuccess) + { + return true; + } + else + { + auto lastError = GetLastError(); + if (lastError == ERROR_IO_PENDING || lastError == ERROR_LOCK_VIOLATION) + { + return false; + } + else + { + throw SystemException("cannot lock try-reader lock", lastError); + } + } +} + + +inline void FileStreamRWLockImpl::writeLockImpl() +{ + BOOL fSuccess = LockFileEx(_fd, LockMode::WRITE, 0, _size.LowPart, _size.HighPart, &_overlapped); + if (!fSuccess) + { + throw SystemException("cannot lock writer lock", GetLastError()); + } +} + + +inline bool FileStreamRWLockImpl::tryWriteLockImpl() +{ + BOOL fSuccess = LockFileEx(_fd, LockMode::TRY_WRITE, 0, _size.LowPart, _size.HighPart, &_overlapped); + if (fSuccess) + { + return true; + } + else + { + auto lastError = GetLastError(); + if (lastError == ERROR_IO_PENDING || lastError == ERROR_LOCK_VIOLATION) + { + return false; + } + else + { + throw SystemException("cannot lock try-writer lock", lastError); + } + } +} + + +inline void FileStreamRWLockImpl::unlockImpl() +{ + BOOL fSuccess = UnlockFileEx(_fd, 0, _size.LowPart, _size.HighPart, &_overlapped); + if (!fSuccess) + { + throw SystemException("cannot unlock ", GetLastError()); + } +} + + +} // namespace Poco + + +#endif // Foundation_FileStreamRWLock_WIN32_INCLUDED diff --git a/Foundation/src/FileStreamRWLock.cpp b/Foundation/src/FileStreamRWLock.cpp index 8295992036..f27e8609be 100644 --- a/Foundation/src/FileStreamRWLock.cpp +++ b/Foundation/src/FileStreamRWLock.cpp @@ -2,7 +2,7 @@ // FileStreamRWLock.cpp // // Library: Foundation -// Package: Threading +// Package: Processes // Module: FileStreamRWLock // // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. diff --git a/Foundation/src/FileStreamRWLock_POSIX.cpp b/Foundation/src/FileStreamRWLock_POSIX.cpp index 86a3441f9b..94c7c8a0be 100644 --- a/Foundation/src/FileStreamRWLock_POSIX.cpp +++ b/Foundation/src/FileStreamRWLock_POSIX.cpp @@ -2,7 +2,7 @@ // FileStreamRWLock_POSIX.cpp // // Library: Foundation -// Package: Threading +// Package: Processes // Module: FileStreamRWLock // // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. diff --git a/Foundation/src/FileStreamRWLock_WIN32.cpp b/Foundation/src/FileStreamRWLock_WIN32.cpp new file mode 100644 index 0000000000..12d4935baa --- /dev/null +++ b/Foundation/src/FileStreamRWLock_WIN32.cpp @@ -0,0 +1,39 @@ +// +// FileStreamRWLock_WIN32.cpp +// +// Library: Foundation +// Package: Processes +// Module: FileStreamRWLock +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/FileStreamRWLock_WIN32.h" + + +namespace Poco { + + +FileStreamRWLockImpl::FileStreamRWLockImpl(const FileStream::NativeHandle &fd, Poco::UInt64 offset, Poco::UInt64 size): + _fd(fd) +{ + LARGE_INTEGER offt; + offt.QuadPart = offset; + memset(&_overlapped, 0, sizeof(OVERLAPPED)); + + _overlapped.Offset = offt.LowPart; + _overlapped.OffsetHigh = offt.HighPart; + _size.QuadPart = size; +} + + +FileStreamRWLockImpl::~FileStreamRWLockImpl() +{ +} + + +} // namespace Poco diff --git a/Foundation/testsuite/src/FileStreamRWLockTest.cpp b/Foundation/testsuite/src/FileStreamRWLockTest.cpp index 0dc28be848..d90c51a75a 100644 --- a/Foundation/testsuite/src/FileStreamRWLockTest.cpp +++ b/Foundation/testsuite/src/FileStreamRWLockTest.cpp @@ -30,21 +30,47 @@ using Poco::ProcessRunner; using Poco::Path; using Poco::Stopwatch; +static std::string getTestAppName() +{ + std::string name("TestApp"); + std::string ext; +#if POCO_OS == POCO_OS_WINDOWS_NT + ext = ".exe"; +#endif // POCO_OS == POCO_OS_WINDOWS_NT + +#if defined(_DEBUG) + Poco::File testapp(name + ext); + if (!testapp.exists()) + { + name += "d"; + } +#endif + return (name + ext); +} + +#if POCO_OS == POCO_OS_WINDOWS_NT + +#include "Poco/File_WIN32U.h" + +HANDLE createFileForSahredRWAccess(const std::string &path) +{ + DWORD access = GENERIC_READ | GENERIC_WRITE; + DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + + HANDLE handle = CreateFileA(path.c_str(), access, shareMode, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle == INVALID_HANDLE_VALUE) + Poco::File::handleLastError(path); + + return handle; +} +#endif + class FileStreamRWLockRunnable: public Runnable { public: - FileStreamRWLockRunnable(std::string fileLock): _fileLock(std::move(fileLock)) + FileStreamRWLockRunnable(std::string fileLock): _fileLock(std::move(fileLock)), _cmd(getTestAppName()) { - std::string name("TestApp"); -#if defined(_DEBUG) - Poco::File testapp(name); - if (!testapp.exists()) - { - name += "d"; - } -#endif - _cmd = name; - } void run() override @@ -78,18 +104,8 @@ class FileStreamRWTryLockRunnable: public Runnable { public: - FileStreamRWTryLockRunnable(std::string fileLock): _fileLock(std::move(fileLock)) + FileStreamRWTryLockRunnable(std::string fileLock): _fileLock(std::move(fileLock)), _cmd(getTestAppName()) { - std::string name("TestApp"); -#if defined(_DEBUG) - Poco::File testapp(name); - if (!testapp.exists()) - { - name += "d"; - } -#endif - _cmd = name; - } void run() override @@ -132,7 +148,13 @@ FileStreamRWLockTest::~FileStreamRWLockTest() void FileStreamRWLockTest::testFSLock() { TemporaryFile fl; - FileStream fs(fl.path(), std::ios::out | std::ios::in | std::ios::binary); +#if POCO_OS != POCO_OS_WINDOWS_NT + FileStream fs(fl.path(), std::ios::in | std::ios::out | std::ios::binary); +#else + FileStream fs; + fs.openHandle(createFileForSahredRWAccess(fl.path()), std::ios::in | std::ios::out | std::ios::binary); +#endif // POCO_OS != POCO_OS_WINDOWS_NT + Poco::Int32 i32 = 0; fs.seekp(0, std::ios::beg); fs.write((const char *)&i32, sizeof(i32)); @@ -162,7 +184,7 @@ void FileStreamRWLockTest::testFSLock() fs.seekp(0, std::ios::beg); fs.read((char *)&i32, sizeof(i32)); - assertEquals(50000, i32); + assertEqual(500, i32); assertTrue (r1.ok()); assertTrue (r2.ok()); assertTrue (r3.ok()); @@ -174,7 +196,13 @@ void FileStreamRWLockTest::testFSLock() void FileStreamRWLockTest::testFSTryLock() { TemporaryFile fl; - FileStream fs(fl.path(), std::ios::out | std::ios::in | std::ios::binary); +#if POCO_OS != POCO_OS_WINDOWS_NT + FileStream fs(fl.path(), std::ios::in | std::ios::out | std::ios::binary); +#else + FileStream fs; + fs.openHandle(createFileForSahredRWAccess(fl.path()), std::ios::in | std::ios::out | std::ios::binary); +#endif // POCO_OS != POCO_OS_WINDOWS_NT + Poco::Int32 i32 = 0; fs.seekp(0, std::ios::beg); fs.write((const char *)&i32, sizeof(i32)); @@ -204,7 +232,7 @@ void FileStreamRWLockTest::testFSTryLock() fs.seekp(0, std::ios::beg); fs.read((char *)&i32, sizeof(i32)); - assertTrue (i32 == 50000); + assertEqual(500, i32); assertTrue (r1.ok()); assertTrue (r2.ok()); assertTrue (r3.ok()); diff --git a/Foundation/testsuite/src/ProcessesTestSuite.cpp b/Foundation/testsuite/src/ProcessesTestSuite.cpp index ab0f12b594..dd9671aaab 100644 --- a/Foundation/testsuite/src/ProcessesTestSuite.cpp +++ b/Foundation/testsuite/src/ProcessesTestSuite.cpp @@ -14,6 +14,7 @@ #include "NamedEventTest.h" #include "SharedMemoryTest.h" #include "ProcessRunnerTest.h" +#include "FileStreamRWLockTest.h" CppUnit::Test* ProcessesTestSuite::suite() @@ -25,6 +26,7 @@ CppUnit::Test* ProcessesTestSuite::suite() pSuite->addTest(NamedEventTest::suite()); pSuite->addTest(SharedMemoryTest::suite()); pSuite->addTest(ProcessRunnerTest::suite()); + pSuite->addTest(FileStreamRWLockTest::suite()); return pSuite; } diff --git a/Foundation/testsuite/src/TestApp.cpp b/Foundation/testsuite/src/TestApp.cpp index 8e576c54ee..648038073c 100644 --- a/Foundation/testsuite/src/TestApp.cpp +++ b/Foundation/testsuite/src/TestApp.cpp @@ -25,6 +25,7 @@ #include "Poco/Thread.h" #include "Poco/Runnable.h" #elif defined(POCO_OS_FAMILY_WINDOWS) +#include "Poco/Thread.h" #include "Poco/Process.h" #include "Poco/Event.h" #include "Poco/NamedEvent.h" @@ -100,6 +101,7 @@ class MyApp _terminate.wait(); _terminated.set(); } + #elif defined(POCO_OS_FAMILY_UNIX) void waitForTerminationRequest() { @@ -158,6 +160,22 @@ class MyApp #if defined(POCO_OS_FAMILY_WINDOWS) Poco::Event MyApp::_terminated; Poco::NamedEvent MyApp::_terminate(Poco::ProcessImpl::terminationEventName(Poco::Process::id())); + +#include "Poco/File.h" +#include "Poco/File_WIN32U.h" + +HANDLE openFileForSahredRWAccess(const std::string& path) +{ + DWORD access = GENERIC_READ | GENERIC_WRITE; + DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + + HANDLE handle = CreateFileA(path.c_str(), access, shareMode, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle == INVALID_HANDLE_VALUE) + Poco::File::handleLastError(path); + + return handle; +} #endif int main(int argc, char** argv) @@ -242,12 +260,17 @@ int main(int argc, char** argv) if (equals_pos != std::string::npos) { std::string fl = arg.substr(equals_pos + 1); - FileStream fs(fl, std::ios::out | std::ios::in | std::ios::binary); +#if POCO_OS != POCO_OS_WINDOWS_NT + FileStream fs(fl, std::ios::in | std::ios::out | std::ios::binary); +#else + FileStream fs; + fs.openHandle(openFileForSahredRWAccess(fl), std::ios::in | std::ios::out | std::ios::binary); +#endif // POCO_OS != POCO_OS_WINDOWS_NT Poco::Int32 ok = 1; Poco::Int32 lastCount = 0; Poco::Int32 counter = 0; FileStreamRWLock lock(fs, 0, sizeof(counter)); - for (int i = 0; i < 10000; ++i) + for (int i = 0; i < 100; ++i) { lock.readLock(); fs.seekg(0, std::ios::beg); @@ -309,12 +332,17 @@ int main(int argc, char** argv) if (equals_pos != std::string::npos) { std::string fl = arg.substr(equals_pos + 1); - FileStream fs(fl, std::ios::out | std::ios::in | std::ios::binary); +#if POCO_OS != POCO_OS_WINDOWS_NT + FileStream fs(fl, std::ios::in | std::ios::out | std::ios::binary); +#else + FileStream fs; + fs.openHandle(openFileForSahredRWAccess(fl), std::ios::in | std::ios::out | std::ios::binary); +#endif // POCO_OS != POCO_OS_WINDOWS_NT Poco::Int32 ok = 1; Poco::Int32 lastCount = 0; Poco::Int32 counter = 0; FileStreamRWLock lock(fs, 0, sizeof(counter)); - for (int i = 0; i < 10000; ++i) + for (int i = 0; i < 100; ++i) { while (!lock.tryReadLock()) Thread::yield(); fs.seekg(0, std::ios::beg); diff --git a/Foundation/testsuite/src/ThreadingTestSuite.cpp b/Foundation/testsuite/src/ThreadingTestSuite.cpp index 5f74c0a486..11936a86ea 100644 --- a/Foundation/testsuite/src/ThreadingTestSuite.cpp +++ b/Foundation/testsuite/src/ThreadingTestSuite.cpp @@ -20,7 +20,6 @@ #include "ActiveDispatcherTest.h" #include "ConditionTest.h" #include "ActiveThreadPoolTest.h" -#include "FileStreamRWLockTest.h" CppUnit::Test* ThreadingTestSuite::suite() @@ -38,7 +37,6 @@ CppUnit::Test* ThreadingTestSuite::suite() pSuite->addTest(ActiveDispatcherTest::suite()); pSuite->addTest(ConditionTest::suite()); pSuite->addTest(ActiveThreadPoolTest::suite()); - pSuite->addTest(FileStreamRWLockTest::suite()); return pSuite; } From bc7d0d587859a17ee42a89fb0a1a1b033c3c0767 Mon Sep 17 00:00:00 2001 From: Alexander B Date: Mon, 23 Sep 2024 13:48:24 +0300 Subject: [PATCH 03/10] add files FileStreamRWLock* into makefile and vcproj --- Foundation/Foundation_vs160.vcxproj | 34 ++++++++++++++- Foundation/Foundation_vs170.vcxproj | 46 +++++++++++++++++++- Foundation/Makefile | 2 +- Foundation/testsuite/Makefile-Driver | 2 +- Foundation/testsuite/TestSuite_vs160.vcxproj | 4 +- Foundation/testsuite/TestSuite_vs170.vcxproj | 4 +- 6 files changed, 86 insertions(+), 6 deletions(-) diff --git a/Foundation/Foundation_vs160.vcxproj b/Foundation/Foundation_vs160.vcxproj index f1a28048f3..fba81249ef 100644 --- a/Foundation/Foundation_vs160.vcxproj +++ b/Foundation/Foundation_vs160.vcxproj @@ -976,6 +976,35 @@ true true + + + true + true + true + true + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true + true + true + true + true @@ -1595,6 +1624,9 @@ + + + @@ -1871,4 +1903,4 @@ - \ No newline at end of file + diff --git a/Foundation/Foundation_vs170.vcxproj b/Foundation/Foundation_vs170.vcxproj index 3ecff85c5d..7f48d2f3d1 100644 --- a/Foundation/Foundation_vs170.vcxproj +++ b/Foundation/Foundation_vs170.vcxproj @@ -1414,6 +1414,47 @@ true true + + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true @@ -2207,6 +2248,9 @@ + + + @@ -2507,4 +2551,4 @@ - \ No newline at end of file + diff --git a/Foundation/Makefile b/Foundation/Makefile index 2cf81af21c..33378d299b 100644 --- a/Foundation/Makefile +++ b/Foundation/Makefile @@ -30,7 +30,7 @@ objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel AsyncNotificationCent FileStreamFactory URIStreamFactory URIStreamOpener UTF32Encoding UTF16Encoding UTF8Encoding UTF8String \ Unicode UnicodeConverter Windows1250Encoding Windows1251Encoding Windows1252Encoding \ UUID UUIDGenerator Void Var VarHolder VarIterator VarVisitor Format Pipe PipeImpl PipeStream SharedMemory \ - MemoryStream FileStream AtomicCounter DataURIStream DataURIStreamFactory + MemoryStream FileStream AtomicCounter DataURIStream DataURIStreamFactory FileStreamRWLock FileStreamRWLock_POSIX zlib_objects = adler32 compress crc32 deflate \ infback inffast inflate inftrees trees zutil diff --git a/Foundation/testsuite/Makefile-Driver b/Foundation/testsuite/Makefile-Driver index 1a2b3c64c7..4878e0f05f 100644 --- a/Foundation/testsuite/Makefile-Driver +++ b/Foundation/testsuite/Makefile-Driver @@ -38,7 +38,7 @@ objects = ActiveMethodTest ActivityTest ActiveDispatcherTest \ UniqueExpireCacheTest UniqueExpireLRUCacheTest UnicodeConverterTest \ TuplesTest NamedTuplesTest TypeListTest VarTest DynamicTestSuite FileStreamTest \ MemoryStreamTest ObjectPoolTest DirectoryWatcherTest DirectoryIteratorsTest \ - DataURIStreamTest + DataURIStreamTest FileStreamRWLockTest target = testrunner target_version = 1 diff --git a/Foundation/testsuite/TestSuite_vs160.vcxproj b/Foundation/testsuite/TestSuite_vs160.vcxproj index 1da0e5e618..e6912db55b 100644 --- a/Foundation/testsuite/TestSuite_vs160.vcxproj +++ b/Foundation/testsuite/TestSuite_vs160.vcxproj @@ -663,6 +663,7 @@ + @@ -806,6 +807,7 @@ + @@ -910,4 +912,4 @@ - \ No newline at end of file + diff --git a/Foundation/testsuite/TestSuite_vs170.vcxproj b/Foundation/testsuite/TestSuite_vs170.vcxproj index d91f6c533b..1e9b8166c8 100644 --- a/Foundation/testsuite/TestSuite_vs170.vcxproj +++ b/Foundation/testsuite/TestSuite_vs170.vcxproj @@ -996,6 +996,7 @@ + @@ -1139,6 +1140,7 @@ + @@ -1243,4 +1245,4 @@ - \ No newline at end of file + From fef6e68fabeecf54ee48a5a61958cbdcac3144a4 Mon Sep 17 00:00:00 2001 From: Alexander B Date: Mon, 23 Sep 2024 14:01:39 +0300 Subject: [PATCH 04/10] remove unnecessary file from makefile --- Foundation/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/Makefile b/Foundation/Makefile index 33378d299b..6e5e6af98c 100644 --- a/Foundation/Makefile +++ b/Foundation/Makefile @@ -30,7 +30,7 @@ objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel AsyncNotificationCent FileStreamFactory URIStreamFactory URIStreamOpener UTF32Encoding UTF16Encoding UTF8Encoding UTF8String \ Unicode UnicodeConverter Windows1250Encoding Windows1251Encoding Windows1252Encoding \ UUID UUIDGenerator Void Var VarHolder VarIterator VarVisitor Format Pipe PipeImpl PipeStream SharedMemory \ - MemoryStream FileStream AtomicCounter DataURIStream DataURIStreamFactory FileStreamRWLock FileStreamRWLock_POSIX + MemoryStream FileStream AtomicCounter DataURIStream DataURIStreamFactory FileStreamRWLock zlib_objects = adler32 compress crc32 deflate \ infback inffast inflate inftrees trees zutil From 94bdbc07b2e6d2111db505e867170b6bfce75351 Mon Sep 17 00:00:00 2001 From: Alexander B Date: Mon, 23 Sep 2024 14:56:34 +0300 Subject: [PATCH 05/10] use absolute path to the TesApp with ProcessRunner --- Foundation/testsuite/src/FileStreamRWLockTest.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Foundation/testsuite/src/FileStreamRWLockTest.cpp b/Foundation/testsuite/src/FileStreamRWLockTest.cpp index d90c51a75a..0a5f09af2f 100644 --- a/Foundation/testsuite/src/FileStreamRWLockTest.cpp +++ b/Foundation/testsuite/src/FileStreamRWLockTest.cpp @@ -45,7 +45,9 @@ static std::string getTestAppName() name += "d"; } #endif - return (name + ext); + Poco::Path testAppPath = Poco::Path::current(); + testAppPath.append(name + ext).makeFile(); + return testAppPath.toString(); } #if POCO_OS == POCO_OS_WINDOWS_NT From d0f802c82e01e4015fc0a007048c1e8537b20809 Mon Sep 17 00:00:00 2001 From: Alexander B Date: Tue, 24 Sep 2024 21:21:07 +0300 Subject: [PATCH 06/10] fix vc*.proj --- Foundation/testsuite/TestSuite_vs160.vcxproj | 1 + Foundation/testsuite/TestSuite_vs170.vcxproj | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Foundation/testsuite/TestSuite_vs160.vcxproj b/Foundation/testsuite/TestSuite_vs160.vcxproj index e6912db55b..ab02fdfa09 100644 --- a/Foundation/testsuite/TestSuite_vs160.vcxproj +++ b/Foundation/testsuite/TestSuite_vs160.vcxproj @@ -806,6 +806,7 @@ + diff --git a/Foundation/testsuite/TestSuite_vs170.vcxproj b/Foundation/testsuite/TestSuite_vs170.vcxproj index 1e9b8166c8..080cb11cfb 100644 --- a/Foundation/testsuite/TestSuite_vs170.vcxproj +++ b/Foundation/testsuite/TestSuite_vs170.vcxproj @@ -1140,7 +1140,7 @@ - + From 046af767d83c12ffd099ed60f8eebef648557093 Mon Sep 17 00:00:00 2001 From: Alexander B Date: Tue, 24 Sep 2024 21:36:21 +0300 Subject: [PATCH 07/10] add new test files into vc.proj.filters --- Foundation/testsuite/TestSuite_vs160.vcxproj.filters | 8 +++++++- Foundation/testsuite/TestSuite_vs170.vcxproj.filters | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Foundation/testsuite/TestSuite_vs160.vcxproj.filters b/Foundation/testsuite/TestSuite_vs160.vcxproj.filters index 0c534981ee..2b4d53c6ca 100644 --- a/Foundation/testsuite/TestSuite_vs160.vcxproj.filters +++ b/Foundation/testsuite/TestSuite_vs160.vcxproj.filters @@ -603,6 +603,9 @@ Threading\Source Files + + Processes\Source Files + @@ -1028,5 +1031,8 @@ Threading\Header Files + + Processes\Header Files + - \ No newline at end of file + diff --git a/Foundation/testsuite/TestSuite_vs170.vcxproj.filters b/Foundation/testsuite/TestSuite_vs170.vcxproj.filters index 0c534981ee..2b4d53c6ca 100644 --- a/Foundation/testsuite/TestSuite_vs170.vcxproj.filters +++ b/Foundation/testsuite/TestSuite_vs170.vcxproj.filters @@ -603,6 +603,9 @@ Threading\Source Files + + Processes\Source Files + @@ -1028,5 +1031,8 @@ Threading\Header Files + + Processes\Header Files + - \ No newline at end of file + From de1563c9ad7d711dc914294dda2c4d842114eba2 Mon Sep 17 00:00:00 2001 From: Alexander B Date: Thu, 3 Oct 2024 18:15:45 +0300 Subject: [PATCH 08/10] fix comments --- Foundation/include/Poco/FileStreamRWLock.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Foundation/include/Poco/FileStreamRWLock.h b/Foundation/include/Poco/FileStreamRWLock.h index 45e8f39cba..21ba070f7a 100644 --- a/Foundation/include/Poco/FileStreamRWLock.h +++ b/Foundation/include/Poco/FileStreamRWLock.h @@ -39,8 +39,8 @@ class ScopedFStreamWriteRWLock; class Foundation_API FileStreamRWLock: private FileStreamRWLockImpl - /// A reader writer file lock allows multiple concurrent - /// readers or one exclusive writer. + /// A reader writer lock on the file region allows multiple concurrent + /// process-readers or one exclusive process-writer. { public: using ScopedLock = ScopedFStreamRWLock; @@ -56,20 +56,20 @@ class Foundation_API FileStreamRWLock: private FileStreamRWLockImpl /// Destroys the Reader/Writer lock on the file region. void readLock(); - /// Acquires a read lock. If another thread or process currently holds a write lock, + /// Acquires a read lock. If another process currently holds a write lock, /// waits until the write lock is released. bool tryReadLock(); /// Tries to acquire a read lock. Immediately returns true if successful, or - /// false if another thread or process currently holds a write lock. + /// false if another process currently holds a write lock. void writeLock(); - /// Acquires a write lock on the file region. If one or more other threads or processes currently hold + /// Acquires a write lock on the file region. If one or more other processes currently hold /// locks, waits until all locks are released. bool tryWriteLock(); /// Tries to acquire a write lock on the file region. Immediately returns true if successful, - /// or false if one or more other threads or processes currently hold + /// or false if one or more other processes currently hold /// locks. void unlock(); From cc401c59dcbf3226be7449edda268a327c3f162d Mon Sep 17 00:00:00 2001 From: Alexander B Date: Mon, 14 Oct 2024 14:07:51 +0300 Subject: [PATCH 09/10] fix spelling fo PR #4723 add atomic_bool _locked and check if FileStreamRWLock is locked on destruction for force unlock --- Foundation/include/Poco/FileStreamRWLock.h | 12 ++++++++++-- Foundation/src/FileStreamRWLock.cpp | 5 +++++ Foundation/testsuite/src/FileStreamRWLockTest.cpp | 2 +- Foundation/testsuite/src/TestApp.cpp | 2 +- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Foundation/include/Poco/FileStreamRWLock.h b/Foundation/include/Poco/FileStreamRWLock.h index 21ba070f7a..9cea6d09d0 100644 --- a/Foundation/include/Poco/FileStreamRWLock.h +++ b/Foundation/include/Poco/FileStreamRWLock.h @@ -76,6 +76,7 @@ class Foundation_API FileStreamRWLock: private FileStreamRWLockImpl /// Releases the read or write lock. private: + std::atomic_bool _locked = false; FileStreamRWLock(const FileStreamRWLock&); FileStreamRWLock& operator = (const FileStreamRWLock&); }; @@ -121,30 +122,37 @@ class Foundation_API ScopedFStreamWriteRWLock : public ScopedFStreamRWLock inline void FileStreamRWLock::readLock() { readLockImpl(); + _locked = true; } inline bool FileStreamRWLock::tryReadLock() { - return tryReadLockImpl(); + bool locked = tryReadLockImpl(); + if (locked) _locked = true; // assign only if success lock + return locked; } inline void FileStreamRWLock::writeLock() { writeLockImpl(); + _locked = true; } inline bool FileStreamRWLock::tryWriteLock() { - return tryWriteLockImpl(); + bool locked = tryWriteLockImpl(); + if (locked) _locked = true; // assign only if success lock + return locked; } inline void FileStreamRWLock::unlock() { unlockImpl(); + _locked = false; } diff --git a/Foundation/src/FileStreamRWLock.cpp b/Foundation/src/FileStreamRWLock.cpp index f27e8609be..482b4933eb 100644 --- a/Foundation/src/FileStreamRWLock.cpp +++ b/Foundation/src/FileStreamRWLock.cpp @@ -33,6 +33,11 @@ FileStreamRWLock::FileStreamRWLock(const FileStream &fs, Poco::UInt64 offset, Po FileStreamRWLock::~FileStreamRWLock() { + if (_locked) + { + unlockImpl(); + _locked = false; + } } diff --git a/Foundation/testsuite/src/FileStreamRWLockTest.cpp b/Foundation/testsuite/src/FileStreamRWLockTest.cpp index 0a5f09af2f..af8f423f93 100644 --- a/Foundation/testsuite/src/FileStreamRWLockTest.cpp +++ b/Foundation/testsuite/src/FileStreamRWLockTest.cpp @@ -54,7 +54,7 @@ static std::string getTestAppName() #include "Poco/File_WIN32U.h" -HANDLE createFileForSahredRWAccess(const std::string &path) +HANDLE createFileWithRWAccess(const std::string &path) { DWORD access = GENERIC_READ | GENERIC_WRITE; DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; diff --git a/Foundation/testsuite/src/TestApp.cpp b/Foundation/testsuite/src/TestApp.cpp index 648038073c..ef775b0915 100644 --- a/Foundation/testsuite/src/TestApp.cpp +++ b/Foundation/testsuite/src/TestApp.cpp @@ -164,7 +164,7 @@ Poco::NamedEvent MyApp::_terminate(Poco::ProcessImpl::terminationEventName( #include "Poco/File.h" #include "Poco/File_WIN32U.h" -HANDLE openFileForSahredRWAccess(const std::string& path) +HANDLE openFileWithRWAccess(const std::string& path) { DWORD access = GENERIC_READ | GENERIC_WRITE; DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; From 34b4472f925a194ba1878f1363f759b255f6b69c Mon Sep 17 00:00:00 2001 From: Alexander B Date: Mon, 14 Oct 2024 14:13:15 +0300 Subject: [PATCH 10/10] add atomic header --- Foundation/include/Poco/FileStreamRWLock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/include/Poco/FileStreamRWLock.h b/Foundation/include/Poco/FileStreamRWLock.h index 9cea6d09d0..7227ed03d9 100644 --- a/Foundation/include/Poco/FileStreamRWLock.h +++ b/Foundation/include/Poco/FileStreamRWLock.h @@ -21,7 +21,7 @@ #include "Poco/Foundation.h" #include "Poco/Exception.h" #include "Poco/FileStream.h" - +#include #if defined(POCO_OS_FAMILY_WINDOWS) #include "Poco/FileStreamRWLock_WIN32.h"