summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorDaniel Wilhelm <shieldwed@outlook.com>2018-05-09 00:01:21 +0200
committerDaniel Wilhelm <shieldwed@outlook.com>2018-05-09 00:01:21 +0200
commitb962d4fd3f8e802b99bd9c074851fd0f05a12adb (patch)
tree13a12ded9c3a9713a8c368975a95f5efe6ec997c /zen
parent9.2 (diff)
downloadFreeFileSync-b962d4fd3f8e802b99bd9c074851fd0f05a12adb.tar.gz
FreeFileSync-b962d4fd3f8e802b99bd9c074851fd0f05a12adb.tar.bz2
FreeFileSync-b962d4fd3f8e802b99bd9c074851fd0f05a12adb.zip
9.3
Diffstat (limited to 'zen')
-rwxr-xr-xzen/file_access.cpp13
-rwxr-xr-xzen/file_io.cpp57
-rwxr-xr-xzen/guid.h6
-rwxr-xr-xzen/scope_guard.h5
-rwxr-xr-xzen/serialize.h23
-rwxr-xr-xzen/thread.h52
6 files changed, 90 insertions, 66 deletions
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index 7d57045d..69b6c388 100755
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -345,7 +345,7 @@ void zen::renameFile(const Zstring& pathSource, const Zstring& pathTarget) //thr
const Zstring fileNameTrg = afterLast (pathTarget, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL);
const Zstring parentPathSrc = beforeLast(pathSource, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE);
const Zstring parentPathTrg = beforeLast(pathTarget, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE);
- //some (broken) devices may fail to rename case directly:
+ //some (broken) devices may fail to rename case directly:
if (equalFilePath(parentPathSrc, parentPathTrg))
{
if (fileNameSrc == fileNameTrg)
@@ -385,12 +385,12 @@ void setWriteTimeNative(const Zstring& itemPath, const struct ::timespec& modTim
if (procSl == ProcSymlink::FOLLOW)
{
//hell knows why files on gvfs-mounted Samba shares fail to open(O_WRONLY) returning EOPNOTSUPP:
- //http://www.freefilesync.org/forum/viewtopic.php?t=2803 => utimensat() works
+ //http://www.freefilesync.org/forum/viewtopic.php?t=2803 => utimensat() works (but not for gvfs SFTP)
if (::utimensat(AT_FDCWD, itemPath.c_str(), newTimes, 0) == 0)
return;
//in other cases utimensat() returns EINVAL for CIFS/NTFS drives, but open+futimens works: http://www.freefilesync.org/forum/viewtopic.php?t=387
- const int fdFile = ::open(itemPath.c_str(), O_WRONLY);
+ const int fdFile = ::open(itemPath.c_str(), O_WRONLY | O_APPEND); //2017-07-04: O_WRONLY | O_APPEND seems to avoid EOPNOTSUPP on gvfs SFTP!
if (fdFile == -1)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(itemPath)), L"open");
ZEN_ON_SCOPE_EXIT(::close(fdFile));
@@ -515,7 +515,7 @@ void zen::createDirectory(const Zstring& dirPath) //throw FileError, ErrorTarget
{
const mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; //0777, default for newly created directories
- if (::mkdir(dirPath.c_str(), mode) != 0)
+ if (::mkdir(dirPath.c_str(), mode) != 0)
{
const int lastError = errno; //copy before directly or indirectly making other system calls!
const std::wstring errorMsg = replaceCpy(_("Cannot create directory %x."), L"%x", fmtPath(dirPath));
@@ -537,7 +537,7 @@ void zen::createDirectoryIfMissingRecursion(const Zstring& dirPath) //throw File
try
{
- createDirectory(dirPath); //throw FileError, ErrorTargetExisting
+ createDirectory(dirPath); //throw FileError, ErrorTargetExisting
}
catch (FileError&)
{
@@ -628,7 +628,10 @@ FileCopyResult copyFileOsSpecific(const Zstring& sourceFile, //throw FileError,
FileOutput fileOut(fdTarget, targetFile, IOCallbackDivider(notifyUnbufferedIO, totalUnbufferedIO)); //pass ownership
bufferedStreamCopy(fileIn, fileOut); //throw FileError, X
+
+ //flush intermediate buffers before fiddling with the raw file handle
fileOut.flushBuffers(); //throw FileError, X
+
struct ::stat targetInfo = {};
if (::fstat(fileOut.getHandle(), &targetInfo) != 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(targetFile)), L"fstat");
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index d291e741..60023849 100755
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -130,22 +130,29 @@ size_t FileInput::tryRead(void* buffer, size_t bytesToRead) //throw FileError; m
size_t FileInput::read(void* buffer, size_t bytesToRead) //throw FileError, X; return "bytesToRead" bytes unless end of stream!
{
const size_t blockSize = getBlockSize();
-
- while (memBuf_.size() < bytesToRead)
+ assert(memBuf_.size() <= blockSize);
+ char* it = static_cast<char*>(buffer);
+ char* const itEnd = it + bytesToRead;
+ for (;;)
{
- memBuf_.resize(memBuf_.size() + blockSize);
- const size_t bytesRead = tryRead(&*(memBuf_.end() - blockSize), blockSize); //throw FileError; may return short, only 0 means EOF! => CONTRACT: bytesToRead > 0
- memBuf_.resize(memBuf_.size() - blockSize + bytesRead); //caveat: unsigned arithmetics
+ const size_t junkSize = std::min(static_cast<size_t>(itEnd - it), memBuf_.size());
+ std::copy (memBuf_.begin(), memBuf_.begin() + junkSize, it);
+ memBuf_.erase(memBuf_.begin(), memBuf_.begin() + junkSize);
+ it += junkSize;
+
+ if (it == itEnd)
+ break;
+ //--------------------------------------------------------------------
+ memBuf_.resize(blockSize);
+ const size_t bytesRead = tryRead(&memBuf_[0], blockSize); //throw FileError; may return short, only 0 means EOF! => CONTRACT: bytesToRead > 0
+ memBuf_.resize(bytesRead);
if (notifyUnbufferedIO_) notifyUnbufferedIO_(bytesRead); //throw X
if (bytesRead == 0) //end of file
- bytesToRead = std::min(bytesToRead, memBuf_.size());
+ break;
}
-
- std::copy(memBuf_.begin(), memBuf_.begin() + bytesToRead, static_cast<char*>(buffer));
- memBuf_.erase(memBuf_.begin(), memBuf_.begin() + bytesToRead);
- return bytesToRead;
+ return it - static_cast<char*>(buffer);
}
//----------------------------------------------------------------------------------------------------
@@ -224,16 +231,21 @@ size_t FileOutput::tryWrite(const void* buffer, size_t bytesToWrite) //throw Fil
void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileError, X
{
- auto bufFirst = static_cast<const char*>(buffer);
- memBuf_.insert(memBuf_.end(), bufFirst, bufFirst + bytesToWrite);
-
const size_t blockSize = getBlockSize();
- size_t bytesRemaining = memBuf_.size();
- ZEN_ON_SCOPE_EXIT(memBuf_.erase(memBuf_.begin(), memBuf_.end() - bytesRemaining));
- while (bytesRemaining >= blockSize)
+ assert(memBuf_.size() <= blockSize);
+ const char* it = static_cast<const char*>(buffer);
+ const char* const itEnd = it + bytesToWrite;
+ for (;;)
{
- const size_t bytesWritten = tryWrite(&*(memBuf_.end() - bytesRemaining), blockSize); //throw FileError; may return short! CONTRACT: bytesToWrite > 0
- bytesRemaining -= bytesWritten;
+ const size_t junkSize = std::min(static_cast<size_t>(itEnd - it), blockSize - memBuf_.size());
+ memBuf_.insert(memBuf_.end(), it, it + junkSize);
+ it += junkSize;
+
+ if (it == itEnd)
+ return;
+ //--------------------------------------------------------------------
+ const size_t bytesWritten = tryWrite(&memBuf_[0], blockSize); //throw FileError; may return short! CONTRACT: bytesToWrite > 0
+ memBuf_.erase(memBuf_.begin(), memBuf_.begin() + bytesWritten);
if (notifyUnbufferedIO_) notifyUnbufferedIO_(bytesWritten); //throw X!
}
}
@@ -241,12 +253,11 @@ void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileErro
void FileOutput::flushBuffers() //throw FileError, X
{
- size_t bytesRemaining = memBuf_.size();
- ZEN_ON_SCOPE_EXIT(memBuf_.erase(memBuf_.begin(), memBuf_.end() - bytesRemaining));
- while (bytesRemaining > 0)
+ assert(memBuf_.size() <= getBlockSize());
+ while (!memBuf_.empty())
{
- const size_t bytesWritten = tryWrite(&*(memBuf_.end() - bytesRemaining), bytesRemaining); //throw FileError; may return short! CONTRACT: bytesToWrite > 0
- bytesRemaining -= bytesWritten;
+ const size_t bytesWritten = tryWrite(&memBuf_[0], memBuf_.size()); //throw FileError; may return short! CONTRACT: bytesToWrite > 0
+ memBuf_.erase(memBuf_.begin(), memBuf_.begin() + bytesWritten);
if (notifyUnbufferedIO_) notifyUnbufferedIO_(bytesWritten); //throw X!
}
}
diff --git a/zen/guid.h b/zen/guid.h
index b34c3cbf..f47a141c 100755
--- a/zen/guid.h
+++ b/zen/guid.h
@@ -20,11 +20,11 @@ namespace zen
inline
std::string generateGUID() //creates a 16-byte GUID
{
- //perf: generator: 0.38ms per creation;
- // retrieve GUID: 0.13µs per call
+ //perf: generator: 0.38ms per creation;
+ // retrieve GUID: 0.13µs per call
//generator is only thread-safe like an int => keep thread-local
thread_local boost::uuids::random_generator gen;
- const boost::uuids::uuid nativeRep = gen();
+ const boost::uuids::uuid nativeRep = gen();
return std::string(nativeRep.begin(), nativeRep.end());
}
}
diff --git a/zen/scope_guard.h b/zen/scope_guard.h
index b336ad53..f4ffc92b 100755
--- a/zen/scope_guard.h
+++ b/zen/scope_guard.h
@@ -13,7 +13,7 @@
//std::uncaught_exceptions() currently unsupported on GCC and Clang => clean up ASAP
- static_assert(__GNUC__ < 6 || (__GNUC__ == 6 && (__GNUC_MINOR__ < 3 || (__GNUC_MINOR__ == 3 && __GNUC_PATCHLEVEL__ <= 1))), "check std::uncaught_exceptions support");
+ static_assert(__GNUC__ < 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ < 1 || (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 1))), "check std::uncaught_exceptions support");
namespace __cxxabiv1
{
@@ -21,7 +21,8 @@ struct __cxa_eh_globals;
extern "C" __cxa_eh_globals* __cxa_get_globals() noexcept;
}
-inline int getUncaughtExceptionCount()
+inline
+int getUncaughtExceptionCount()
{
return *(reinterpret_cast<unsigned int*>(static_cast<char*>(static_cast<void*>(__cxxabiv1::__cxa_get_globals())) + sizeof(void*)));
}
diff --git a/zen/serialize.h b/zen/serialize.h
index 81d2d1ef..8f7e813c 100755
--- a/zen/serialize.h
+++ b/zen/serialize.h
@@ -36,20 +36,20 @@ public:
using iterator = std::vector<char>::iterator;
using const_iterator = std::vector<char>::const_iterator;
- iterator begin() { return buffer->begin(); }
- iterator end () { return buffer->end (); }
+ iterator begin() { return buffer_->begin(); }
+ iterator end () { return buffer_->end (); }
- const_iterator begin() const { return buffer->begin(); }
- const_iterator end () const { return buffer->end (); }
+ const_iterator begin() const { return buffer_->begin(); }
+ const_iterator end () const { return buffer_->end (); }
- void resize(size_t len) { buffer->resize(len); }
- size_t size() const { return buffer->size(); }
- bool empty() const { return buffer->empty(); }
+ void resize(size_t len) { buffer_->resize(len); }
+ size_t size() const { return buffer_->size(); }
+ bool empty() const { return buffer_->empty(); }
- inline friend bool operator==(const ByteArray& lhs, const ByteArray& rhs) { return *lhs.buffer == *rhs.buffer; }
+ inline friend bool operator==(const ByteArray& lhs, const ByteArray& rhs) { return *lhs.buffer_ == *rhs.buffer_; }
private:
- std::shared_ptr<std::vector<char>> buffer { std::make_shared<std::vector<char>>() }; //always bound!
+ std::shared_ptr<std::vector<char>> buffer_ { std::make_shared<std::vector<char>>() }; //always bound!
//perf: shared_ptr indirection irrelevant: less than 1% slower!
};
@@ -148,9 +148,8 @@ struct MemoryStreamOut
void write(const void* buffer, size_t bytesToWrite)
{
static_assert(sizeof(typename BinContainer::value_type) == 1, ""); //expect: bytes
- const size_t oldSize = buffer_.size();
- buffer_.resize(oldSize + bytesToWrite);
- std::copy(static_cast<const char*>(buffer), static_cast<const char*>(buffer) + bytesToWrite, buffer_.begin() + oldSize);
+ buffer_.resize(buffer_.size() + bytesToWrite);
+ std::copy(static_cast<const char*>(buffer), static_cast<const char*>(buffer) + bytesToWrite, buffer_.end() - bytesToWrite);
}
const BinContainer& ref() const { return buffer_; }
diff --git a/zen/thread.h b/zen/thread.h
index 41261f1e..85e64493 100755
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -12,6 +12,7 @@
#include "scope_guard.h"
#include "type_traits.h"
#include "optional.h"
+ #include <sys/prctl.h>
namespace zen
@@ -46,7 +47,7 @@ public:
private:
std::thread stdThread_;
- std::shared_ptr<InterruptionStatus> intStatus_;
+ std::shared_ptr<InterruptionStatus> intStatus_{ std::make_shared<InterruptionStatus>() };
std::future<void> threadCompleted_;
};
@@ -59,6 +60,7 @@ void interruptibleWait(std::condition_variable& cv, std::unique_lock<std::mutex>
template <class Rep, class Period>
void interruptibleSleep(const std::chrono::duration<Rep, Period>& relTime); //throw ThreadInterruption
+void setCurrentThreadName(const char* threadName);
uint64_t getThreadId(); //simple integer thread id, unlike boost::thread::id: https://svn.boost.org/trac/boost/ticket/5754
@@ -121,7 +123,7 @@ public:
template <class Function>
void access(Function fun)
{
- std::lock_guard<std::mutex> dummy(lockValue);
+ std::lock_guard<std::mutex> dummy(lockValue_);
fun(value_);
}
@@ -129,7 +131,7 @@ private:
Protected (const Protected&) = delete;
Protected& operator=(const Protected&) = delete;
- std::mutex lockValue;
+ std::mutex lockValue_;
T value_{};
};
@@ -267,24 +269,24 @@ public:
//context of InterruptibleThread instance:
void interrupt()
{
- interrupted = true;
+ interrupted_ = true;
{
- std::lock_guard<std::mutex> dummy(lockSleep); //needed! makes sure the following signal is not lost!
+ std::lock_guard<std::mutex> dummy(lockSleep_); //needed! makes sure the following signal is not lost!
//usually we'd make "interrupted" non-atomic, but this is already given due to interruptibleWait() handling
}
- conditionSleepInterruption.notify_all();
+ conditionSleepInterruption_.notify_all();
- std::lock_guard<std::mutex> dummy(lockConditionPtr);
- if (activeCondition)
- activeCondition->notify_all(); //signal may get lost!
+ std::lock_guard<std::mutex> dummy(lockConditionPtr_);
+ if (activeCondition_)
+ activeCondition_->notify_all(); //signal may get lost!
//alternative design locking the cv's mutex here could be dangerous: potential for dead lock!
}
//context of worker thread:
void checkInterruption() //throw ThreadInterruption
{
- if (interrupted)
+ if (interrupted_)
throw ThreadInterruption();
}
@@ -296,7 +298,7 @@ public:
ZEN_ON_SCOPE_EXIT(setConditionVar(nullptr));
//"interrupted" is not protected by cv's mutex => signal may get lost!!! => add artifical time out to mitigate! CPU: 0.25% vs 0% for longer time out!
- while (!cv.wait_for(lock, std::chrono::milliseconds(1), [&] { return this->interrupted || pred(); }))
+ while (!cv.wait_for(lock, std::chrono::milliseconds(1), [&] { return this->interrupted_ || pred(); }))
;
checkInterruption(); //throw ThreadInterruption
@@ -306,26 +308,26 @@ public:
template <class Rep, class Period>
void interruptibleSleep(const std::chrono::duration<Rep, Period>& relTime) //throw ThreadInterruption
{
- std::unique_lock<std::mutex> lock(lockSleep);
- if (conditionSleepInterruption.wait_for(lock, relTime, [this] { return static_cast<bool>(this->interrupted); }))
+ std::unique_lock<std::mutex> lock(lockSleep_);
+ if (conditionSleepInterruption_.wait_for(lock, relTime, [this] { return static_cast<bool>(this->interrupted_); }))
throw ThreadInterruption();
}
private:
void setConditionVar(std::condition_variable* cv)
{
- std::lock_guard<std::mutex> dummy(lockConditionPtr);
- activeCondition = cv;
+ std::lock_guard<std::mutex> dummy(lockConditionPtr_);
+ activeCondition_ = cv;
}
- std::atomic<bool> interrupted{ false }; //std:atomic is uninitialized by default!!!
+ std::atomic<bool> interrupted_{ false }; //std:atomic is uninitialized by default!!!
//"The default constructor is trivial: no initialization takes place other than zero initialization of static and thread-local objects."
- std::condition_variable* activeCondition = nullptr;
- std::mutex lockConditionPtr; //serialize pointer access (only!)
+ std::condition_variable* activeCondition_ = nullptr;
+ std::mutex lockConditionPtr_; //serialize pointer access (only!)
- std::condition_variable conditionSleepInterruption;
- std::mutex lockSleep;
+ std::condition_variable conditionSleepInterruption_;
+ std::mutex lockSleep_;
};
@@ -373,7 +375,7 @@ void interruptibleSleep(const std::chrono::duration<Rep, Period>& relTime) //thr
template <class Function> inline
-InterruptibleThread::InterruptibleThread(Function&& f) : intStatus_(std::make_shared<InterruptionStatus>())
+InterruptibleThread::InterruptibleThread(Function&& f)
{
std::promise<void> pFinished;
threadCompleted_ = pFinished.get_future();
@@ -403,6 +405,14 @@ void InterruptibleThread::interrupt() { intStatus_->interrupt(); }
inline
+void setCurrentThreadName(const char* threadName)
+{
+ ::prctl(PR_SET_NAME, threadName, 0, 0, 0);
+
+}
+
+
+inline
uint64_t getThreadId()
{
//obviously "gettid()" is not available on Ubuntu/Debian/Suse => use the OpenSSL approach:
bgstack15