summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
Diffstat (limited to 'zen')
-rw-r--r--zen/FindFilePlus/find_file_plus.cpp8
-rw-r--r--zen/debug_minidump.cpp55
-rw-r--r--zen/dir_watcher.cpp272
-rw-r--r--zen/dir_watcher.h15
-rw-r--r--zen/file_handling.cpp102
-rw-r--r--zen/file_traverser.cpp72
-rw-r--r--zen/int64.h3
-rw-r--r--zen/osx_string.h2
-rw-r--r--zen/privilege.cpp6
-rw-r--r--zen/stl_tools.h11
-rw-r--r--zen/string_base.h11
-rw-r--r--zen/thread.h2
-rw-r--r--zen/zstring.cpp8
13 files changed, 270 insertions, 297 deletions
diff --git a/zen/FindFilePlus/find_file_plus.cpp b/zen/FindFilePlus/find_file_plus.cpp
index ea58005e..247b916c 100644
--- a/zen/FindFilePlus/find_file_plus.cpp
+++ b/zen/FindFilePlus/find_file_plus.cpp
@@ -285,15 +285,15 @@ bool FileSearcher::readDirImpl(FileInformation& output) //throw NtFileError; ret
/* corresponding first access in ::FindFirstFileW()
NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle,
- nullptr, //__in_opt HANDLE event,
- nullptr, //__in_opt PIO_APC_ROUTINE apcRoutine,
- nullptr, //__in_opt PVOID apcContext,
+ nullptr, //__in_opt HANDLE event,
+ nullptr, //__in_opt PIO_APC_ROUTINE apcRoutine,
+ nullptr, //__in_opt PVOID apcContext,
&status, //__out PIO_STATUS_BLOCK ioStatusBlock,
&buffer, //__out_bcount(Length) PVOID fileInformation,
BUFFER_SIZE, //__in ULONG length, ::FindFirstFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * MAX_PATH == 0x268
FileIdBothDirectoryInformation, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation"
true, //__in BOOLEAN returnSingleEntry,
- nullptr, //__in_opt PUNICODE_STRING mask,
+ nullptr, //__in_opt PUNICODE_STRING mask,
false); //__in BOOLEAN restartScan
*/
diff --git a/zen/debug_minidump.cpp b/zen/debug_minidump.cpp
index 1b625015..29500ae4 100644
--- a/zen/debug_minidump.cpp
+++ b/zen/debug_minidump.cpp
@@ -9,18 +9,33 @@
#include <sstream>
#include <cassert>
#include <cstdlib> //malloc(), free()
+#include <zen/file_error.h>
+#include <zen/scope_guard.h>
+#include <zen/time.h>
#include "win.h" //includes "windows.h"
#include "DbgHelp.h" //available for MSC only
#pragma comment(lib, "Dbghelp.lib")
+using namespace zen;
+
namespace
{
-LONG WINAPI writeDumpOnException(EXCEPTION_POINTERS* pExceptionInfo)
+LONG WINAPI writeDumpOnException(EXCEPTION_POINTERS* pExceptionInfo) //blocks showing message boxes on success and error!
{
- HANDLE hFile = ::CreateFile(L"exception.dmp", GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
- if (hFile != INVALID_HANDLE_VALUE)
+ assert(false);
+
+ const Zstring filename = L"CrashDump " + formatTime<Zstring>(L"%Y-%m-%d %H%M%S") + L".dmp";
+
{
+ HANDLE hFile = ::CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ ::MessageBox(nullptr, (replaceCpy<std::wstring>(L"Cannot write file %x.", L"%x", fmtFileName(filename)) + L"\n\n" + formatSystemError(L"CreateFile", ::GetLastError())).c_str(), L"Application Crash", MB_SERVICE_NOTIFICATION | MB_ICONERROR);
+ std::terminate();
+ }
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
+
MINIDUMP_EXCEPTION_INFORMATION exInfo = {};
exInfo.ThreadId = ::GetCurrentThreadId();
exInfo.ExceptionPointers = pExceptionInfo;
@@ -28,23 +43,33 @@ LONG WINAPI writeDumpOnException(EXCEPTION_POINTERS* pExceptionInfo)
MINIDUMP_EXCEPTION_INFORMATION* exceptParam = pExceptionInfo ? &exInfo : nullptr;
- /*bool rv = */
- ::MiniDumpWriteDump(::GetCurrentProcess (), //__in HANDLE hProcess,
- ::GetCurrentProcessId(), //__in DWORD ProcessId,
- hFile, //__in HANDLE hFile,
- MiniDumpWithDataSegs, //__in MINIDUMP_TYPE DumpType, ->Standard: MiniDumpNormal, Medium: MiniDumpWithDataSegs, Full: MiniDumpWithFullMemory
- exceptParam, //__in PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
- nullptr, //__in PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
- nullptr); //__in PMINIDUMP_CALLBACK_INFORMATION CallbackParam
+ if (!::MiniDumpWriteDump(::GetCurrentProcess (), //__in HANDLE hProcess,
+ ::GetCurrentProcessId(), //__in DWORD ProcessId,
+ hFile, //__in HANDLE hFile,
+ MiniDumpWithDataSegs, //__in MINIDUMP_TYPE DumpType, ->Standard: MiniDumpNormal, Medium: MiniDumpWithDataSegs, Full: MiniDumpWithFullMemory
+ exceptParam, //__in PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ nullptr, //__in PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ nullptr)) //__in PMINIDUMP_CALLBACK_INFORMATION CallbackParam
+ {
+ ::MessageBox(nullptr, (replaceCpy<std::wstring>(L"Cannot write file %x.", L"%x", fmtFileName(filename)) + L"\n\n" + formatSystemError(L"MiniDumpWriteDump", ::GetLastError())).c_str(), L"Application Crash", MB_SERVICE_NOTIFICATION | MB_ICONERROR);
+ std::terminate();
+ }
+ } //close file before showing success message
+
+ //attention: the app has not yet officially crashed! => use MB_SERVICE_NOTIFICATION to avoid Win32 GUI callbacks while message box is shown!
+ ::MessageBox(nullptr, replaceCpy<std::wstring>(L"Crash dump file %x written!", L"%x", fmtFileName(filename)).c_str(), L"Application Crash", MB_SERVICE_NOTIFICATION | MB_ICONERROR);
+ std::terminate();
- ::CloseHandle(hFile);
- }
- assert(false);
return EXCEPTION_EXECUTE_HANDLER;
}
//ensure that a dump-file is written for uncaught exceptions
-struct OnStartup { OnStartup() { ::SetUnhandledExceptionFilter(writeDumpOnException); }} dummy;
+struct OnStartup {
+ OnStartup()
+ {
+ /*LPTOP_LEVEL_EXCEPTION_FILTER oldFilter = */ ::SetUnhandledExceptionFilter(writeDumpOnException);
+ //oldFilter == &__CxxUnhandledExceptionFilter() by default!
+ }} dummy;
}
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 1945ada7..951dd3ae 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -21,10 +21,8 @@
#include "file_traverser.h"
#elif defined ZEN_MAC
-//#include <sys/types.h>
-//#include <sys/event.h>
-//#include <sys/time.h>
-#include "file_traverser.h"
+#include <CoreServices/CoreServices.h>
+#include <zen/osx_string.h>
#endif
using namespace zen;
@@ -97,7 +95,7 @@ public:
//context of main thread
- void getChanges(std::vector<DirWatcher::Entry>& output) //throw FileError
+ void fetchChanges(std::vector<DirWatcher::Entry>& output) //throw FileError
{
boost::lock_guard<boost::mutex> dummy(lockAccess);
@@ -162,6 +160,14 @@ public:
//end of constructor, no need to start managing "hDir"
}
+ ReadChangesAsync(ReadChangesAsync&& other) :
+ hDir(INVALID_HANDLE_VALUE)
+ {
+ shared_ = std::move(other.shared_);
+ dirnamePf = std::move(other.dirnamePf);
+ std::swap(hDir, other.hDir);
+ }
+
~ReadChangesAsync()
{
if (hDir != INVALID_HANDLE_VALUE) //valid hDir is NOT an invariant, see move constructor!
@@ -250,14 +256,6 @@ public:
}
}
- ReadChangesAsync(ReadChangesAsync&& other) :
- hDir(INVALID_HANDLE_VALUE)
- {
- shared_ = std::move(other.shared_);
- dirnamePf = std::move(other.dirnamePf);
- std::swap(hDir, other.hDir);
- }
-
HANDLE getDirHandle() const { return hDir; } //for reading/monitoring purposes only, don't abuse (e.g. close handle)!
private:
@@ -364,7 +362,7 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()
output.push_back(Entry(ACTION_DELETE, pimpl_->dirname)); //report removal as change to main directory
}
else //the normal case...
- pimpl_->shared->getChanges(output); //throw FileError
+ pimpl_->shared->fetchChanges(output); //throw FileError
return output;
}
@@ -395,6 +393,8 @@ private:
struct DirWatcher::Pimpl
{
+ Pimpl() : notifDescr() {}
+
Zstring baseDirname;
int notifDescr;
std::map<int, Zstring> watchDescrs; //watch descriptor and (sub-)directory name (postfixed with separator) -> owned by "notifDescr"
@@ -519,188 +519,116 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()
}
#elif defined ZEN_MAC
-warn_static("finish");
-struct DirWatcher::Pimpl {};
-DirWatcher::DirWatcher(const Zstring& directory) {}
-DirWatcher::~DirWatcher() {}
-std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()>&) { return std::vector<DirWatcher::Entry>(); }
-
-#if 0
namespace
{
-class DirsOnlyTraverser : public zen::TraverseCallback
+void eventCallback(ConstFSEventStreamRef streamRef,
+ void* clientCallBackInfo,
+ size_t numEvents,
+ void* eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[])
{
-public:
- DirsOnlyTraverser(std::vector<Zstring>& dirs) : dirs_(dirs) {}
+ std::vector<DirWatcher::Entry>& changedFiles = *static_cast<std::vector<DirWatcher::Entry>*>(clientCallBackInfo);
- virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details) {}
- virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) { return LINK_SKIP; }
- virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& fullName)
+ auto paths = static_cast<const char**>(eventPaths);
+ for (size_t i = 0; i < numEvents; ++i)
{
- dirs_.push_back(fullName);
- return this;
+ //::printf("0x%08x\t%s\n", static_cast<unsigned int>(eventFlags[i]), paths[i]);
+
+ //events are aggregated => it's possible to see a single event with flags
+ //kFSEventStreamEventFlagItemCreated | kFSEventStreamEventFlagItemModified | kFSEventStreamEventFlagItemRemoved
+
+ if (eventFlags[i] & kFSEventStreamEventFlagItemCreated ||
+ eventFlags[i] & kFSEventStreamEventFlagMount)
+ changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_CREATE, paths[i]));
+ if (eventFlags[i] & kFSEventStreamEventFlagItemModified || //
+ eventFlags[i] & kFSEventStreamEventFlagItemXattrMod || //
+ eventFlags[i] & kFSEventStreamEventFlagItemChangeOwner || //aggregate these into a single event
+ eventFlags[i] & kFSEventStreamEventFlagItemInodeMetaMod || //
+ eventFlags[i] & kFSEventStreamEventFlagItemFinderInfoMod || //
+ eventFlags[i] & kFSEventStreamEventFlagItemRenamed || //OS X sends the same event flag for both old and new names!!!
+ eventFlags[i] & kFSEventStreamEventFlagMustScanSubDirs) //something changed in one of the subdirs: NOT expected due to kFSEventStreamCreateFlagFileEvents
+ changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_UPDATE, paths[i]));
+ if (eventFlags[i] & kFSEventStreamEventFlagItemRemoved ||
+ eventFlags[i] & kFSEventStreamEventFlagRootChanged || //root is (indirectly) deleted or renamed
+ eventFlags[i] & kFSEventStreamEventFlagUnmount)
+ changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_DELETE, paths[i]));
+
+ //kFSEventStreamEventFlagEventIdsWrapped -> irrelevant!
+ //kFSEventStreamEventFlagHistoryDone -> not expected due to kFSEventStreamEventIdSinceNow below
}
- virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) { throw FileError(msg); }
- virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) { throw FileError(msg); }
-
-private:
- std::vector<Zstring>& dirs_;
-};
-
-
-class DirDescriptor //throw FileError
-{
-public:
- DirDescriptor(const Zstring& dirname) : dirname_(dirname)
- {
- fdDir = ::open(dirname.c_str(), O_EVTONLY); //"descriptor requested for event notifications only"; O_EVTONLY does not exist on Linux
- if (fdDir == -1)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"open", getLastError()));
- }
-
- ~DirDescriptor() { if (fdDir != -1) ::close(fdDir); } //check for "-1" only needed by move-constructor
-
- DirDescriptor(DirDescriptor&& other) : fdDir(other.fdDir), dirname_(std::move(other.dirname_)) { other.fdDir = -1; }
-
- int getDescriptor() const { return fdDir; }
- Zstring getDirname() const { return dirname_; }
-
-private:
- DirDescriptor(const DirDescriptor&) = delete;
- DirDescriptor& operator=(const DirDescriptor&) = delete;
-
- int fdDir;
- Zstring dirname_;
-};
+}
}
-warn_static("finish")
+
struct DirWatcher::Pimpl
{
- Zstring baseDirname;
- int queueDescr;
- std::map<int, DirDescriptor> watchDescrs; //directory descriptors and corresponding (sub-)directory name (postfixed with separator!)
- std::vector<struct ::kevent> changelist;
+ Pimpl() : eventStream() {}
+ FSEventStreamRef eventStream;
+ std::vector<DirWatcher::Entry> changedFiles;
};
-DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
+DirWatcher::DirWatcher(const Zstring& directory) :
pimpl_(new Pimpl)
{
- //get all subdirectories
- Zstring dirname = directory;
- if (endsWith(dirname, FILE_NAME_SEPARATOR))
- dirname.resize(dirname.size() - 1);
-
- std::vector<Zstring> fullDirList { dirname };
- {
- DirsOnlyTraverser traverser(fullDirList); //throw FileError
- zen::traverseFolder(dirname, traverser); //don't traverse into symlinks (analog to windows build)
- }
-
- pimpl_->baseDirname = directory;
-
- pimpl_->queueDescr = ::kqueue();
- if (pimpl_->queueDescr == -1)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), formatSystemError(L"kqueue", getLastError()));
- zen::ScopeGuard guardDescr = zen::makeGuard([&] { ::close(pimpl_->queueDescr); });
-
- for (const Zstring& subdir : fullDirList)
- {
- DirDescriptor descr(subdir);
- const int rawDescr = descr.getDescriptor();
- pimpl_->watchDescrs.insert(std::make_pair(rawDescr, std::move(descr)));
-
- pimpl_->changelist.push_back({});
- EV_SET(&pimpl_->changelist.back(),
- rawDescr, //identifier for this event
- EVFILT_VNODE, //filter for event
- EV_ADD | EV_CLEAR, //general flags
- NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB, //filter-specific flags
- 0, //filter-specific data
- nullptr); //opaque user data identifier
- }
-
- //what about EINTR?
- struct ::timespec timeout = {}; //=> poll
- if (::kevent(pimpl_->queueDescr, &pimpl_->changelist[0], pimpl_->changelist.size(), nullptr, 0, &timeout) < 0)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), formatSystemError(L"kevent", getLastError()));
-
- guardDescr.dismiss();
+ CFStringRef dirnameCf = osx::createCFString(directory.c_str()); //returns nullptr on error
+ if (!dirnameCf)
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), L"Function call failed: createCFString"); //no error code documented!
+ ZEN_ON_SCOPE_EXIT(::CFRelease(dirnameCf));
+
+ CFArrayRef dirnameCfArray = ::CFArrayCreate(nullptr, //CFAllocatorRef allocator,
+ reinterpret_cast<const void**>(&dirnameCf), //const void** values,
+ 1, //CFIndex numValues,
+ nullptr); //const CFArrayCallBacks* callBacks
+ if (!dirnameCfArray)
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), L"Function call failed: CFArrayCreate"); //no error code documented!
+ ZEN_ON_SCOPE_EXIT(::CFRelease(dirnameCfArray));
+
+ FSEventStreamContext context = {};
+ context.info = &pimpl_->changedFiles;
+
+ pimpl_->eventStream = ::FSEventStreamCreate(nullptr, //CFAllocatorRef allocator,
+ &eventCallback, //FSEventStreamCallback callback,
+ &context, //FSEventStreamContext* context,
+ dirnameCfArray, //CFArrayRef pathsToWatch,
+ kFSEventStreamEventIdSinceNow, //FSEventStreamEventId sinceWhen,
+ 0, //CFTimeInterval latency, in seconds
+ kFSEventStreamCreateFlagWatchRoot |
+ kFSEventStreamCreateFlagFileEvents); //FSEventStreamCreateFlags flags
+ //can this fail?? not documented!
+
+ zen::ScopeGuard guardCreate = zen::makeGuard([&] { ::FSEventStreamRelease(pimpl_->eventStream); });
+
+ ::FSEventStreamScheduleWithRunLoop(pimpl_->eventStream, //FSEventStreamRef streamRef,
+ ::CFRunLoopGetCurrent(), //CFRunLoopRef runLoop; CFRunLoopGetCurrent(): failure not documented!
+ kCFRunLoopDefaultMode); //CFStringRef runLoopMode
+ //no-fail
+
+ zen::ScopeGuard guardRunloop = zen::makeGuard([&] { ::FSEventStreamInvalidate(pimpl_->eventStream); });
+
+ if (!::FSEventStreamStart(pimpl_->eventStream))
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), L"Function call failed: FSEventStreamStart"); //no error code documented!
+
+ guardCreate .dismiss();
+ guardRunloop.dismiss();
}
DirWatcher::~DirWatcher()
{
- ::close(pimpl_->queueDescr);
+ ::FSEventStreamStop (pimpl_->eventStream);
+ ::FSEventStreamInvalidate(pimpl_->eventStream);
+ ::FSEventStreamRelease (pimpl_->eventStream);
}
-std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()>&) //throw FileError
+std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()>&)
{
- std::vector<Entry> output;
-
- std::vector<struct ::kevent> events(512);
- for (;;)
- {
- assert(!pimpl_->changelist.empty()); //contains at least parent directory
- struct ::timespec timeout = {}; //=> poll
-
- int evtCount = 0;
- do
- {
- evtCount = ::kevent(pimpl_->queueDescr, //int kq,
- &pimpl_->changelist[0], //const struct kevent* changelist,
- pimpl_->changelist.size(), //int nchanges,
- &events[0], //struct kevent* eventlist,
- events.size(), //int nevents,
- &timeout); //const struct timespec* timeout
- }
- while (evtCount < 0 && errno == EINTR);
-
- if (evtCount == -1)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->baseDirname)), formatSystemError(L"kevent", getLastError()));
-
- for (int i = 0; i < evtCount; ++i)
- {
- const auto& evt = events[i];
-
- auto it = pimpl_->watchDescrs.find(static_cast<int>(evt.ident));
- if (it == pimpl_->watchDescrs.end())
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->baseDirname)), L"Received event from unknown source.");
+ ::FSEventStreamFlushSync(pimpl_->eventStream); //flushes pending events + execs runloop
- //"If an error occurs [...] and there is enough room in the eventlist, then the event will
- // be placed in the eventlist with EV_ERROR set in flags and the system error in data."
- if (evt.flags & EV_ERROR)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(it->second.getDirname())), formatSystemError(L"kevent", static_cast<ErrorCode>(evt.data)));
-
- assert(evt.filter == EVFILT_VNODE);
- if (evt.filter == EVFILT_VNODE)
- {
- if (evt.fflags & NOTE_DELETE)
- wxMessageBox(L"NOTE_DELETE "+ it->second.getDirname());
- else if (evt.fflags & NOTE_REVOKE)
- wxMessageBox(L"NOTE_REVOKE "+ it->second.getDirname());
- else if (evt.fflags & NOTE_RENAME)
- wxMessageBox(L"NOTE_RENAME "+ it->second.getDirname());
- else if (evt.fflags & NOTE_WRITE)
- wxMessageBox(L"NOTE_WRITE "+ it->second.getDirname());
- else if (evt.fflags & NOTE_EXTEND)
- wxMessageBox(L"NOTE_EXTEND "+ it->second.getDirname());
- else if (evt.fflags & NOTE_ATTRIB)
- wxMessageBox(L"NOTE_ATTRIB "+ it->second.getDirname());
- else
- assert(false);
- }
- }
-
- if (evtCount < events.size())
- break;
- }
-
- return output;
+ std::vector<DirWatcher::Entry> changes;
+ changes.swap(pimpl_->changedFiles);
+ return changes;
}
#endif
-
-
-#endif
diff --git a/zen/dir_watcher.h b/zen/dir_watcher.h
index 233bdc59..bc9714a0 100644
--- a/zen/dir_watcher.h
+++ b/zen/dir_watcher.h
@@ -21,13 +21,16 @@ namespace zen
//watch directory including subdirectories
/*
!Note handling of directories!:
- Linux: newly added subdirectories are reported but not automatically added for watching! -> reset Dirwatcher!
- removal of top watched directory is NOT notified!
- Windows: removal of top watched directory also NOT notified (e.g. brute force usb stick removal)
+ Windows: removal of top watched directory is NOT notified (e.g. brute force usb stick removal)
however manual unmount IS notified (e.g. usb stick removal, then re-insert), but watching is stopped!
Renaming of top watched directory handled incorrectly: Not notified(!) + additional changes in subfolders
now do report FILE_ACTION_MODIFIED for directory (check that should prevent this fails!)
+ Linux: newly added subdirectories are reported but not automatically added for watching! -> reset Dirwatcher!
+ removal of top watched directory is NOT notified!
+
+ OS X: everything works as expected; renaming of top level folder is also detected
+
Overcome all issues portably: check existence of top watched directory externally + reinstall watch after changes in directory structure (added directories) are detected
*/
class DirWatcher
@@ -38,9 +41,9 @@ public:
enum ActionType
{
- ACTION_CREATE,
- ACTION_UPDATE,
- ACTION_DELETE,
+ ACTION_CREATE, //informal only!
+ ACTION_UPDATE, //use for debugging/logging only!
+ ACTION_DELETE, //
};
struct Entry
diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp
index 8c5584db..563a07ce 100644
--- a/zen/file_handling.cpp
+++ b/zen/file_handling.cpp
@@ -14,7 +14,7 @@
#include "file_io.h"
#include "assert_static.h"
#include "file_id_def.h"
-#include <boost/thread/tss.hpp>
+//#include <boost/thread/tss.hpp>
#ifdef ZEN_WIN
#include <Aclapi.h>
@@ -1303,36 +1303,42 @@ void zen::makeDirectoryPlain(const Zstring& directory, //throw FileError, ErrorT
::SetFileAttributes(applyLongPathPrefix(directory).c_str(), dirInfo.dwFileAttributes);
//copy "read-only and system attributes": http://blogs.msdn.com/b/oldnewthing/archive/2003/09/30/55100.aspx
- const bool isCompressed = (dirInfo.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0;
const bool isEncrypted = (dirInfo.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0;
+ const bool isCompressed = (dirInfo.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0;
if (isEncrypted)
::EncryptFile(directory.c_str()); //seems no long path is required (check passed!)
- if (isCompressed)
+ HANDLE hDirTrg = ::CreateFile(applyLongPathPrefix(directory).c_str(),
+ GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ nullptr);
+ if (hDirTrg != INVALID_HANDLE_VALUE)
{
- HANDLE hDirTrg = ::CreateFile(applyLongPathPrefix(directory).c_str(),
- GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- nullptr,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- nullptr);
- if (hDirTrg != INVALID_HANDLE_VALUE)
- {
- ZEN_ON_SCOPE_EXIT(::CloseHandle(hDirTrg));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hDirTrg));
+ if (isCompressed)
+ {
USHORT cmpState = COMPRESSION_FORMAT_DEFAULT;
DWORD bytesReturned = 0;
- ::DeviceIoControl(hDirTrg, //handle to file or directory
- FSCTL_SET_COMPRESSION, //dwIoControlCode
- &cmpState, //input buffer
- sizeof(cmpState), //size of input buffer
- nullptr, //lpOutBuffer
- 0, //OutBufferSize
- &bytesReturned, //number of bytes returned
- nullptr); //OVERLAPPED structure
+ /*bool rv = */::DeviceIoControl(hDirTrg, //handle to file or directory
+ FSCTL_SET_COMPRESSION, //dwIoControlCode
+ &cmpState, //input buffer
+ sizeof(cmpState), //size of input buffer
+ nullptr, //lpOutBuffer
+ 0, //OutBufferSize
+ &bytesReturned, //number of bytes returned
+ nullptr); //OVERLAPPED structure
}
+
+ //(try to) set creation and modification time
+ /*bool rv = */::SetFileTime(hDirTrg, //_In_ HANDLE hFile,
+ &dirInfo.ftCreationTime, //_Out_opt_ LPFILETIME lpCreationTime,
+ nullptr, //_Out_opt_ LPFILETIME lpLastAccessTime,
+ &dirInfo.ftLastWriteTime); //_Out_opt_ LPFILETIME lpLastWriteTime
}
}
}
@@ -1783,12 +1789,12 @@ public:
throw ErrorShouldCopyAsSparse(L"sparse dummy value");
if (exceptionInUserCallback)
- try
- {
- exceptionInUserCallback(0); //should throw again!!!
- assert(false);
- }
- catch (...) { throw; }
+ try
+ {
+ exceptionInUserCallback(0); //should throw again!!!
+ assert(false);
+ }
+ catch (...) { throw; }
if (!errorMsg.first.empty())
throw FileError(errorMsg.first, errorMsg.second);
@@ -2171,19 +2177,6 @@ void copyFileLinuxMac(const Zstring& sourceFile,
}
#endif
-
-Zstring findUnusedTempName(const Zstring& filename)
-{
- Zstring output = filename + zen::TEMP_FILE_ENDING;
-
- //ensure uniqueness (+ minor file system race condition!)
- for (int i = 1; somethingExists(output); ++i)
- output = filename + Zchar('_') + numberTo<Zstring>(i) + zen::TEMP_FILE_ENDING;
-
- return output;
-}
-
-
/*
------------------
|File Copy Layers|
@@ -2225,25 +2218,22 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath
{
if (transactionalCopy)
{
- Zstring temporary = targetFile + zen::TEMP_FILE_ENDING; //use temporary file until a correct date has been set
+ Zstring tmpTarget = targetFile + TEMP_FILE_ENDING; //use temporary file until a correct date has been set
//raw file copy
- try
- {
- copyFileSelectOs(sourceFile, temporary, onUpdateCopyStatus, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
- }
- catch (ErrorTargetExisting&)
- {
- //determine non-used temp file name "first":
- //using optimistic strategy: assume everything goes well, but recover on error -> minimize file accesses
- temporary = findUnusedTempName(targetFile);
-
- //retry
- copyFileSelectOs(sourceFile, temporary, onUpdateCopyStatus, sourceAttr); //throw FileError
- }
+ for (int i = 1;; ++i)
+ try
+ {
+ copyFileSelectOs(sourceFile, tmpTarget, onUpdateCopyStatus, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
+ break;
+ }
+ catch (const ErrorTargetExisting&) //using optimistic strategy: assume everything goes well, but recover on error -> minimize file accesses
+ {
+ tmpTarget = targetFile + Zchar('_') + numberTo<Zstring>(i) + TEMP_FILE_ENDING;
+ }
//transactional behavior: ensure cleanup; not needed before copyFileSelectOs() which is already transactional
- zen::ScopeGuard guardTempFile = zen::makeGuard([&] { try { removeFile(temporary); } catch (FileError&) {} });
+ zen::ScopeGuard guardTempFile = zen::makeGuard([&] { try { removeFile(tmpTarget); } catch (FileError&) {} });
//have target file deleted (after read access on source and target has been confirmed) => allow for almost transactional overwrite
if (onDeleteTargetFile)
@@ -2251,7 +2241,7 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath
//rename temporary file:
//perf: this call is REALLY expensive on unbuffered volumes! ~40% performance decrease on FAT USB stick!
- renameFile(temporary, targetFile); //throw FileError
+ renameFile(tmpTarget, targetFile); //throw FileError
/*
CAVEAT on FAT/FAT32: the sequence of deleting the target file and renaming "file.txt.ffs_tmp" to "file.txt" does
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index 9c1b01a4..70593d1d 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -22,6 +22,7 @@
#endif
#if defined ZEN_LINUX || defined ZEN_MAC
+#include <cstddef> //required by GCC 4.8.1 to find ptrdiff_t
#include <sys/stat.h>
#include <dirent.h>
#endif
@@ -153,8 +154,7 @@ typedef ... FindData;
static void create(const Zstring& directory, DirHandle& hnd); //throw FileError - *no* concession to FindFirstFile(): open handle only, *no* return of data!
static void destroy(DirHandle hnd); //throw()
-template <class FallbackFun>
-static bool getEntry(DirHandle hnd, const Zstring& directory, FindData& fileInfo, FallbackFun fb) //throw FileError -> fb: fallback to FindFirstFile()/FindNextFile()
+static bool getEntry(DirHandle hnd, const Zstring& directory, FindData& fileInfo) //throw FileError, NeedFallbackToWin32Traverser -> fallback to FindFirstFile()/FindNextFile()
//FindData "member" functions
static void extractFileInfo (const FindData& fileInfo, DWORD volumeSerial, TraverseCallback::FileInfo& output); //volumeSerial may be 0 if not available!
@@ -207,8 +207,7 @@ struct Win32Traverser
static void destroy(const DirHandle& hnd) { ::FindClose(hnd.searchHandle); } //throw()
- template <class FallbackFun>
- static bool getEntry(DirHandle& hnd, const Zstring& dirname, FindData& fileInfo, FallbackFun) //throw FileError
+ static bool getEntry(DirHandle& hnd, const Zstring& dirname, FindData& fileInfo) //throw FileError
{
if (hnd.searchHandle == INVALID_HANDLE_VALUE) //handle special case of "truly empty directories"
return false;
@@ -247,6 +246,9 @@ struct Win32Traverser
};
+class NeedFallbackToWin32Traverser {}; //special exception class
+
+
struct FilePlusTraverser
{
struct DirHandle
@@ -267,8 +269,7 @@ struct FilePlusTraverser
static void destroy(DirHandle hnd) { ::closeDir(hnd.searchHandle); } //throw()
- template <class FallbackFun>
- static bool getEntry(DirHandle hnd, const Zstring& dirname, FindData& fileInfo, FallbackFun fb) //throw FileError
+ static bool getEntry(DirHandle hnd, const Zstring& dirname, FindData& fileInfo) //throw FileError, NeedFallbackToWin32Traverser
{
if (!::readDir(hnd.searchHandle, fileInfo))
{
@@ -281,10 +282,8 @@ struct FilePlusTraverser
this is required for NetDrive mounted Webdav, e.g. www.box.net and NT4, 2000 remote drives, et al.
*/
if (lastError == ERROR_NOT_SUPPORTED)
- {
- fb(); //fallback should apply to whole directory sub-tree! => client needs to handle duplicate file notifications!
- return false;
- }
+ throw NeedFallbackToWin32Traverser();
+ //fallback should apply to whole directory sub-tree! => client needs to handle duplicate file notifications!
//else we have a problem... report it:
throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"readDir", lastError));
@@ -312,6 +311,12 @@ struct FilePlusTraverser
class DirTraverser
{
public:
+ static void execute(const Zstring& baseDirectory, TraverseCallback& sink, DstHackCallback* dstCallback)
+ {
+ DirTraverser(baseDirectory, sink, dstCallback);
+ }
+
+private:
DirTraverser(const Zstring& baseDirectory, TraverseCallback& sink, DstHackCallback* dstCallback) :
needDstHack(dstCallback ? dst::isFatDrive(baseDirectory) : false)
{
@@ -322,7 +327,13 @@ public:
catch (FileError&) {} //don't cause issues in user mode
if (::openDir && ::readDir && ::closeDir)
- traverse<FilePlusTraverser>(baseDirectory, sink, retrieveVolumeSerial(baseDirectory)); //retrieveVolumeSerial returns 0 on error
+ {
+ try
+ {
+ traverse<FilePlusTraverser>(baseDirectory, sink, retrieveVolumeSerial(baseDirectory)); //throw NeedFallbackToWin32Traverser; retrieveVolumeSerial returns 0 on error
+ }
+ catch (NeedFallbackToWin32Traverser&) { traverse<Win32Traverser>(baseDirectory, sink, 0); }
+ }
else //fallback
traverse<Win32Traverser>(baseDirectory, sink, 0);
@@ -332,33 +343,29 @@ public:
applyDstHack(*dstCallback);
}
-private:
DirTraverser(const DirTraverser&);
DirTraverser& operator=(const DirTraverser&);
template <class Trav>
- void traverse(const Zstring& dirname, zen::TraverseCallback& sink, DWORD volumeSerial /*may be 0!*/)
+ void traverse(const Zstring& dirname, zen::TraverseCallback& sink, DWORD volumeSerial /*may be 0!*/) //throw NeedFallbackToWin32Traverser
{
//no need to check for endless recursion: Windows seems to have an internal path limit of about 700 chars
typename Trav::DirHandle searchHandle;
- if (!tryReportingDirError([&]
- {
- typedef Trav Trav; //f u VS!
- Trav::create(dirname, searchHandle); //throw FileError
- }, sink))
+ if (!tryReportingDirError([&] { Trav::create(dirname, searchHandle); /*throw FileError*/ }, sink))
return; //ignored error
- ZEN_ON_SCOPE_EXIT(typedef Trav Trav; Trav::destroy(searchHandle));
+ ZEN_ON_SCOPE_EXIT(Trav::destroy(searchHandle));
typename Trav::FindData findData = {};
- auto fallback = [&] { this->traverse<Win32Traverser>(dirname, sink, volumeSerial); }; //help VS2010 a little by avoiding too deeply nested lambdas
-
for (;;)
{
bool gotEntry = false;
- tryReportingDirError([&] { typedef Trav Trav; /*VS 2010 bug*/ gotEntry = Trav::getEntry(searchHandle, dirname, findData, fallback); }, sink); //throw FileError
+ tryReportingDirError([&]
+ {
+ gotEntry = Trav::getEntry(searchHandle, dirname, findData); //throw FileError, NeedFallbackToWin32Traverser
+ }, sink);
if (!gotEntry) //no more items or ignored error
return;
@@ -383,7 +390,11 @@ private:
if (TraverseCallback* trav = sink.onDir(shortName, fullName))
{
ZEN_ON_SCOPE_EXIT(sink.releaseDirTraverser(trav));
- traverse<Trav>(fullName, *trav, retrieveVolumeSerial(fullName)); //symlink may link to different volume => redetermine volume serial!
+ try
+ {
+ traverse<Trav>(fullName, *trav, retrieveVolumeSerial(fullName)); //throw NeedFallbackToWin32Traverser; symlink may link to different volume => redetermine volume serial!
+ }
+ catch (NeedFallbackToWin32Traverser&) { traverse<Win32Traverser>(fullName, *trav, 0); }
}
}
else //a file
@@ -410,7 +421,11 @@ private:
if (TraverseCallback* trav = sink.onDir(shortName, fullName))
{
ZEN_ON_SCOPE_EXIT(sink.releaseDirTraverser(trav));
- traverse<Trav>(fullName, *trav, volumeSerial);
+ try
+ {
+ traverse<Trav>(fullName, *trav, volumeSerial); //throw NeedFallbackToWin32Traverser
+ }
+ catch (NeedFallbackToWin32Traverser&) { traverse<Win32Traverser>(fullName, *trav, 0); }
}
}
else //a file
@@ -493,6 +508,12 @@ private:
class DirTraverser
{
public:
+ static void execute(const Zstring& baseDirectory, TraverseCallback& sink, DstHackCallback* dstCallback)
+ {
+ DirTraverser(baseDirectory, sink, dstCallback);
+ }
+
+private:
DirTraverser(const Zstring& baseDirectory, zen::TraverseCallback& sink, zen::DstHackCallback* dstCallback)
{
const Zstring directoryFormatted = //remove trailing slash
@@ -511,7 +532,6 @@ public:
traverse(directoryFormatted, sink);
}
-private:
DirTraverser(const DirTraverser&);
DirTraverser& operator=(const DirTraverser&);
@@ -658,5 +678,5 @@ private:
void zen::traverseFolder(const Zstring& dirname, TraverseCallback& sink, DstHackCallback* dstCallback)
{
- DirTraverser(dirname, sink, dstCallback);
+ DirTraverser::execute(dirname, sink, dstCallback);
}
diff --git a/zen/int64.h b/zen/int64.h
index 6901ebeb..f658e034 100644
--- a/zen/int64.h
+++ b/zen/int64.h
@@ -39,9 +39,6 @@ void checkRange(U value)
//caveat: std::numeric_limits<T>::min returns minimum positive(!) number for T = double, while behaving correctly for integer types... sigh
assert(double(std::numeric_limits<T>::lowest()) <= double(value) && //new with C++11!
double(std::numeric_limits<T>::max() ) >= double(value));
-
- // assert(double(boost::numeric::bounds<T>::lowest ()) <= double(value) &&
- // double(boost::numeric::bounds<T>::highest()) >= double(value));
}
class Int64
diff --git a/zen/osx_string.h b/zen/osx_string.h
index 38c54023..ba83ca27 100644
--- a/zen/osx_string.h
+++ b/zen/osx_string.h
@@ -15,7 +15,7 @@ namespace osx
Zstring cfStringToZstring(const CFStringRef& cfStr);
CFStringRef createCFString (const char* utf8Str); //returns nullptr on error
-CFMutableStringRef createMutableCFString(const char* utf8Str); //pass ownership! => ZEN_ON_SCOPE_EXIT(::CFRelease(utf8Str));
+CFMutableStringRef createMutableCFString(const char* utf8Str); //pass ownership! => ZEN_ON_SCOPE_EXIT(::CFRelease(str));
diff --git a/zen/privilege.cpp b/zen/privilege.cpp
index 98eaad43..90612756 100644
--- a/zen/privilege.cpp
+++ b/zen/privilege.cpp
@@ -1,6 +1,6 @@
#include "privilege.h"
#include <map>
-#include "thread.h" //includes <boost/thread.hpp>
+#include <mutex>
#include "zstring.h"
#include "scope_guard.h"
#include "win_ver.h"
@@ -127,12 +127,12 @@ private:
std::map<Zstring, bool> activePrivileges; //bool: enabled by this application
};
-boost::mutex lockPrivileges;
+std::mutex lockPrivileges;
}
void zen::activatePrivilege(LPCTSTR privilege) //throw FileError
{
- boost::lock_guard<boost::mutex> dummy(lockPrivileges);
+ std::lock_guard<std::mutex> dummy(lockPrivileges);
Privileges::getInstance().ensureActive(privilege);
}
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index 2bb4fd3f..92cd86ad 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -25,6 +25,9 @@ namespace zen
template <class V, class Predicate>
void vector_remove_if(V& vec, Predicate p);
+template <class V, class W>
+void vector_append(V& vec, W& vec2);
+
template <class S, class Predicate>
void set_remove_if(S& set, Predicate p);
@@ -88,6 +91,13 @@ void vector_remove_if(V& vec, Predicate p)
}
+template <class V, class W> inline
+void vector_append(V& vec, W& vec2)
+{
+vec.insert(vec.end(), vec2.begin(), vec2.end());
+}
+
+
template <class S, class Predicate> inline
void set_remove_if(S& set, Predicate p)
{
@@ -196,6 +206,7 @@ template<class T, class Arg1, class Arg2, class Arg3> inline std::u
template<class T, class Arg1, class Arg2, class Arg3, class Arg4> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4))); }
template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4, Arg5&& arg5) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4), std::forward<Arg5>(arg5))); }
template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4, Arg5&& arg5, Arg6&& arg6) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4), std::forward<Arg5>(arg5), std::forward<Arg6>(arg6))); }
+template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4, Arg5&& arg5, Arg6&& arg6, Arg7&& arg7) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4), std::forward<Arg5>(arg5), std::forward<Arg6>(arg6), std::forward<Arg7>(arg7))); }
//template<typename T, typename ...Args> inline
//std::unique_ptr<T> make_unique(Args&& ...args)
diff --git a/zen/string_base.h b/zen/string_base.h
index c828b240..0e3bbdd3 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -10,8 +10,8 @@
#include <algorithm>
#include <cassert>
#include <cstdint>
+#include <atomic>
#include "string_tools.h"
-#include <boost/detail/atomic_count.hpp>
//Zbase - a policy based string class optimizing performance and flexibility
@@ -168,15 +168,14 @@ protected:
private:
struct Descriptor
{
- Descriptor(long rc, size_t len, size_t cap) :
- refCount(rc),
+ Descriptor(int rc, size_t len, size_t cap) :
length (static_cast<std::uint32_t>(len)),
- capacity(static_cast<std::uint32_t>(cap)) {}
+ capacity(static_cast<std::uint32_t>(cap)),
+ refCount(rc) { assert_static(ATOMIC_INT_LOCK_FREE == 2); } //2: "the types are always lock-free"
- boost::detail::atomic_count refCount; //practically no perf loss: ~0.2%! (FFS comparison)
- //replace by #include <atomic> std::atomic_int when finally getting rid of VS2010
std::uint32_t length;
std::uint32_t capacity; //allocated size without null-termination
+ std::atomic<int> refCount; //practically no perf loss: ~0.2%! (FFS comparison)
};
static Descriptor* descr( Char* ptr) { return reinterpret_cast< Descriptor*>(ptr) - 1; }
diff --git a/zen/thread.h b/zen/thread.h
index 1fa2c951..5c6eecc5 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -184,7 +184,7 @@ template <class T>
template <class Fun> inline
void RunUntilFirstHit<T>::addJob(Fun f) //f must return a std::unique_ptr<T> containing a value on success
{
- auto result2 = result; //MSVC2010: this is ridiculous!!!
+ auto result2 = result; //MSVC 2010: this is ridiculous!!!
boost::thread t([result2, f] { result2->reportFinished(f()); });
++jobsTotal;
t.detach(); //we have to be explicit since C++11: [thread.thread.destr] ~thread() calls std::terminate() if joinable()!!!
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index 83eb5127..c33ea707 100644
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -17,7 +17,7 @@
#endif
#ifndef NDEBUG
-#include "thread.h" //includes <boost/thread.hpp>
+#include <mutex>
#include <iostream>
#endif
@@ -32,14 +32,14 @@ class LeakChecker //small test for memory leaks
public:
void insert(const void* ptr, size_t size)
{
- boost::lock_guard<boost::mutex> dummy(lockActStrings);
+ std::lock_guard<std::mutex> dummy(lockActStrings);
if (!activeStrings.insert(std::make_pair(ptr, size)).second)
reportProblem("Serious Error: New memory points into occupied space: " + rawMemToString(ptr, size));
}
void remove(const void* ptr)
{
- boost::lock_guard<boost::mutex> dummy(lockActStrings);
+ std::lock_guard<std::mutex> dummy(lockActStrings);
if (activeStrings.erase(ptr) != 1)
reportProblem("Serious Error: No memory available for deallocation at this location!");
}
@@ -89,7 +89,7 @@ private:
throw std::logic_error("Memory leak! " + message);
}
- boost::mutex lockActStrings;
+ std::mutex lockActStrings;
zen::hash_map<const void*, size_t> activeStrings;
};
bgstack15