[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    Re: [RFC] Use QFileSystemWatcher as another method for KDirWatch?
From:       Christian Ehrlicher <Ch.Ehrlicher () gmx ! de>
Date:       2007-12-05 19:24:27
Message-ID: 4756FAEB.80208 () gmx ! de
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


Christian Ehrlicher schrieb:
> Hi,
> 
> Using kdirwatch on windows is very cpu consuming (kded sometimes use 40% cpu on my \
> duron 1300). Therefore I want to implement QFileSystemWatcher as an optional \
> method. Is there a reason why this should not work? Should it be an optional or a \
> hard dependency? 
Ok, here the patch.

I enabled it only for windows to not get in trouble with 4.0.0. There's
a bug (task-tracker id 170021) which prevents watching directories on a
fat32 partition. It's fixed in 4.4 but it would be nice when this patch
could be applied to qt-copy.



Christian


["kdirwatch_qfsfileengine.patch" (text/x-diff)]

Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt	(revision 745174)
+++ CMakeLists.txt	(working copy)
@@ -31,6 +31,11 @@
 
 check_include_files(sys/inotify.h SYS_INOTIFY_H_FOUND)
 macro_bool_to_01(SYS_INOTIFY_H_FOUND HAVE_SYS_INOTIFY_H)
+if(WIN32)
+ # currently for win32 only --> enable it for all in 4.1?
+ OPTION(USE_QFILESYSTEMWATCHER "Use QFileSystemWatcher instead polling for KDirWatch" ON)
+ macro_bool_to_01(USE_QFILESYSTEMWATCHER HAVE_QFILESYSTEMWATCHER)
+endif(WIN32)
 
 configure_file(kio/config-kdirwatch.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kio/config-kdirwatch.h )
 
Index: kio/config-kdirwatch.h.cmake
===================================================================
--- kio/config-kdirwatch.h.cmake	(revision 745174)
+++ kio/config-kdirwatch.h.cmake	(working copy)
@@ -3,3 +3,5 @@
 #cmakedefine HAVE_INOTIFY 1
 
 #cmakedefine HAVE_SYS_INOTIFY_H 1
+
+#cmakedefine HAVE_QFILESYSTEMWATCHER 1
Index: kio/kdirwatch.cpp
===================================================================
--- kio/kdirwatch.cpp	(revision 745174)
+++ kio/kdirwatch.cpp	(working copy)
@@ -50,8 +50,10 @@
 #include <QtCore/QDir>
 #include <QtCore/QFile>
 #include <QtCore/QSocketNotifier>
-#include <QtCore/QMutableStringListIterator>
 #include <QtCore/QTimer>
+#ifdef HAVE_QFILESYSTEMWATCHER
+#include <QtCore/QFileSystemWatcher>
+#endif
 
 #include <kapplication.h>
 #include <kdebug.h>
@@ -122,16 +124,22 @@
   m_nfsPollInterval = config.readEntry("NFSPollInterval", 5000);
   m_PollInterval = config.readEntry("PollInterval", 500);
 
-  QString method = config.readEntry("PreferredMethod", "Fam"); 
+  QString method = config.readEntry("PreferredMethod", "Fam");
   if (method == "Fam")
   {
     m_preferredMethod = Fam;
   }else if (method == "Stat")
   {
     m_preferredMethod = Stat;
+  }else if (method == "QFSWatch") {
+    m_preferredMethod = QFSWatch;
   }else
   {
+#ifdef Q_OS_WIN
+    m_preferredMethod = QFSWatch;
+#else
     m_preferredMethod = INotify;
+#endif
   }
 
 
@@ -192,7 +200,12 @@
              this, SLOT( inotifyEventReceived() ) );
   }
 #endif
-
+#ifdef HAVE_QFILESYSTEMWATCHER
+  availableMethods << "QFileSystemWatcher";
+  fsWatcher = new QFileSystemWatcher();
+  connect(fsWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(fswEventReceived(QString)));
+  connect(fsWatcher, SIGNAL(fileChanged(QString)),      this, SLOT(fswEventReceived(QString)));
+#endif
   kDebug(7001) << "Available methods: " << availableMethods;
 }
 
@@ -213,6 +226,9 @@
   if ( supports_inotify )
     ::close( m_inotify_fd );
 #endif
+#ifdef HAVE_QFILESYSTEMWATCHER
+  delete fsWatcher;
+#endif
 }
 
 void KDirWatchPrivate::inotifyEventReceived()
