Changeset 374


Ignore:
Timestamp:
Dec 3, 2009, 2:17:13 AM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

corelib/io: Improved the polling QFileSystemWatcher implementation so that it doesn't eat all CPU when there are more than 100 items to watch any more.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/corelib/io/qfilesystemwatcher.cpp

    r2 r374  
    5151#include <qmutex.h>
    5252#include <qset.h>
    53 #include <qtimer.h>
     53#include <q.h>
    5454
    5555#if defined(Q_OS_WIN)
     
    6464QT_BEGIN_NAMESPACE
    6565
    66 enum { PollingInterval = 1000 };
    67 
    6866class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine
    6967{
    70     Q_OBJECT
     68    enum {
     69        SmallPollingInterval = 50,  // time to wait after checking each watched
     70                                    // item, ms
     71        BigPollingInterval = 1000,  // time to wait after checking all watched
     72                                    // items, ms
     73    };
    7174
    7275    class FileInfo
     
    8487              permissions(fileInfo.permissions()),
    8588              lastModified(fileInfo.lastModified())
    86         { 
     89        {
    8790            if (fileInfo.isDir()) {
    8891                entries = fileInfo.absoluteDir().entryList(QDir::AllEntries);
     
    119122    void stop();
    120123
    121 private slots:
    122     void timeout();
     124private:
     125    QWaitCondition waitCond;
     126    bool askedToFinish;
     127    bool startOver;
    123128};
    124129
    125130QPollingFileSystemWatcherEngine::QPollingFileSystemWatcherEngine()
     131
    126132{
    127133#ifndef QT_NO_THREAD
     
    132138void QPollingFileSystemWatcherEngine::run()
    133139{
    134     QTimer timer;
    135     connect(&timer, SIGNAL(timeout()), SLOT(timeout()));
    136     timer.start(PollingInterval);
    137     (void) exec();
     140    mutex.lock();
     141
     142    forever {
     143        startOver = false;
     144        QMutableHashIterator<QString, FileInfo> fit(files);
     145        while (!startOver && fit.hasNext()) {
     146            QHash<QString, FileInfo>::iterator x = fit.next();
     147            QString path = x.key();
     148            QFileInfo fi(path);
     149            if (!fi.exists()) {
     150                fit.remove();
     151                emit fileChanged(path, true);
     152            } else if (x.value() != fi) {
     153                x.value() = fi;
     154                emit fileChanged(path, false);
     155            }
     156            waitCond.wait(&mutex, SmallPollingInterval);
     157        }
     158        QMutableHashIterator<QString, FileInfo> dit(directories);
     159        while (!startOver && dit.hasNext()) {
     160            QHash<QString, FileInfo>::iterator x = dit.next();
     161            QString path = x.key();
     162            QFileInfo fi(path);
     163            if (!path.endsWith(QLatin1Char('/')))
     164                fi = QFileInfo(path + QLatin1Char('/'));
     165            if (!fi.exists()) {
     166                dit.remove();
     167                emit directoryChanged(path, true);
     168            } else if (x.value() != fi) {
     169                x.value() = fi;
     170                emit directoryChanged(path, false);
     171            }
     172            waitCond.wait(&mutex, SmallPollingInterval);
     173        }
     174        if (!startOver && !askedToFinish) {
     175            waitCond.wait(&mutex, BigPollingInterval);
     176        }
     177        if (askedToFinish) {
     178            askedToFinish = false;
     179            break;
     180        }
     181    }
     182
     183    mutex.unlock();
    138184}
    139185
     
    156202                fi = QFileInfo(path + QLatin1Char('/'));
    157203            this->directories.insert(path, fi);
     204
    158205        } else {
    159206            if (!files->contains(path))
    160207                files->append(path);
    161208            this->files.insert(path, fi);
     209
    162210        }
    163211        it.remove();
    164212    }
    165     start();
     213    start();
    166214    return p;
    167215}
     
    179227            directories->removeAll(path);
    180228            it.remove();
     229
    181230        } else if (this->files.remove(path)) {
    182231            files->removeAll(path);
    183232            it.remove();
     233
    184234        }
    185235    }
    186236    if (this->files.isEmpty() && this->directories.isEmpty()) {
     237
     238
    187239        locker.unlock();
    188         stop();
    189240        wait();
    190241    }
     
    194245void QPollingFileSystemWatcherEngine::stop()
    195246{
    196     QMetaObject::invokeMethod(this, "quit");
    197 }
    198 
    199 void QPollingFileSystemWatcherEngine::timeout()
    200 {
    201247    QMutexLocker locker(&mutex);
    202     QMutableHashIterator<QString, FileInfo> fit(files);
    203     while (fit.hasNext()) {
    204         QHash<QString, FileInfo>::iterator x = fit.next();
    205         QString path = x.key();
    206         QFileInfo fi(path);
    207         if (!fi.exists()) {
    208             fit.remove();
    209             emit fileChanged(path, true);
    210         } else if (x.value() != fi) {
    211             x.value() = fi;
    212             emit fileChanged(path, false);
    213         }
    214     }
    215     QMutableHashIterator<QString, FileInfo> dit(directories);
    216     while (dit.hasNext()) {
    217         QHash<QString, FileInfo>::iterator x = dit.next();
    218         QString path = x.key();
    219         QFileInfo fi(path);
    220         if (!path.endsWith(QLatin1Char('/')))
    221             fi = QFileInfo(path + QLatin1Char('/'));
    222         if (!fi.exists()) {
    223             dit.remove();
    224             emit directoryChanged(path, true);
    225         } else if (x.value() != fi) {
    226             x.value() = fi;
    227             emit directoryChanged(path, false);
    228         }
    229        
    230     }
    231 }
    232 
    233 
     248    startOver = true;
     249    askedToFinish = true;
     250    waitCond.wakeAll();
     251}
    234252
    235253
     
    615633#include "moc_qfilesystemwatcher.cpp"
    616634
    617 #include "qfilesystemwatcher.moc"
    618 
    619635#endif // QT_NO_FILESYSTEMWATCHER
    620636
Note: See TracChangeset for help on using the changeset viewer.