diff options
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/qfilesystemengine_win.cpp | 3 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemwatcher_win.cpp | 43 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemwatcher_win_p.h | 20 | ||||
-rw-r--r-- | src/corelib/io/qprocess_win.cpp | 2 | ||||
-rw-r--r-- | src/corelib/io/qurl.h | 6 | ||||
-rw-r--r-- | src/corelib/io/qwinoverlappedionotifier.cpp | 50 |
6 files changed, 93 insertions, 31 deletions
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 2c9ed9da3d..e8904b0ab7 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -1049,7 +1049,8 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea if (slash) { QString chunk = dirName.left(slash); if (!mkDir(chunk)) { - if (GetLastError() == ERROR_ALREADY_EXISTS) { + const DWORD lastError = GetLastError(); + if (lastError == ERROR_ALREADY_EXISTS || lastError == ERROR_ACCESS_DENIED) { bool existed = false; if (isDirPath(chunk, &existed) && existed) continue; diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp index 6ac6a3fbd9..bb16df04ad 100644 --- a/src/corelib/io/qfilesystemwatcher_win.cpp +++ b/src/corelib/io/qfilesystemwatcher_win.cpp @@ -95,7 +95,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths, ) #endif normalPath.chop(1); - QFileInfo fileInfo(normalPath.toLower()); + QFileInfo fileInfo(normalPath); if (!fileInfo.exists()) continue; @@ -136,15 +136,16 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths, thread = *jt; QMutexLocker locker(&(thread->mutex)); - handle = thread->handleForDir.value(absolutePath); + handle = thread->handleForDir.value(QFileSystemWatcherPathKey(absolutePath)); if (handle.handle != INVALID_HANDLE_VALUE && handle.flags == flags) { // found a thread now insert... DEBUG() << "Found a thread" << thread; - QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h - = thread->pathInfoForHandle[handle.handle]; - if (!h.contains(fileInfo.absoluteFilePath())) { - thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); + QWindowsFileSystemWatcherEngineThread::PathInfoHash &h = + thread->pathInfoForHandle[handle.handle]; + const QFileSystemWatcherPathKey key(fileInfo.absoluteFilePath()); + if (!h.contains(key)) { + thread->pathInfoForHandle[handle.handle].insert(key, pathInfo); if (isDir) directories->append(path); else @@ -177,9 +178,9 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths, DEBUG() << "Added handle" << handle.handle << "for" << absolutePath << "to watch" << fileInfo.absoluteFilePath() << "to existing thread " << thread; thread->handles.append(handle.handle); - thread->handleForDir.insert(absolutePath, handle); + thread->handleForDir.insert(QFileSystemWatcherPathKey(absolutePath), handle); - thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); + thread->pathInfoForHandle[handle.handle].insert(QFileSystemWatcherPathKey(fileInfo.absoluteFilePath()), pathInfo); if (isDir) directories->append(path); else @@ -195,9 +196,9 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths, QWindowsFileSystemWatcherEngineThread *thread = new QWindowsFileSystemWatcherEngineThread(); DEBUG() << " ###Creating new thread" << thread << "(" << (threads.count()+1) << "threads)"; thread->handles.append(handle.handle); - thread->handleForDir.insert(absolutePath, handle); + thread->handleForDir.insert(QFileSystemWatcherPathKey(absolutePath), handle); - thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); + thread->pathInfoForHandle[handle.handle].insert(QFileSystemWatcherPathKey(fileInfo.absoluteFilePath()), pathInfo); if (isDir) directories->append(path); else @@ -230,7 +231,7 @@ QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &path QString normalPath = path; if (normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\'))) normalPath.chop(1); - QFileInfo fileInfo(normalPath.toLower()); + QFileInfo fileInfo(normalPath); DEBUG() << "removing" << normalPath; QString absolutePath = fileInfo.absoluteFilePath(); QList<QWindowsFileSystemWatcherEngineThread *>::iterator jt, end; @@ -242,16 +243,16 @@ QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &path QMutexLocker locker(&(thread->mutex)); - QWindowsFileSystemWatcherEngine::Handle handle = thread->handleForDir.value(absolutePath); + QWindowsFileSystemWatcherEngine::Handle handle = thread->handleForDir.value(QFileSystemWatcherPathKey(absolutePath)); if (handle.handle == INVALID_HANDLE_VALUE) { // perhaps path is a file? absolutePath = fileInfo.absolutePath(); - handle = thread->handleForDir.value(absolutePath); + handle = thread->handleForDir.value(QFileSystemWatcherPathKey(absolutePath)); } if (handle.handle != INVALID_HANDLE_VALUE) { - QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h = + QWindowsFileSystemWatcherEngineThread::PathInfoHash &h = thread->pathInfoForHandle[handle.handle]; - if (h.remove(fileInfo.absoluteFilePath())) { + if (h.remove(QFileSystemWatcherPathKey(fileInfo.absoluteFilePath()))) { // ### files->removeAll(path); directories->removeAll(path); @@ -264,7 +265,7 @@ QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &path Q_ASSERT(indexOfHandle != -1); thread->handles.remove(indexOfHandle); - thread->handleForDir.remove(absolutePath); + thread->handleForDir.remove(QFileSystemWatcherPathKey(absolutePath)); // h is now invalid it.remove(); @@ -326,7 +327,7 @@ QWindowsFileSystemWatcherEngineThread::~QWindowsFileSystemWatcherEngineThread() } } -static inline QString msgFindNextFailed(const QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &pathInfos) +static inline QString msgFindNextFailed(const QWindowsFileSystemWatcherEngineThread::PathInfoHash &pathInfos) { QString result; QTextStream str(&result); @@ -366,7 +367,7 @@ void QWindowsFileSystemWatcherEngineThread::run() // for some reason, so we must check if the handle exist in the handles vector if (handles.contains(handle)) { DEBUG() << "thread" << this << "Acknowledged handle:" << at << handle; - QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h = pathInfoForHandle[handle]; + QWindowsFileSystemWatcherEngineThread::PathInfoHash &h = pathInfoForHandle[handle]; bool fakeRemove = false; if (!FindNextChangeNotification(handle)) { @@ -381,9 +382,9 @@ void QWindowsFileSystemWatcherEngineThread::run() qErrnoWarning(error, "%s", qPrintable(msgFindNextFailed(h))); } - QMutableHashIterator<QString, QWindowsFileSystemWatcherEngine::PathInfo> it(h); + QMutableHashIterator<QFileSystemWatcherPathKey, QWindowsFileSystemWatcherEngine::PathInfo> it(h); while (it.hasNext()) { - QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo>::iterator x = it.next(); + QWindowsFileSystemWatcherEngineThread::PathInfoHash::iterator x = it.next(); QString absolutePath = x.value().absolutePath; QFileInfo fileInfo(x.value().path); DEBUG() << "checking" << x.key(); @@ -407,7 +408,7 @@ void QWindowsFileSystemWatcherEngineThread::run() Q_ASSERT(indexOfHandle != -1); handles.remove(indexOfHandle); - handleForDir.remove(absolutePath); + handleForDir.remove(QFileSystemWatcherPathKey(absolutePath)); // h is now invalid } } else if (x.value().isDir) { diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h index 8937910d10..790fb954d9 100644 --- a/src/corelib/io/qfilesystemwatcher_win_p.h +++ b/src/corelib/io/qfilesystemwatcher_win_p.h @@ -128,11 +128,27 @@ private: }; +class QFileSystemWatcherPathKey : public QString +{ +public: + QFileSystemWatcherPathKey() {} + explicit QFileSystemWatcherPathKey(const QString &other) : QString(other) {} + QFileSystemWatcherPathKey(const QFileSystemWatcherPathKey &other) : QString(other) {} + bool operator==(const QFileSystemWatcherPathKey &other) const { return !compare(other, Qt::CaseInsensitive); } +}; + +Q_DECLARE_TYPEINFO(QFileSystemWatcherPathKey, Q_MOVABLE_TYPE); + +inline uint qHash(const QFileSystemWatcherPathKey &key) { return qHash(key.toCaseFolded()); } + class QWindowsFileSystemWatcherEngineThread : public QThread { Q_OBJECT public: + typedef QHash<QFileSystemWatcherPathKey, QWindowsFileSystemWatcherEngine::Handle> HandleForDirHash; + typedef QHash<QFileSystemWatcherPathKey, QWindowsFileSystemWatcherEngine::PathInfo> PathInfoHash; + QWindowsFileSystemWatcherEngineThread(); ~QWindowsFileSystemWatcherEngineThread(); void run(); @@ -143,9 +159,9 @@ public: QVector<Qt::HANDLE> handles; int msg; - QHash<QString, QWindowsFileSystemWatcherEngine::Handle> handleForDir; + HandleForDirHash handleForDir; - QHash<Qt::HANDLE, QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> > pathInfoForHandle; + QHash<Qt::HANDLE, PathInfoHash> pathInfoForHandle; Q_SIGNALS: void fileChanged(const QString &path, bool removed); diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 7776852277..bcc3fe0b0d 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -641,7 +641,7 @@ bool QProcessPrivate::drainOutputPipes() readyReadEmitted |= stderrReader->waitForReadyRead(0); readOperationActive |= stderrReader->isReadOperationActive(); } - if (!readOperationActive) + if (!readOperationActive || !readyReadEmitted) break; Sleep(100); } diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index 98cf760dec..453e0be1d2 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -114,6 +114,10 @@ public: template<typename E1, typename E2> class QTypeInfo<QUrlTwoFlags<E1, E2> > : public QTypeInfoMerger<QUrlTwoFlags<E1, E2>, E1, E2> {}; +class QUrl; +// qHash is a friend, but we can't use default arguments for friends (ยง8.3.6.4) +Q_CORE_EXPORT uint qHash(const QUrl &url, uint seed = 0) Q_DECL_NOTHROW; + class Q_CORE_EXPORT QUrl { public: @@ -326,7 +330,7 @@ public: static QList<QUrl> fromStringList(const QStringList &uris, ParsingMode mode = TolerantMode); static void setIdnWhitelist(const QStringList &); - friend Q_CORE_EXPORT uint qHash(const QUrl &url, uint seed = 0) Q_DECL_NOTHROW; + friend Q_CORE_EXPORT uint qHash(const QUrl &url, uint seed) Q_DECL_NOTHROW; private: QUrlPrivate *d; diff --git a/src/corelib/io/qwinoverlappedionotifier.cpp b/src/corelib/io/qwinoverlappedionotifier.cpp index 8f4b8be9a3..914264e69e 100644 --- a/src/corelib/io/qwinoverlappedionotifier.cpp +++ b/src/corelib/io/qwinoverlappedionotifier.cpp @@ -83,7 +83,9 @@ class QWinIoCompletionPort : protected QThread { public: QWinIoCompletionPort() - : hPort(INVALID_HANDLE_VALUE) + : finishThreadKey(reinterpret_cast<ULONG_PTR>(this)), + drainQueueKey(reinterpret_cast<ULONG_PTR>(this + 1)), + hPort(INVALID_HANDLE_VALUE) { setObjectName(QLatin1String("I/O completion port thread")); HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); @@ -92,13 +94,19 @@ public: return; } hPort = hIOCP; + hQueueDrainedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!hQueueDrainedEvent) { + qErrnoWarning("CreateEvent failed."); + return; + } } ~QWinIoCompletionPort() { - PostQueuedCompletionStatus(hPort, 0, 0, NULL); + PostQueuedCompletionStatus(hPort, 0, finishThreadKey, NULL); QThread::wait(); CloseHandle(hPort); + CloseHandle(hQueueDrainedEvent); } void registerNotifier(QWinOverlappedIoNotifier *notifier) @@ -122,29 +130,50 @@ public: mutex.unlock(); } + void drainQueue() + { + QMutexLocker locker(&drainQueueMutex); + ResetEvent(hQueueDrainedEvent); + PostQueuedCompletionStatus(hPort, 0, drainQueueKey, NULL); + WaitForSingleObject(hQueueDrainedEvent, INFINITE); + } + + using QThread::isRunning; + protected: void run() { DWORD dwBytesRead; ULONG_PTR pulCompletionKey; OVERLAPPED *overlapped; + DWORD msecs = INFINITE; forever { BOOL success = GetQueuedCompletionStatus(hPort, &dwBytesRead, &pulCompletionKey, &overlapped, - INFINITE); + msecs); DWORD errorCode = success ? ERROR_SUCCESS : GetLastError(); if (!success && !overlapped) { + if (!msecs) { + // Time out in drain mode. The completion status queue is empty. + msecs = INFINITE; + SetEvent(hQueueDrainedEvent); + continue; + } qErrnoWarning(errorCode, "GetQueuedCompletionStatus failed."); return; } - if (success && !(dwBytesRead || pulCompletionKey || overlapped)) { - // We've posted null values via PostQueuedCompletionStatus to end this thread. + if (pulCompletionKey == finishThreadKey) return; + if (pulCompletionKey == drainQueueKey) { + // Enter drain mode. + Q_ASSERT(msecs == INFINITE); + msecs = 0; + continue; } QWinOverlappedIoNotifier *notifier = reinterpret_cast<QWinOverlappedIoNotifier *>(pulCompletionKey); @@ -156,9 +185,13 @@ protected: } private: + const ULONG_PTR finishThreadKey; + const ULONG_PTR drainQueueKey; HANDLE hPort; QSet<QWinOverlappedIoNotifier *> notifiers; QMutex mutex; + QMutex drainQueueMutex; + HANDLE hQueueDrainedEvent; }; QWinIoCompletionPort *QWinOverlappedIoNotifier::iocp = 0; @@ -216,7 +249,14 @@ void QWinOverlappedIoNotifier::setEnabled(bool enabled) */ bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped) { + if (!iocp->isRunning()) { + qWarning("Called QWinOverlappedIoNotifier::waitForNotified on inactive notifier."); + return false; + } + forever { + if (msecs == 0) + iocp->drainQueue(); DWORD result = WaitForSingleObject(hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs)); if (result == WAIT_OBJECT_0) { ReleaseSemaphore(hSemaphore, 1, NULL); |