@@ -353,7 +369,7 @@
 {
   if (instance == 0)
     return;
-  
+
   foreach(Client* client, m_clients) {
     if (client->instance == instance) {
       client->count++;
@@ -529,7 +545,22 @@
   return false;
 }
 #endif
+#ifdef HAVE_QFILESYSTEMWATCHER
+bool KDirWatchPrivate::useQFSWatch(Entry* e)
+{
+  e->m_mode = QFSWatchMode;
+  e->dirty = false;
 
+  if ( e->m_status == NonExistent ) {
+    addEntry( 0, QDir::cleanPath( e->path + "/.." ), e, true );
+    return true;
+  }
+
+  fsWatcher->addPath( e->path );
+  return true;
+}
+#endif
+
 bool KDirWatchPrivate::useStat(Entry* e)
 {
   KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByPath(e->path);
@@ -668,7 +699,7 @@
     } else if (watchModes & KDirWatch::WatchFiles) {
       filters |= QDir::Files;
     }
- 
+
     QDir basedir (e->path);
     QFileInfoList contents = basedir.entryInfoList(filters);
     for (QFileInfoList::iterator iter = contents.begin();
@@ -680,11 +711,11 @@
                 isDir ? watchModes : KDirWatch::WatchDirOnly);
     }
   }
-  
+
   // Now I've put inotify check before famd one, otherwise famd will be used
   // also when inotify is available. Since inotify works
   // better than famd, it is preferred to the last one
- 
+
   //First try to use the preferred method, if that fails use the usual order:
   //inotify,fam,stat
   bool entryAdded = false;
@@ -698,6 +729,11 @@
 #if defined(HAVE_SYS_INOTIFY_H)
     entryAdded = useINotify(e);
 #endif
+  }else if (m_preferredMethod == QFSWatch)
+  {
+#ifdef HAVE_QFILESYSTEMWATCHER
+    entryAdded = useQFSWatch(e);
+#endif
   }else if (m_preferredMethod == Stat)
   {
     entryAdded = useStat(e);
@@ -708,18 +744,22 @@
 #if defined(HAVE_SYS_INOTIFY_H)
     if (useINotify(e)) return;
 #endif
-  
+
 #if defined(HAVE_FAM)
     if (useFAM(e)) return;
 #endif
-  
+
+#if defined(HAVE_QFILESYSTEMWATCHER)
+    if (useQFSWatch(e)) return;
+#endif
+
     useStat(e);
   }
 }
 
 
 void KDirWatchPrivate::removeEntry( KDirWatch* instance,
-				    const QString& _path, Entry* sub_entry )
+                                    const QString& _path, Entry* sub_entry )
 {
   kDebug(7001)  << "KDirWatchPrivate::removeEntry for" << _path
                 << "sub_entry:" << sub_entry;
@@ -778,6 +818,11 @@
   }
 #endif
 
