From ce402f298b2f9733b614fbf1bde99a052d0ab5c0 Mon Sep 17 00:00:00 2001 From: Arno Date: Thu, 21 Mar 2013 16:14:54 +0100 Subject: 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... --- smdirwatcher.cpp | 107 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 51 deletions(-) (limited to 'smdirwatcher.cpp') diff --git a/smdirwatcher.cpp b/smdirwatcher.cpp index 8650d3b..8b72aab 100644 --- a/smdirwatcher.cpp +++ b/smdirwatcher.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -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 >(); + 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 c = qMakePair(dir, Populate); + mDataQueue->enqueue(c); + mSemUsed->release(); } void SmDirWatcher::run(){ - QMutexLocker lock(&mWatchMx); - QVarLengthArray 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(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(&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 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 > *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 cur = mDataQueue->dequeue(); + if(cur.second == SmDirWatcher::Populate){ + SmTreeItem *i = populate(cur.first); + emit population(i); + mSemFree->release(); + continue; + + } + QFileInfo fi(cur.first); QList 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 SmDataGatherer::fileData(const QFileInfo &fi) const{ +const QList SmDataColletor::fileData(const QFileInfo &fi) const{ QList data; data << fi.fileName() << fi.size(); QString mime = Helper::mimeType(fi.absoluteFilePath()); -- cgit v1.2.3-70-g09d2