diff options
author | Arno <am@disconnect.de> | 2013-03-21 16:14:54 +0100 |
---|---|---|
committer | Arno <am@disconnect.de> | 2013-03-21 16:14:54 +0100 |
commit | ce402f298b2f9733b614fbf1bde99a052d0ab5c0 (patch) | |
tree | 26da14cacb2e4fffcab47cf0a61d066568a15e7a /smdirwatcher.cpp | |
parent | 03831d3669ea49a99a15aaf5d17724be8c533b85 (diff) | |
download | SheMov-ce402f298b2f9733b614fbf1bde99a052d0ab5c0.tar.gz SheMov-ce402f298b2f9733b614fbf1bde99a052d0ab5c0.tar.bz2 SheMov-ce402f298b2f9733b614fbf1bde99a052d0ab5c0.zip |
Final inotify!
A huge commit, I know, but it was definitely worth it! It makes the
homebrew FilesystemModel work! It's divided up into two threads:
1. The Watcher: it reacts on inotify events and dispatches them to:
2. The Collector: this thread gathers the data and emits the SIGNALS to
the the view.
Now we can actually refresh the View, not possible with
QFileSystemModel, and the data reloads in almost real time without
blocking the GUI.
Unfortunately this uncovered some bugs I had to fix:
1. Helper::md5sum: Don't crash if read fails with -1
2. SmTreeModel::addRow is broken. Even after 5h I couldn't figure out
how or why, so I brute forced it. Reset the moded when a file is added.
3. Get rid of a lot of unneeded #include's
I guess that's about it...
Diffstat (limited to 'smdirwatcher.cpp')
-rw-r--r-- | smdirwatcher.cpp | 107 |
1 files changed, 56 insertions, 51 deletions
diff --git a/smdirwatcher.cpp b/smdirwatcher.cpp index 8650d3b..8b72aab 100644 --- a/smdirwatcher.cpp +++ b/smdirwatcher.cpp @@ -9,6 +9,7 @@ #include <QMutexLocker> #include <QDateTime> #include <QDir> +#include <QSemaphore> #include <sys/inotify.h> #include <stropts.h> @@ -23,17 +24,26 @@ extern int errno; SmDirWatcher::SmDirWatcher(QObject *parent) : QThread(parent), mFd(0), mDescr(0) { - mFd = inotify_init1(IN_NONBLOCK); + mBufLen = 1024 * (sizeof(struct inotify_event) + 16); + mINdata = new char[mBufLen]; + mFd = inotify_init(); + + mCollector = new SmDataColletor(8, this); + mSemFree = new QSemaphore(1024); + mSemUsed = new QSemaphore; + mDataQueue = new QQueue<QPair<QString, DWEvent> >(); + mCollector->init(mSemFree, mSemUsed, mDataQueue); + mCollector->start(); } SmDirWatcher::~SmDirWatcher(){ if(mFd && mDescr){ inotify_rm_watch(mFd, mDescr); } + delete mINdata; } void SmDirWatcher::setDir(const QString &dir){ - QMutexLocker lock(&mWatchMx); if(mDescr){ inotify_rm_watch(mFd, mDescr); //generates IN_IGNORE ??? } @@ -44,78 +54,73 @@ void SmDirWatcher::setDir(const QString &dir){ */ mDescr = inotify_add_watch(mFd, qPrintable(dir), IN_CLOSE_WRITE | IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO); mCurrent = dir; + mSemFree->acquire(); + QPair<QString, DWEvent> c = qMakePair(dir, Populate); + mDataQueue->enqueue(c); + mSemUsed->release(); } void SmDirWatcher::run(){ - QMutexLocker lock(&mWatchMx); - QVarLengthArray<char, 4096> data(4096); - int r = read(mFd, data.data(), data.size()); - int err = errno; - if(r < 0){ - if(err != EAGAIN){ - return; - } - r = read(mFd, data.data(), data.size()); - } - // inspect data - char *at = data.data(); - inotify_event *e = reinterpret_cast<inotify_event*>(at); - if(!e->len){ + int r = read(mFd, mINdata, mBufLen); + if(r <= 0){ return; } - char *end = at + data.size(); - while(at < end){ - if(e->mask & IN_IGNORED){ - at += sizeof(inotify_event) + e->len; + int i = 0; + while(i < r){ + inotify_event *e = reinterpret_cast<inotify_event*>(&mINdata[i]); + if((!e->len) || (e->mask & IN_IGNORED)){ + i += sizeof(inotify_event) + e->len; continue; } + mSemFree->acquire(); quint32 mask = e->mask; QString name = QString("%1/%2").arg(mCurrent).arg(e->name); - at += sizeof(inotify_event) + e->len; - if(mask & IN_CREATE){ - emit dwEvent(name, Added); - return; + DWEvent curEvent = None; + if(mask & IN_CREATE || mask & IN_MOVED_TO){ + curEvent = Added; } - if(mask & IN_DELETE){ - emit dwEvent(name, Deleted); - return; + if(mask & IN_DELETE || mask & IN_MOVED_FROM){ + curEvent = Deleted; } if(mask & IN_CLOSE_WRITE || e->mask & IN_MODIFY){ - emit dwEvent(name, Modified); - return; - } - if(mask & IN_MOVED_FROM || e->mask & IN_MOVED_TO){ - emit needRefresh(); - return; + curEvent = Modified; } + QPair<QString, DWEvent> c = qMakePair(name, curEvent); + mDataQueue->enqueue(c); + mSemUsed->release(); + i += sizeof(inotify_event) + e->len; } } -SmDataGatherer::SmDataGatherer(const int numFields, QObject *parent) : QThread(parent), mNumFields(numFields) {} +SmDataColletor::SmDataColletor(const int numFields, QObject *parent) : QThread(parent), mSemFree(0), mSemUsed(0), mDataQueue(0), mNumFields(numFields) {} -void SmDataGatherer::setCurrent(const QString ¤t, int mode){ - QMutexLocker lock(&mSetMx); - mCurrent = current; - mMode = mode; +void SmDataColletor::init(QSemaphore *set, QSemaphore *get, QQueue<QPair<QString, SmDirWatcher::DWEvent> > *data){ + mSemFree = set; + mSemUsed = get; + mDataQueue = data; } -void SmDataGatherer::run(){ - QMutexLocker lock(&mRunMx); - QFileInfo fi(mCurrent); - if(fi.isDir()){ - SmTreeItem *rv = populate(); - emit population(rv); - return; - } - if(fi.isFile()){ +void SmDataColletor::run(){ + forever { + mSemUsed->acquire(); + QPair<QString, SmDirWatcher::DWEvent> cur = mDataQueue->dequeue(); + if(cur.second == SmDirWatcher::Populate){ + SmTreeItem *i = populate(cur.first); + emit population(i); + mSemFree->release(); + continue; + + } + QFileInfo fi(cur.first); QList<QVariant> fd = fileData(fi); - emit newData(fd, mMode); + emit newData(fd, cur.second); + mSemFree->release(); } } -SmTreeItem * SmDataGatherer::populate(){ +SmTreeItem * SmDataColletor::populate(const QString &dir){ SmTreeItem *retval = new SmTreeItem(mNumFields); - QDir d = QDir(mCurrent); + QDir d = QDir(dir); foreach(QFileInfo fi, d.entryInfoList()){ if(fi.fileName() == "."){ continue; @@ -127,7 +132,7 @@ SmTreeItem * SmDataGatherer::populate(){ return retval; } -const QList<QVariant> SmDataGatherer::fileData(const QFileInfo &fi) const{ +const QList<QVariant> SmDataColletor::fileData(const QFileInfo &fi) const{ QList<QVariant> data; data << fi.fileName() << fi.size(); QString mime = Helper::mimeType(fi.absoluteFilePath()); |