[PATCH] Re: KDirWatch still crashes

Josef Weidendorfer Josef.Weidendorfer at gmx.de
Tue Apr 16 13:15:58 BST 2002


Hi,

I hope this time it's right:
In slotRescan(), every actual entry removal is delayed until all events are 
emitted. Can you check if this solves your problem?

Then I found a problem with FAM again ;-(
Some kind of showstopper: I recently installed Suse 8.0.
Using FAM, KDE3 has a deadlock while starting!
Reason: When monitoring a directory, FAM sends back Exist
events for each file in the directory. These events are
consumed in KDirWatch in the main event loop with QSocketNotifier.
Unfortunately, kded monitors MANY directories with LOTS of files
when starting, and the main loop isn't called in between.
Thus, with the big KMenu of Suse 8.0, a deadlock happens among
kded and fam, thus blocking the whole KDE startup.
Solution: call famEventReceived() after each FAM monitoring call.

Cheers,
Josef


On Sunday 14 April 2002 17:43, Michael Brade wrote:
> Hi!
>
> For me KDirWatch still crashes if removeDir is called within the slot
> connected to KDirWatch::dirty(..), the console says:
>
> kio (KDirWatch): KDirWatch-1 emitting dirty /home/michael
> kio (KDirListerCache): [void KDirListerCache::updateDirectory(const KURL
> &)] file:/home/michael
> kio (KDirWatch): Removed Dir /home/michael [KDirWatch-1]
> kio (KDirListerCache): [void KDirListerCache::updateDirectory(const KURL
> &)] directory file:/home/michael not in use, marked dirty.
> KCrash: crashing.... crashRecursionCounter = 2
>
> and the backtrace looks as follows:
> ...
> #5  0x410c8928 in sigaction () from /lib/libc.so.6
> #6  0x402f51d9 in KDirWatchPrivate::emitEvent (this=0x8276968, e=0x8278888,
>     event=1, fileName=@0x40ec7f64) at /opt/qt-3.0/include/qptrlist.h:94
> #7  0x402f661c in KDirWatchPrivate::slotRescan (this=0x8276968)
>     at /usr/src/KDE/kde-cvs/kdelibs/kio/kio/kdirwatch.cpp:906
> #8  0x402f90e0 in KDirWatchPrivate::qt_invoke (this=0x8276968, _id=2,
>     _o=0xbffff2b8) at kdirwatch_p.moc:85
> #9  0x40ab67b6 in QObject::activate_signal ()
>    from /opt/qt-3.0/lib/libqt-mt.so.3
>
> Thanks,

================================================

--- kdirwatch_p.h.orig      Fri Mar 22 11:19:54 2002
+++ kdirwatch_p.h       Mon Apr 15 21:45:09 2002
@@ -51,6 +51,7 @@ public:
     void addClient(KDirWatch*);
     void removeClient(KDirWatch*);
     int clients();
+    bool isValid() { return m_clients.count() || m_entries.count(); }

 #ifdef HAVE_FAM
     FAMRequest fr;
@@ -99,6 +100,9 @@ private:
   int m_nfsPollInterval, m_PollInterval;
   bool useStat(Entry*);

+  bool delayRemove;
+  QPtrList<Entry> removeList;
+
 #ifdef HAVE_FAM
   QSocketNotifier *sn;
   FAMConnection fc;

--- kdirwatch.cpp.orig  Mon Apr 15 20:35:11 2002
+++ kdirwatch.cpp       Tue Apr 16 00:08:39 2002
@@ -127,6 +127,7 @@ KDirWatchPrivate::KDirWatchPrivate()
   connect (timer, SIGNAL(timeout()), this, SLOT(slotRescan()));
   freq = 3600000; // 1 hour as upper bound
   statEntries = 0;
+  delayRemove = false;

   KConfigGroup config(KGlobal::config(), QCString("DirWatch"));
   m_nfsPollInterval = config.readNumEntry("NFSPollInterval", 5000);
@@ -349,6 +350,11 @@ bool KDirWatchPrivate::useFAM(Entry* e)
                    << ") for " << e->path << endl;
     }
   }
+
+  // handle FAM events to avoid deadlock
+  // (FAM sends back all files in a directory when monitoring)
+  famEventReceived();
+
   return true;
 }
 #endif
@@ -533,9 +534,15 @@ void KDirWatchPrivate::removeEntry( KDir
   else
     e->removeClient(instance);

-  if ( e->m_clients.count() || e->m_entries.count())
+  if (e->m_clients.count() || e->m_entries.count())
     return;

+  if (delayRemove) {
+    removeList.append(e);
+    // now e->isValid() is false
+    return;
+  }
+
 #ifdef HAVE_FAM
   if (e->m_mode == FAMMode) {
     if ( e->m_status == Normal) {
@@ -837,11 +844,6 @@ void KDirWatchPrivate::emitEvent(Entry*
   }
 }

-struct EmitEntry {
-  EmitEntry(QString _path, int _event)
-    : path(_path), event(_event) {};
-  QString path; int event;
-};

 /* Scan all entries to be watched for changes. This is done regularly
  * when polling and once after a DNOTIFY signal. This is NOT used by FAM.
@@ -850,10 +852,9 @@ void KDirWatchPrivate::slotRescan()
 {
   EntryMap::Iterator it;

-  // Buffer dirty entry paths, so that it won't crash if an app
-  // calls removeDir() in slotDirty().
-  QPtrList<EmitEntry> emitList;
-  emitList.setAutoDelete(true);
+  // We delay deletions of entries this way.
+  // removeDir(), when called in slotDirty(), can cause a crash otherwise
+  delayRemove = true;

 #ifdef HAVE_DNOTIFY
   QPtrList<Entry> dList, cList;
@@ -869,6 +870,9 @@ void KDirWatchPrivate::slotRescan()

   it = m_mapEntries.begin();
   for( ; it != m_mapEntries.end(); ++it ) {
+    // we don't check invalid entries (i.e. remove delayed)
+    if (!(*it).isValid()) continue;
+
     int ev = scanEntry( &(*it) );

 #ifdef HAVE_DNOTIFY
@@ -898,17 +902,13 @@ void KDirWatchPrivate::slotRescan()
 #endif

     if ( ev != NoChange )
-      emitList.append(new EmitEntry((*it).path, ev));
+      emitEvent( &(*it), ev);
   }

-  for(EmitEntry* e = emitList.first(); e; e = emitList.next() ) {
-    if (m_mapEntries.contains( e->path ))
-      emitEvent( & m_mapEntries[e->path], e->event);
-  }
+  Entry* e;

 #ifdef HAVE_DNOTIFY
   // Scan parent of deleted directories for new creation
-  Entry* e;
   for(e=dList.first();e;e=dList.next())
     addEntry(0, QDir::cleanDirPath( e->path+"/.."), e, true);

@@ -916,6 +916,12 @@ void KDirWatchPrivate::slotRescan()
   for(e=cList.first();e;e=cList.next())
     removeEntry(0, QDir::cleanDirPath( e->path+"/.."), e);
 #endif
+
+  // Really remove entries which were marked to be removed
+  delayRemove = false;
+  for(e=removeList.first();e;e=removeList.next())
+    removeEntry(0, e->path, 0);
+  removeList.clear();
 }

 #ifdef HAVE_FAM






More information about the kde-core-devel mailing list