diff options
Diffstat (limited to 'src/corelib/io/qfilesystemwatcher_kqueue.cpp')
-rw-r--r-- | src/corelib/io/qfilesystemwatcher_kqueue.cpp | 296 |
1 files changed, 113 insertions, 183 deletions
diff --git a/src/corelib/io/qfilesystemwatcher_kqueue.cpp b/src/corelib/io/qfilesystemwatcher_kqueue.cpp index 387a7f7c4b..fd7bfa2b27 100644 --- a/src/corelib/io/qfilesystemwatcher_kqueue.cpp +++ b/src/corelib/io/qfilesystemwatcher_kqueue.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -67,49 +67,28 @@ QT_BEGIN_NAMESPACE # define DEBUG if(false)qDebug #endif -QKqueueFileSystemWatcherEngine *QKqueueFileSystemWatcherEngine::create() +QKqueueFileSystemWatcherEngine *QKqueueFileSystemWatcherEngine::create(QObject *parent) { int kqfd = kqueue(); if (kqfd == -1) return 0; - return new QKqueueFileSystemWatcherEngine(kqfd); + return new QKqueueFileSystemWatcherEngine(kqfd, parent); } -QKqueueFileSystemWatcherEngine::QKqueueFileSystemWatcherEngine(int kqfd) - : kqfd(kqfd) +QKqueueFileSystemWatcherEngine::QKqueueFileSystemWatcherEngine(int kqfd, QObject *parent) + : QFileSystemWatcherEngine(parent), + kqfd(kqfd), + notifier(kqfd, QSocketNotifier::Read, this) { - fcntl(kqfd, F_SETFD, FD_CLOEXEC); + connect(¬ifier, SIGNAL(activated(int)), SLOT(readFromKqueue())); - if (pipe(kqpipe) == -1) { - perror("QKqueueFileSystemWatcherEngine: cannot create pipe"); - kqpipe[0] = kqpipe[1] = -1; - return; - } - fcntl(kqpipe[0], F_SETFD, FD_CLOEXEC); - fcntl(kqpipe[1], F_SETFD, FD_CLOEXEC); - - struct kevent kev; - EV_SET(&kev, - kqpipe[0], - EVFILT_READ, - EV_ADD | EV_ENABLE, - 0, - 0, - 0); - if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) { - perror("QKqueueFileSystemWatcherEngine: cannot watch pipe, kevent returned"); - return; - } + fcntl(kqfd, F_SETFD, FD_CLOEXEC); } QKqueueFileSystemWatcherEngine::~QKqueueFileSystemWatcherEngine() { - stop(); - wait(); - + notifier.setEnabled(false); close(kqfd); - close(kqpipe[0]); - close(kqpipe[1]); foreach (int id, pathToID) ::close(id < 0 ? -id : id); @@ -120,82 +99,73 @@ QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *directories) { QStringList p = paths; - { - QMutexLocker locker(&mutex); - - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - int fd; + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + int fd; #if defined(O_EVTONLY) - fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY); + fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY); #else - fd = qt_safe_open(QFile::encodeName(path), O_RDONLY); + fd = qt_safe_open(QFile::encodeName(path), O_RDONLY); #endif - if (fd == -1) { - perror("QKqueueFileSystemWatcherEngine::addPaths: open"); - continue; - } - if (fd >= (int)FD_SETSIZE / 2 && fd < (int)FD_SETSIZE) { - int fddup = fcntl(fd, F_DUPFD, FD_SETSIZE); - if (fddup != -1) { - ::close(fd); - fd = fddup; - } + if (fd == -1) { + perror("QKqueueFileSystemWatcherEngine::addPaths: open"); + continue; + } + if (fd >= (int)FD_SETSIZE / 2 && fd < (int)FD_SETSIZE) { + int fddup = fcntl(fd, F_DUPFD, FD_SETSIZE); + if (fddup != -1) { + ::close(fd); + fd = fddup; } - fcntl(fd, F_SETFD, FD_CLOEXEC); + } + fcntl(fd, F_SETFD, FD_CLOEXEC); - QT_STATBUF st; - if (QT_FSTAT(fd, &st) == -1) { - perror("QKqueueFileSystemWatcherEngine::addPaths: fstat"); + QT_STATBUF st; + if (QT_FSTAT(fd, &st) == -1) { + perror("QKqueueFileSystemWatcherEngine::addPaths: fstat"); + ::close(fd); + continue; + } + int id = (S_ISDIR(st.st_mode)) ? -fd : fd; + if (id < 0) { + if (directories->contains(path)) { ::close(fd); continue; } - int id = (S_ISDIR(st.st_mode)) ? -fd : fd; - if (id < 0) { - if (directories->contains(path)) { - ::close(fd); - continue; - } - } else { - if (files->contains(path)) { - ::close(fd); - continue; - } - } - - struct kevent kev; - EV_SET(&kev, - fd, - EVFILT_VNODE, - EV_ADD | EV_ENABLE | EV_CLEAR, - NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, - 0, - 0); - if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) { - perror("QKqueueFileSystemWatcherEngine::addPaths: kevent"); + } else { + if (files->contains(path)) { ::close(fd); continue; } + } - it.remove(); - if (id < 0) { - DEBUG() << "QKqueueFileSystemWatcherEngine: added directory path" << path; - directories->append(path); - } else { - DEBUG() << "QKqueueFileSystemWatcherEngine: added file path" << path; - files->append(path); - } + struct kevent kev; + EV_SET(&kev, + fd, + EVFILT_VNODE, + EV_ADD | EV_ENABLE | EV_CLEAR, + NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, + 0, + 0); + if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) { + perror("QKqueueFileSystemWatcherEngine::addPaths: kevent"); + ::close(fd); + continue; + } - pathToID.insert(path, id); - idToPath.insert(id, path); + it.remove(); + if (id < 0) { + DEBUG() << "QKqueueFileSystemWatcherEngine: added directory path" << path; + directories->append(path); + } else { + DEBUG() << "QKqueueFileSystemWatcherEngine: added file path" << path; + files->append(path); } - } - if (!isRunning()) - start(); - else - write(kqpipe[1], "@", 1); + pathToID.insert(path, id); + idToPath.insert(id, path); + } return p; } @@ -206,126 +176,86 @@ QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths { bool isEmpty; QStringList p = paths; - { - QMutexLocker locker(&mutex); - if (pathToID.isEmpty()) - return p; - - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - int id = pathToID.take(path); - QString x = idToPath.take(id); - if (x.isEmpty() || x != path) - continue; + if (pathToID.isEmpty()) + return p; - ::close(id < 0 ? -id : id); + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + int id = pathToID.take(path); + QString x = idToPath.take(id); + if (x.isEmpty() || x != path) + continue; - it.remove(); - if (id < 0) - directories->removeAll(path); - else - files->removeAll(path); - } - isEmpty = pathToID.isEmpty(); - } + ::close(id < 0 ? -id : id); - if (isEmpty) { - stop(); - wait(); - } else { - write(kqpipe[1], "@", 1); + it.remove(); + if (id < 0) + directories->removeAll(path); + else + files->removeAll(path); } + isEmpty = pathToID.isEmpty(); return p; } -void QKqueueFileSystemWatcherEngine::stop() -{ - write(kqpipe[1], "q", 1); -} - -void QKqueueFileSystemWatcherEngine::run() +void QKqueueFileSystemWatcherEngine::readFromKqueue() { forever { + DEBUG() << "QKqueueFileSystemWatcherEngine: polling for changes"; int r; struct kevent kev; - DEBUG() << "QKqueueFileSystemWatcherEngine: waiting for kevents..."; - EINTR_LOOP(r, kevent(kqfd, 0, 0, &kev, 1, 0)); + struct timespec ts = { 0, 0 }; // 0 ts, because we want to poll + EINTR_LOOP(r, kevent(kqfd, 0, 0, &kev, 1, &ts)); if (r < 0) { perror("QKqueueFileSystemWatcherEngine: error during kevent wait"); return; + } else if (r == 0) { + // polling returned no events, so stop + break; } else { int fd = kev.ident; DEBUG() << "QKqueueFileSystemWatcherEngine: processing kevent" << kev.ident << kev.filter; - if (fd == kqpipe[0]) { - // read all pending data from the pipe - QByteArray ba; - ba.resize(kev.data); - if (read(kqpipe[0], ba.data(), ba.size()) != ba.size()) { - perror("QKqueueFileSystemWatcherEngine: error reading from pipe"); - return; - } - // read the command from the buffer (but break and return on 'q') - char cmd = 0; - for (int i = 0; i < ba.size(); ++i) { - cmd = ba.constData()[i]; - if (cmd == 'q') - break; - } - // handle the command - switch (cmd) { - case 'q': - DEBUG() << "QKqueueFileSystemWatcherEngine: thread received 'q', exiting..."; - return; - case '@': - DEBUG() << "QKqueueFileSystemWatcherEngine: thread received '@', continuing..."; - break; - default: - DEBUG() << "QKqueueFileSystemWatcherEngine: thread received unknow message" << cmd; - break; - } - } else { - QMutexLocker locker(&mutex); - int id = fd; - QString path = idToPath.value(id); + int id = fd; + QString path = idToPath.value(id); + if (path.isEmpty()) { + // perhaps a directory? + id = -id; + path = idToPath.value(id); if (path.isEmpty()) { - // perhaps a directory? - id = -id; - path = idToPath.value(id); - if (path.isEmpty()) { - DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent for a file we're not watching"; - continue; - } - } - if (kev.filter != EVFILT_VNODE) { - DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent with the wrong filter"; + DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent for a file we're not watching"; continue; } + } + if (kev.filter != EVFILT_VNODE) { + DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent with the wrong filter"; + continue; + } - if ((kev.fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) != 0) { - DEBUG() << path << "removed, removing watch also"; + if ((kev.fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) != 0) { + DEBUG() << path << "removed, removing watch also"; - pathToID.remove(path); - idToPath.remove(id); - ::close(fd); + pathToID.remove(path); + idToPath.remove(id); + ::close(fd); - if (id < 0) - emit directoryChanged(path, true); - else - emit fileChanged(path, true); - } else { - DEBUG() << path << "changed"; + if (id < 0) + emit directoryChanged(path, true); + else + emit fileChanged(path, true); + } else { + DEBUG() << path << "changed"; - if (id < 0) - emit directoryChanged(path, false); - else - emit fileChanged(path, false); - } + if (id < 0) + emit directoryChanged(path, false); + else + emit fileChanged(path, false); } } + } } |