From d32895c5d83d767fb9dc4a7eb489efe1195f47e8 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 7 Oct 2013 09:58:51 +0000 Subject: [PATCH] Generate events with specific wxFSW_WARNING_OVERFLOW type if applicable. This allows the program to distinguish between some other, unspecified, warnings and this one which can and does happen whenever too many changes occur too quickly but which has a clearly defined work around: the state kept inside the program just needs to be refreshed by rescanning the directory anew. See #12847. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74950 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + include/wx/fswatcher.h | 34 ++++++++++++++++++--- interface/wx/fswatcher.h | 55 ++++++++++++++++++++++++++++++++-- src/common/fswatchercmn.cpp | 5 ++++ src/msw/fswatcher.cpp | 30 +++++++++++++++++-- src/unix/fswatcher_inotify.cpp | 33 ++++++++++---------- 6 files changed, 130 insertions(+), 28 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 65a709bcf4..738638a7f6 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -565,6 +565,7 @@ All: - Adjust dates invalid due to DST consistently under all platforms in wxDateTime. - Allow using custom HTTP methods with wxHTTP (Kolya Kosenko). - Add wxFileName::SetPermissions() (Catalin Raceanu). +- Add specific wxFSW_WARNING_OVERFLOW warning type (Rob Bresalier). - Fix build with wxUSE_FFILE==0 (jroemmler). - Add wxDEPRECATED_MSG() and use it in a few places. - Return the old file descriptor/pointer from wx(F)File::Detach() (troelsk). diff --git a/include/wx/fswatcher.h b/include/wx/fswatcher.h index 2955407864..056780d348 100644 --- a/include/wx/fswatcher.h +++ b/include/wx/fswatcher.h @@ -66,6 +66,13 @@ enum wxFSWPathType wxFSWPath_Tree // Watch a directory and all its children recursively. }; +// Type of the warning for the events notifying about them. +enum wxFSWWarningType +{ + wxFSW_WARNING_NONE, + wxFSW_WARNING_GENERAL, + wxFSW_WARNING_OVERFLOW +}; /** * Event containing information about file system change. @@ -77,24 +84,36 @@ wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_BASE, wxEVT_FSWATCHER, class WXDLLIMPEXP_BASE wxFileSystemWatcherEvent: public wxEvent { public: + // Constructor for any kind of events, also used as default ctor. wxFileSystemWatcherEvent(int changeType = 0, int watchid = wxID_ANY) : wxEvent(watchid, wxEVT_FSWATCHER), - m_changeType(changeType) + m_changeType(changeType), + m_warningType(wxFSW_WARNING_NONE) { } - wxFileSystemWatcherEvent(int changeType, const wxString& errorMsg, + // Constructor for the error or warning events. + wxFileSystemWatcherEvent(int changeType, + wxFSWWarningType warningType, + const wxString& errorMsg = wxString(), int watchid = wxID_ANY) : wxEvent(watchid, wxEVT_FSWATCHER), - m_changeType(changeType), m_errorMsg(errorMsg) + m_changeType(changeType), + m_warningType(warningType), + m_errorMsg(errorMsg) { } + // Constructor for the normal events carrying information about the changes. wxFileSystemWatcherEvent(int changeType, const wxFileName& path, const wxFileName& newPath, int watchid = wxID_ANY) : wxEvent(watchid, wxEVT_FSWATCHER), - m_changeType(changeType), m_path(path), m_newPath(newPath) + m_changeType(changeType), + m_warningType(wxFSW_WARNING_NONE), + m_path(path), + m_newPath(newPath) + { } @@ -146,6 +165,7 @@ public: evt->m_errorMsg = m_errorMsg.Clone(); evt->m_path = wxFileName(m_path.GetFullPath().Clone()); evt->m_newPath = wxFileName(m_newPath.GetFullPath().Clone()); + evt->m_warningType = m_warningType; return evt; } @@ -168,6 +188,11 @@ public: return m_errorMsg; } + wxFSWWarningType GetWarningType() const + { + return m_warningType; + } + /** * Returns a wxString describing an event useful for debugging or testing */ @@ -175,6 +200,7 @@ public: protected: int m_changeType; + wxFSWWarningType m_warningType; wxFileName m_path; wxFileName m_newPath; wxString m_errorMsg; diff --git a/interface/wx/fswatcher.h b/interface/wx/fswatcher.h index c89ae09c51..cd4cd29a6f 100644 --- a/interface/wx/fswatcher.h +++ b/interface/wx/fswatcher.h @@ -156,11 +156,15 @@ public: class wxFileSystemWatcherEvent : public wxEvent { public: - wxFileSystemWatcherEvent(int changeType = 0, int watchid = wxID_ANY); - wxFileSystemWatcherEvent(int changeType, const wxString& errorMsg, + wxFileSystemWatcherEvent(int changeType = 0, int watchid = wxID_ANY); wxFileSystemWatcherEvent(int changeType, - const wxFileName& path, const wxFileName& newPath, + wxFSWWarningType warningType, + const wxString& errorMsg, + int watchid = wxID_ANY); + wxFileSystemWatcherEvent(int changeType, + const wxFileName& path, + const wxFileName& newPath, int watchid = wxID_ANY); /** @@ -192,9 +196,22 @@ public: /** Return a description of the warning or error if this is an error event. + + This string may be empty if the exact reason for the error or the + warning is not known. */ wxString GetErrorDescription() const; + /** + Return the type of the warning if this event is a warning one. + + If this is not a warning event, i.e. if GetChangeType() doesn't include + ::wxFSW_EVENT_WARNING, returns ::wxFSW_WARNING_NONE. + + @since 3.0 + */ + wxFSWWarningType GetWarningType() const; + /** Returns a wxString describing an event, useful for logging, debugging or testing. @@ -294,3 +311,35 @@ enum wxFSWFlags wxFSW_EVENT_WARNING | wxFSW_EVENT_ERROR }; +/** + Possible warning types for the warning events generated by + wxFileSystemWatcher. + + @since 3.0 + */ +enum wxFSWWarningType +{ + /** + This is not a warning at all. + */ + wxFSW_WARNING_NONE, + + /** + A generic warning. + + Further information may be provided in the user-readable message + available from wxFileSystemWatcherEvent::GetErrorDescription() + */ + wxFSW_WARNING_GENERAL, + + /** + An overflow event. + + This warning indicates that some file system changes were not signaled + by any events, usually because there were too many of them and the + internally used queue has overflown. If such event is received it is + recommended to completely rescan the files or directories being + monitored. + */ + wxFSW_WARNING_OVERFLOW +}; diff --git a/src/common/fswatchercmn.cpp b/src/common/fswatchercmn.cpp index 1de2422183..66fb869e9c 100644 --- a/src/common/fswatchercmn.cpp +++ b/src/common/fswatchercmn.cpp @@ -65,6 +65,11 @@ IMPLEMENT_DYNAMIC_CLASS(wxFileSystemWatcherEvent, wxEvent); wxString wxFileSystemWatcherEvent::ToString() const { + if (IsError()) + { + return wxString::Format("FSW_EVT type=%d (%s) message='%s'", m_changeType, + GetFSWEventChangeTypeName(m_changeType), GetErrorDescription()); + } return wxString::Format("FSW_EVT type=%d (%s) path='%s'", m_changeType, GetFSWEventChangeTypeName(m_changeType), GetPath().GetFullPath()); } diff --git a/src/msw/fswatcher.cpp b/src/msw/fswatcher.cpp index 7546f03a48..d179f67155 100644 --- a/src/msw/fswatcher.cpp +++ b/src/msw/fswatcher.cpp @@ -231,6 +231,29 @@ bool wxIOCPThread::ReadEvents() if (!count && !watch && !overlapped) return false; + // if the thread got woken up but we got an empty packet it means that + // there was an overflow, too many events and not all could fit in + // the watch buffer. In this case, ReadDirectoryChangesW dumps the + // buffer. + if (!count && watch) + { + wxLogTrace(wxTRACE_FSWATCHER, "[iocp] Event queue overflowed: path=\"%s\"", + watch->GetPath()); + + if (watch->GetFlags() & wxFSW_EVENT_WARNING) + { + wxFileSystemWatcherEvent + overflowEvent(wxFSW_EVENT_WARNING, wxFSW_WARNING_OVERFLOW); + overflowEvent.SetPath(watch->GetPath()); + SendEvent(overflowEvent); + } + + // overflow is not a fatal error, we still want to get future events + // reissue the watch + (void) m_service->SetUpWatch(*watch); + return true; + } + // in case of spurious wakeup if (!count || !watch) return true; @@ -283,9 +306,10 @@ void wxIOCPThread::ProcessNativeEvents(wxVector& events) int flags = Native2WatcherFlags(nativeFlags); if (flags & wxFSW_EVENT_WARNING || flags & wxFSW_EVENT_ERROR) { - // TODO think about this...do we ever have any errors to report? - wxString errMsg = "Error occurred"; - wxFileSystemWatcherEvent event(flags, errMsg); + wxFileSystemWatcherEvent + event(flags, + flags & wxFSW_EVENT_ERROR ? wxFSW_WARNING_NONE + : wxFSW_WARNING_GENERAL); SendEvent(event); } // filter out ignored events and those not asked for. diff --git a/src/unix/fswatcher_inotify.cpp b/src/unix/fswatcher_inotify.cpp index 117a036d4e..694beecedf 100644 --- a/src/unix/fswatcher_inotify.cpp +++ b/src/unix/fswatcher_inotify.cpp @@ -256,6 +256,7 @@ protected: event ( wxFSW_EVENT_WARNING, + wxFSW_WARNING_GENERAL, wxString::Format ( _("Unexpected event for \"%s\": no " @@ -279,8 +280,19 @@ protected: // check out for error/warning condition if (flags & wxFSW_EVENT_WARNING || flags & wxFSW_EVENT_ERROR) { - wxString errMsg = GetErrorDescription(nativeFlags); - wxFileSystemWatcherEvent event(flags, errMsg); + wxFSWWarningType warningType; + if ( flags & wxFSW_EVENT_WARNING ) + { + warningType = nativeFlags & IN_Q_OVERFLOW + ? wxFSW_WARNING_OVERFLOW + : wxFSW_WARNING_GENERAL; + } + else // It's an error, not a warning. + { + warningType = wxFSW_WARNING_NONE; + } + + wxFileSystemWatcherEvent event(flags, warningType); SendEvent(event); return; } @@ -293,6 +305,7 @@ protected: event ( wxFSW_EVENT_WARNING, + wxFSW_WARNING_GENERAL, wxString::Format ( _("Invalid inotify event for \"%s\""), @@ -628,22 +641,6 @@ protected: return -1; } - /** - * Returns error description for specified inotify mask - */ - static const wxString GetErrorDescription(int flag) - { - switch ( flag ) - { - case IN_Q_OVERFLOW: - return _("Event queue overflowed"); - } - - // never reached - wxFAIL_MSG(wxString::Format("Unknown inotify event mask %u", flag)); - return wxEmptyString; - } - wxFSWSourceHandler* m_handler; // handler for inotify event source wxFSWatchEntryDescriptors m_watchMap; // inotify wd=>wxFSWatchEntry* map wxArrayInt m_staleDescriptors; // stores recently-removed watches