+#ifdef HAVE_QFILESYSTEMWATCHER
+  if (e->m_mode == QFSWatchMode) {
+    fsWatcher->removePath(e->path);
+  }
+#endif
   if (e->m_mode == StatMode) {
     statEntries--;
     if ( statEntries == 0 ) {
@@ -961,6 +1006,14 @@
   }
 #endif
 
+#if defined( USE_QFILSYSTEMWATCHER )
+  if (e->m_mode == QFSWatchMode ) {
+    // we know nothing has changed, no need to stat
+    if(!e->dirty) return NoChange;
+    e->dirty = false;
+  }
+#endif
+
   if (e->m_mode == StatMode) {
     // only scan if timeout on entry timer happens;
     // e.g. when using 500msec global timer, a entry
@@ -1012,7 +1065,7 @@
  * and stored pending events. When watching is stopped, the event is
  * added to the pending events.
  */
-void KDirWatchPrivate::emitEvent(Entry* e, int event, const QString &fileName)
+void KDirWatchPrivate::emitEvent(const Entry* e, int event, const QString &fileName)
 {
   QString path (e->path);
   if (!fileName.isEmpty()) {
@@ -1347,6 +1400,7 @@
                     << ((e->m_mode == FAMMode) ? "FAM" :
                         (e->m_mode == INotifyMode) ? "INotify" :
                         (e->m_mode == DNotifyMode) ? "DNotify" :
+                        (e->m_mode == QFSWatchMode) ? "QFSWatch" :
                         (e->m_mode == StatMode) ? "Stat" : "Unknown Method")
                     << ")";
 
@@ -1372,7 +1426,51 @@
   }
 }
 
+// Slots for QFileSystemWatcher
+void KDirWatchPrivate::fswEventReceived(const QString &path)
+{
+  EntryMap::Iterator it;
+  it = m_mapEntries.find(path);
+  if(it != m_mapEntries.end()) {
+    Entry* e = &(*it);
+    e->dirty = true;
+    int ev = scanEntry(e);
+    if (ev != NoChange)
+      emitEvent(e, ev);
+    if(ev == Deleted) {
+      if (e->isDir)
+        addEntry(0, QDir::cleanPath(e->path + "/.."), e, true);
+      else
+        addEntry(0, QFileInfo(e->path).absolutePath(), e, true);
+    } else
+    if (ev == Changed && e->isDir && e->m_entries.count()) {
+      Entry* sub_entry = 0;
+      Q_FOREACH(sub_entry, e->m_entries) {
+        if(e->isDir) {
+          if (QFileInfo(sub_entry->path).isDir())
+            break;
+        } else {
+          if (QFileInfo(sub_entry->path).isFile())
+            break;
+        }
+      }
+      if (sub_entry) {
+        removeEntry(0, e->path, sub_entry);
+        KDE_struct_stat stat_buf;
+        QByteArray tpath = QFile::encodeName(path);
+        KDE_stat(tpath, &stat_buf);
 
+        if(!useQFSWatch(sub_entry))
+#ifdef HAVE_SYS_INOTIFY_H
+          if(!useINotify(sub_entry))
+#endif
+            useStat(sub_entry);
+        fswEventReceived(sub_entry->path);
+      }
+    }
+  }
+}
+
 //
 // Class KDirWatch
 //
Index: kio/kdirwatch.h
===================================================================
--- kio/kdirwatch.h	(revision 745174)
+++ kio/kdirwatch.h	(working copy)
@@ -18,10 +18,9 @@
 #ifndef _KDIRWATCH_H
 #define _KDIRWATCH_H
 
-#include <QtCore/QTimer>
-#include <QtCore/QDate>
-#include <QtCore/QMap>
-#include <QtCore/QSocketNotifier>
+#include <QtCore/QDateTime>
+#include <QtCore/QObject>
+#include <QtCore/QString>
 
 #include <kio/kio_export.h>
 
@@ -75,7 +74,7 @@
       WatchSubDirs = 0x02 ///< Watch also all the subdirs contained by the directory
     };
     Q_DECLARE_FLAGS(WatchModes, WatchMode)
-   
+
    /**
     * Constructor.
     *
Index: kio/kdirwatch_p.h
===================================================================
--- kio/kdirwatch_p.h	(revision 745174)
+++ kio/kdirwatch_p.h	(working copy)
@@ -29,6 +29,14 @@
 #include <config-kdirwatch.h>
 #include "kdirwatch.h"
 
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QTimer>
+class QFileSystemWatcher;
+class QSocketNotifier;
+
 #ifdef HAVE_FAM
 #include <limits.h>
 #include <fam.h>
@@ -63,11 +71,11 @@
 public:
 
   enum entryStatus { Normal = 0, NonExistent };
-  enum entryMode { UnknownMode = 0, StatMode, DNotifyMode, INotifyMode, FAMMode };
+  enum entryMode { UnknownMode = 0, StatMode, DNotifyMode, INotifyMode, FAMMode, QFSWatchMode };
   enum { NoChange=0, Changed=1, Created=2, Deleted=4 };
 
 
-  enum WatchMethod { Stat, Fam, INotify };
+  enum WatchMethod { Stat, Fam, INotify, QFSWatch };
 
   struct Client {
     KDirWatch* instance;
@@ -134,7 +142,7 @@
 
   Entry* entry(const QString&);
   int scanEntry(Entry* e);
-  void emitEvent(Entry* e, int event, const QString &fileName = QString());
+  void emitEvent(const Entry* e, int event, const QString &fileName = QString());
 
   // Memory management - delete when last KDirWatch gets deleted
   void ref() { m_ref++; }
@@ -147,6 +155,7 @@
   void famEventReceived(); // for FAM
   void inotifyEventReceived(); // for inotify
   void slotRemoveDelayed();
+  void fswEventReceived(const QString &path);  // for QFileSystemWatcher
 
 public:
   QTimer timer;
@@ -181,6 +190,10 @@
 
   bool useINotify(Entry*);
 #endif
+#ifdef HAVE_QFILESYSTEMWATCHER
+  QFileSystemWatcher *fsWatcher;
+  bool useQFSWatch(Entry* e);
+#endif
 
   bool _isStopped;
 };

["signature.asc" (application/pgp-signature)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic