summaryrefslogtreecommitdiffstats
path: root/smdirwatcher.cpp
diff options
context:
space:
mode:
authorArno <am@disconnect.de>2013-03-21 16:14:54 +0100
committerArno <am@disconnect.de>2013-03-21 16:14:54 +0100
commitce402f298b2f9733b614fbf1bde99a052d0ab5c0 (patch)
tree26da14cacb2e4fffcab47cf0a61d066568a15e7a /smdirwatcher.cpp
parent03831d3669ea49a99a15aaf5d17724be8c533b85 (diff)
downloadSheMov-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.cpp107
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 &current, 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());