summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp3
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp43
-rw-r--r--src/corelib/io/qfilesystemwatcher_win_p.h20
-rw-r--r--src/corelib/io/qprocess_win.cpp2
-rw-r--r--src/corelib/io/qurl.h6
-rw-r--r--src/corelib/io/qwinoverlappedionotifier.cpp50
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);