X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6b8ef0b35d674bc262eb2005ac1321762c831d31..1ee968ea97b66a9795f76c4030874be0faa632d5:/src/unix/fswatcher_inotify.cpp diff --git a/src/unix/fswatcher_inotify.cpp b/src/unix/fswatcher_inotify.cpp index 229af98eee..675d1168e3 100644 --- a/src/unix/fswatcher_inotify.cpp +++ b/src/unix/fswatcher_inotify.cpp @@ -45,8 +45,8 @@ class wxFSWatcherImplUnix : public wxFSWatcherImpl public: wxFSWatcherImplUnix(wxFileSystemWatcherBase* watcher) : wxFSWatcherImpl(watcher), - m_loop(NULL), - m_source(NULL) + m_source(NULL), + m_ifd(-1) { m_handler = new wxFSWSourceHandler(this); } @@ -65,42 +65,38 @@ public: bool Init() { wxCHECK_MSG( !IsOk(), false, "Inotify already initialized" ); - wxCHECK_MSG( m_loop == NULL, false, "Event loop != NULL"); - m_loop = (wxEventLoopBase::GetActive()); - wxCHECK_MSG( m_loop, false, "File system watcher needs an active loop" ); + wxEventLoopBase *loop = wxEventLoopBase::GetActive(); + wxCHECK_MSG( loop, false, "File system watcher needs an event loop" ); - int fd = inotify_init(); - if (fd == -1) + m_ifd = inotify_init(); + if ( m_ifd == -1 ) { wxLogSysError( _("Unable to create inotify instance") ); return false; } - int flags = wxEVENT_SOURCE_INPUT | wxEVENT_SOURCE_EXCEPTION; - m_source = static_cast( - m_loop->CreateSource(fd, m_handler, flags)); - return RegisterSource(); + m_source = loop->AddSourceForFD + ( + m_ifd, + m_handler, + wxEVENT_SOURCE_INPUT | wxEVENT_SOURCE_EXCEPTION + ); + + return m_source != NULL; } - bool Close() + void Close() { - wxCHECK_MSG( IsOk(), false, + wxCHECK_RET( IsOk(), "Inotify not initialized or invalid inotify descriptor" ); - wxCHECK_MSG( m_loop, false, - "m_loop shouldn't be null if inotify is initialized" ); - // ignore errors - (void) UnregisterSource(); + wxDELETE(m_source); - int ret = close(m_source->GetResource()); - if (ret == -1) + if ( close(m_ifd) != 0 ) { wxLogSysError( _("Unable to close inotify instance") ); } - m_source->Invalidate(); - - return ret != -1; } virtual bool DoAdd(wxSharedPtr watch) @@ -143,6 +139,9 @@ public: wxFAIL_MSG( wxString::Format("Path %s is not watched", watch->GetPath()) ); } + // Cache the wd in case any events arrive late + m_staleDescriptors.Add(watch->GetWatchDescriptor()); + watch->SetWatchDescriptor(-1); return true; } @@ -193,39 +192,16 @@ public: return event_count; } - bool IsOk() + bool IsOk() const { - return m_source && m_source->IsOk(); + return m_source != NULL; } protected: - bool RegisterSource() - { - wxCHECK_MSG( IsOk(), false, - "Inotify not initialized or invalid inotify descriptor" ); - - bool ret = m_loop->AddSource(m_source); - return ret; - } - - bool UnregisterSource() - { - wxCHECK_MSG( IsOk(), false, - "Inotify not initialized or invalid inotify descriptor" ); - wxCHECK_MSG( m_loop, false, - "m_loop shouldn't be null if inotify is initialized" ); - - bool ret = m_loop->RemoveSource(m_source); - m_loop = NULL; - return ret; - } - int DoAddInotify(wxFSWatchEntry* watch) { int flags = Watcher2NativeFlags(watch->GetFlags()); - int wd = inotify_add_watch(m_source->GetResource(), - watch->GetPath().fn_str(), - flags); + int wd = inotify_add_watch(m_ifd, watch->GetPath().fn_str(), flags); // finally we can set watch descriptor watch->SetWatchDescriptor(wd); return wd; @@ -233,8 +209,7 @@ protected: int DoRemoveInotify(wxFSWatchEntry* watch) { - return inotify_rm_watch(m_source->GetResource(), - watch->GetWatchDescriptor()); + return inotify_rm_watch(m_ifd, watch->GetWatchDescriptor()); } void ProcessNativeEvent(const inotify_event& inevt) @@ -245,13 +220,33 @@ protected: // will be already removed from our list at that time if (inevt.mask & IN_IGNORED) { + // It is now safe to remove it from the stale descriptors too, we + // won't get any more events for it. + m_staleDescriptors.Remove(inevt.wd); + wxLogTrace(wxTRACE_FSWATCHER, + "Removed wd %i from the stale-wd cache", inevt.wd); return; } // get watch entry for this event wxFSWatchEntryDescriptors::iterator it = m_watchMap.find(inevt.wd); - wxCHECK_RET(it != m_watchMap.end(), - "Watch descriptor not present in the watch map!"); + if (it == m_watchMap.end()) + { + // It's not in the map; check if was recently removed from it. + if (m_staleDescriptors.Index(inevt.wd) != wxNOT_FOUND) + { + wxLogTrace(wxTRACE_FSWATCHER, + "Got an event for stale wd %i", inevt.wd); + } + else + { + wxFAIL_MSG("Event for unknown watch descriptor."); + } + + // In any case, don't process this event: it's either for an + // already removed entry, or for a completely unknown one. + return; + } wxFSWatchEntry& watch = *(it->second); int nativeFlags = inevt.mask; @@ -352,7 +347,7 @@ protected: "Inotify not initialized or invalid inotify descriptor" ); memset(buf, 0, size); - ssize_t left = read(m_source->GetResource(), buf, size); + ssize_t left = read(m_ifd, buf, size); if (left == -1) { wxLogSysError(_("Unable to read from inotify descriptor")); @@ -372,9 +367,12 @@ protected: wxString mask = (inevt.mask & IN_ISDIR) ? wxString::Format("IS_DIR | %u", inevt.mask & ~IN_ISDIR) : wxString::Format("%u", inevt.mask); + const char* name = ""; + if (inevt.len) + name = inevt.name; return wxString::Format("Event: wd=%d, mask=%s, cookie=%u, len=%u, " "name=%s", inevt.wd, mask, inevt.cookie, - inevt.len, inevt.name); + inevt.len, name); } static wxFileName GetEventPath(const wxFSWatchEntry& watch, @@ -382,7 +380,7 @@ protected: { // only when dir is watched, we have non-empty e.name wxFileName path = watch.GetPath(); - if (path.IsDir()) + if (path.IsDir() && inevt.len) { path = wxFileName(path.GetPath(), inevt.name); } @@ -450,9 +448,12 @@ protected: wxFSWSourceHandler* m_handler; // handler for inotify event source wxFSWatchEntryDescriptors m_watchMap; // inotify wd=>wxFSWatchEntry* map + wxArrayInt m_staleDescriptors; // stores recently-removed watches wxInotifyCookies m_cookies; // map to track renames - wxEventLoopBase* m_loop; - wxUnixEventLoopSource* m_source; // our event loop source + wxEventLoopSource* m_source; // our event loop source + + // file descriptor created by inotify_init() + int m_ifd; };