diff options
Diffstat (limited to 'src/corelib')
33 files changed, 412 insertions, 342 deletions
diff --git a/src/corelib/arch/qatomic_bootstrap.h b/src/corelib/arch/qatomic_bootstrap.h index 7f17387c9c..1ab901d826 100644 --- a/src/corelib/arch/qatomic_bootstrap.h +++ b/src/corelib/arch/qatomic_bootstrap.h @@ -67,8 +67,10 @@ template <typename T> struct QAtomicOps: QGenericAtomicOps<QAtomicOps<T> > return --_q_value != 0; } - static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW + static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW { + if (currentValue) + *currentValue = _q_value; if (_q_value == expectedValue) { _q_value = newValue; return true; @@ -83,8 +85,8 @@ template <typename T> struct QAtomicOps: QGenericAtomicOps<QAtomicOps<T> > return tmp; } - static - T fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW + template <typename AdditiveType> static + T fetchAndAddRelaxed(T &_q_value, AdditiveType valueToAdd) Q_DECL_NOTHROW { T returnValue = _q_value; _q_value += valueToAdd; diff --git a/src/corelib/doc/snippets/code/doc_src_plugins-howto.cpp b/src/corelib/doc/snippets/code/doc_src_plugins-howto.cpp index aae4f4bd00..b86f0bbf68 100644 --- a/src/corelib/doc/snippets/code/doc_src_plugins-howto.cpp +++ b/src/corelib/doc/snippets/code/doc_src_plugins-howto.cpp @@ -42,7 +42,7 @@ class MyStylePlugin : public QStylePlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE mystyleplugin.json) + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "mystyleplugin.json") public: QStyle *create(const QString &key); }; diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 80c9992e25..2bc52c6150 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -59,7 +59,11 @@ #include <QtCore/qconfig.h> #include <QtCore/qfeatures.h> #endif -#define QT_SUPPORTS(FEATURE) (!defined(QT_NO_##FEATURE)) +#if defined(Q_CC_MSVC) && _MSC_VER <= 1500 /* VS2008 */ +# define QT_SUPPORTS(FEATURE) (!defined QT_NO_##FEATURE) +#else +# define QT_SUPPORTS(FEATURE) (!defined(QT_NO_##FEATURE)) +#endif #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) # define QT_NO_UNSHARABLE_CONTAINERS #endif diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index 860c954bf8..f2ebeb6a03 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -566,7 +566,7 @@ QLibraryInfo::rawLocation(LibraryLocation loc, PathGroup group) QStringList QLibraryInfo::platformPluginArguments(const QString &platformName) { -#ifndef QT_BOOTSTRAPPED +#if !defined(QT_BOOTSTRAPPED) && !defined(QT_NO_SETTINGS) if (const QSettings *settings = QLibraryInfoPrivate::findConfiguration()) { QString key = QLatin1String(platformsSection); key += QLatin1Char('/'); @@ -574,7 +574,7 @@ QStringList QLibraryInfo::platformPluginArguments(const QString &platformName) key += QLatin1String("Arguments"); return settings->value(key).toStringList(); } -#endif // !QT_BOOTSTRAPPED +#endif // !QT_BOOTSTRAPPED && !QT_NO_SETTINGS return QStringList(); } diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 24a73fffb9..f908dd512e 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1395,8 +1395,7 @@ void qErrnoWarning(int code, const char *msg, ...) \since 5.0 Installs a Qt message \a handler which has been defined - previously. Returns a pointer to the previous message handler - (which may be 0). + previously. Returns a pointer to the previous message handler. The message handler is a function that prints out debug messages, warnings, critical and fatal error messages. The Qt library (debug diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 60f7e47e62..210bb3898c 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -530,7 +530,8 @@ void QFileInfo::setFile(const QDir &dir, const QString &file) is true. In contrast to canonicalFilePath(), symbolic links or redundant "." or ".." elements are not necessarily removed. - If the QFileInfo is empty it returns QDir::currentPath(). + \warning If filePath() is empty the behavior of this function + is undefined. \sa filePath(), canonicalFilePath(), isRelative() */ @@ -572,8 +573,8 @@ QString QFileInfo::canonicalFilePath() const In contrast to canonicalPath() symbolic links or redundant "." or ".." elements are not necessarily removed. - \warning If the QFileInfo object was created with an empty QString, - the behavior of this function is undefined. + \warning If filePath() is empty the behavior of this function + is undefined. \sa absoluteFilePath(), path(), canonicalPath(), fileName(), isRelative() */ diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.mm b/src/corelib/io/qfilesystemwatcher_fsevents.mm index 981d663694..085396da6d 100644 --- a/src/corelib/io/qfilesystemwatcher_fsevents.mm +++ b/src/corelib/io/qfilesystemwatcher_fsevents.mm @@ -64,6 +64,25 @@ QT_BEGIN_NAMESPACE +namespace { +class RaiiAutoreleasePool +{ + Q_DISABLE_COPY(RaiiAutoreleasePool) + +public: + RaiiAutoreleasePool() + : pool([[NSAutoreleasePool alloc] init]) + {} + + ~RaiiAutoreleasePool() + { [pool release]; } + +private: + NSAutoreleasePool *pool; +}; +#define Q_AUTORELEASE_POOL(pool) RaiiAutoreleasePool pool; Q_UNUSED(pool); +} + static void callBackFunction(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents, @@ -71,6 +90,8 @@ static void callBackFunction(ConstFSEventStreamRef streamRef, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) { + Q_AUTORELEASE_POOL(pool) + char **paths = static_cast<char **>(eventPaths); QFseventsFileSystemWatcherEngine *engine = static_cast<QFseventsFileSystemWatcherEngine *>(clientCallBackInfo); engine->processEvent(streamRef, numEvents, paths, eventFlags, eventIds); @@ -283,6 +304,7 @@ void QFseventsFileSystemWatcherEngine::doEmitDirectoryChanged(const QString path void QFseventsFileSystemWatcherEngine::restartStream() { + Q_AUTORELEASE_POOL(pool) QMutexLocker locker(&lock); stopStream(); startStream(); @@ -313,6 +335,8 @@ QFseventsFileSystemWatcherEngine::QFseventsFileSystemWatcherEngine(QObject *pare QFseventsFileSystemWatcherEngine::~QFseventsFileSystemWatcherEngine() { + Q_AUTORELEASE_POOL(pool) + if (stream) FSEventStreamStop(stream); @@ -327,6 +351,8 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *files, QStringList *directories) { + Q_AUTORELEASE_POOL(pool) + if (stream) { DEBUG("Flushing, last id is %llu", FSEventStreamGetLatestEventId(stream)); FSEventStreamFlushSync(stream); @@ -413,6 +439,8 @@ QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &pat QStringList *files, QStringList *directories) { + Q_AUTORELEASE_POOL(pool) + QMutexLocker locker(&lock); bool needsRestart = false; diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp index 518052e537..07245ddea2 100644 --- a/src/corelib/io/qloggingcategory.cpp +++ b/src/corelib/io/qloggingcategory.cpp @@ -50,6 +50,18 @@ const char qtDefaultCategoryName[] = "default"; Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory, (qtDefaultCategoryName)) +#ifndef Q_ATOMIC_INT8_IS_SUPPORTED +static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift) +{ + const int bit = 1 << shift; + + if (enable) + atomic->fetchAndOrRelaxed(bit); + else + atomic->fetchAndAndRelaxed(~bit); +} +#endif + /*! \class QLoggingCategory \inmodule QtCore @@ -129,13 +141,13 @@ Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory, Order of evaluation: \list - \li Rules from QtProject/qlogging.ini + \li Rules from QtProject/qtlogging.ini \li Rules set by \l setFilterRules() \li Rules from file in \c QT_LOGGING_CONF \li Rules from environment variable QT_LOGGING_RULES \endlist - The \c QtProject/qlogging.ini file is looked up in all directories returned + The \c QtProject/qtlogging.ini file is looked up in all directories returned by QStandardPaths::GenericConfigLocation, e.g. \list @@ -171,13 +183,11 @@ Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory, */ QLoggingCategory::QLoggingCategory(const char *category) : d(0), - name(0), - enabledDebug(true), - enabledWarning(true), - enabledCritical(true) + name(0) { Q_UNUSED(d); Q_UNUSED(placeholder); + enabled.store(0x01010101); // enabledDebug = enabledWarning = enabledCritical = true; const bool isDefaultCategory = (category == 0) || (strcmp(category, qtDefaultCategoryName) == 0); @@ -249,9 +259,9 @@ QLoggingCategory::~QLoggingCategory() bool QLoggingCategory::isEnabled(QtMsgType msgtype) const { switch (msgtype) { - case QtDebugMsg: return enabledDebug; - case QtWarningMsg: return enabledWarning; - case QtCriticalMsg: return enabledCritical; + case QtDebugMsg: return isDebugEnabled(); + case QtWarningMsg: return isWarningEnabled(); + case QtCriticalMsg: return isCriticalEnabled(); case QtFatalMsg: return true; } return false; @@ -270,9 +280,15 @@ bool QLoggingCategory::isEnabled(QtMsgType msgtype) const void QLoggingCategory::setEnabled(QtMsgType type, bool enable) { switch (type) { - case QtDebugMsg: enabledDebug = enable; break; - case QtWarningMsg: enabledWarning = enable; break; - case QtCriticalMsg: enabledCritical = enable; break; +#ifdef Q_ATOMIC_INT8_IS_SUPPORTED + case QtDebugMsg: bools.enabledDebug.store(enable); break; + case QtWarningMsg: bools.enabledWarning.store(enable); break; + case QtCriticalMsg: bools.enabledCritical.store(enable); break; +#else + case QtDebugMsg: setBoolLane(&enabled, enable, DebugShift); break; + case QtWarningMsg: setBoolLane(&enabled, enable, WarningShift); break; + case QtCriticalMsg: setBoolLane(&enabled, enable, CriticalShift); break; +#endif case QtFatalMsg: break; } } diff --git a/src/corelib/io/qloggingcategory.h b/src/corelib/io/qloggingcategory.h index 4aec8e63bf..573af2105c 100644 --- a/src/corelib/io/qloggingcategory.h +++ b/src/corelib/io/qloggingcategory.h @@ -57,10 +57,15 @@ public: bool isEnabled(QtMsgType type) const; void setEnabled(QtMsgType type, bool enable); - bool isDebugEnabled() const { return enabledDebug; } - bool isWarningEnabled() const { return enabledWarning; } - bool isCriticalEnabled() const { return enabledCritical; } - +#ifdef Q_ATOMIC_INT8_IS_SUPPORTED + bool isDebugEnabled() const { return bools.enabledDebug.load(); } + bool isWarningEnabled() const { return bools.enabledWarning.load(); } + bool isCriticalEnabled() const { return bools.enabledCritical.load(); } +#else + bool isDebugEnabled() const { return enabled.load() >> DebugShift & 1; } + bool isWarningEnabled() const { return enabled.load() >> WarningShift & 1; } + bool isCriticalEnabled() const { return enabled.load() >> CriticalShift & 1; } +#endif const char *categoryName() const { return name; } // allows usage of both factory method and variable in qCX macros @@ -78,10 +83,24 @@ private: void *d; // reserved for future use const char *name; - bool enabledDebug; - bool enabledWarning; - bool enabledCritical; - bool placeholder[5]; // reserve for future use +#ifdef Q_BIG_ENDIAN + enum { DebugShift = 0, WarningShift = 8, CriticalShift = 16 }; +#else + enum { DebugShift = 24, WarningShift = 16, CriticalShift = 8 }; +#endif + + struct AtomicBools { +#ifdef Q_ATOMIC_INT8_IS_SUPPORTED + QBasicAtomicInteger<bool> enabledDebug; + QBasicAtomicInteger<bool> enabledWarning; + QBasicAtomicInteger<bool> enabledCritical; +#endif + }; + union { + AtomicBools bools; + QBasicAtomicInt enabled; + }; + bool placeholder[4]; // reserve for future use }; #define Q_DECLARE_LOGGING_CATEGORY(name) \ diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 9f9cba81ab..b03e96d0f6 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Intel Corporation ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -819,9 +820,6 @@ QProcessPrivate::QProcessPrivate() emittedBytesWritten = false; #ifdef Q_OS_WIN notifier = 0; - stdoutReader = 0; - stderrReader = 0; - pipeWriter = 0; processFinishedNotifier = 0; #endif // Q_OS_WIN #ifdef Q_OS_UNIX @@ -889,9 +887,9 @@ void QProcessPrivate::cleanup() notifier = 0; } #endif - destroyChannel(&stdoutChannel); - destroyChannel(&stderrChannel); - destroyChannel(&stdinChannel); + closeChannel(&stdoutChannel); + closeChannel(&stderrChannel); + closeChannel(&stdinChannel); destroyPipe(childStartedPipe); destroyPipe(deathPipe); #ifdef Q_OS_UNIX @@ -901,49 +899,63 @@ void QProcessPrivate::cleanup() /*! \internal + Returns true if we emitted readyRead(). */ -bool QProcessPrivate::_q_canReadStandardOutput() +bool QProcessPrivate::tryReadFromChannel(Channel *channel) { Q_Q(QProcess); - qint64 available = bytesAvailableFromStdout(); - if (available == 0) { - if (stdoutChannel.notifier) - stdoutChannel.notifier->setEnabled(false); - destroyChannel(&stdoutChannel); -#if defined QPROCESS_DEBUG - qDebug("QProcessPrivate::canReadStandardOutput(), 0 bytes available"); -#endif + if (channel->pipe[0] == INVALID_Q_PIPE) return false; - } - char *ptr = outputReadBuffer.reserve(available); - qint64 readBytes = readFromStdout(ptr, available); + qint64 available = bytesAvailableInChannel(channel); + if (available == 0) + available = 1; // always try to read at least one byte + + char *ptr = channel->buffer.reserve(available); + qint64 readBytes = readFromChannel(channel, ptr, available); + if (readBytes <= 0) + channel->buffer.chop(available); + if (readBytes == -2) { + // EWOULDBLOCK + return false; + } if (readBytes == -1) { processError = QProcess::ReadError; q->setErrorString(QProcess::tr("Error reading from process")); emit q->error(processError); #if defined QPROCESS_DEBUG - qDebug("QProcessPrivate::canReadStandardOutput(), failed to read from the process"); + qDebug("QProcessPrivate::tryReadFromChannel(%d), failed to read from the process", channel - &stdinChannel); +#endif + return false; + } + if (readBytes == 0) { + // EOF + if (channel->notifier) + channel->notifier->setEnabled(false); + closeChannel(channel); +#if defined QPROCESS_DEBUG + qDebug("QProcessPrivate::tryReadFromChannel(%d), 0 bytes available", channel - &stdinChannel); #endif return false; } #if defined QPROCESS_DEBUG - qDebug("QProcessPrivate::canReadStandardOutput(), read %d bytes from the process' output", + qDebug("QProcessPrivate::tryReadFromChannel(%d), read %d bytes from the process' output", channel - &stdinChannel int(readBytes)); #endif - if (stdoutChannel.closed) { - outputReadBuffer.chop(readBytes); + if (channel->closed) { + channel->buffer.chop(readBytes); return false; } - outputReadBuffer.chop(available - readBytes); + channel->buffer.chop(available - readBytes); bool didRead = false; + bool isStdout = channel == &stdoutChannel; if (readBytes == 0) { - if (stdoutChannel.notifier) - stdoutChannel.notifier->setEnabled(false); - } else if (processChannel == QProcess::StandardOutput) { + if (channel->notifier) + channel->notifier->setEnabled(false); + } else if ((processChannel == QProcess::StandardOutput) == isStdout) { didRead = true; if (!emittedReadyRead) { emittedReadyRead = true; @@ -951,53 +963,27 @@ bool QProcessPrivate::_q_canReadStandardOutput() emittedReadyRead = false; } } - emit q->readyReadStandardOutput(QProcess::QPrivateSignal()); + if (isStdout) + emit q->readyReadStandardOutput(QProcess::QPrivateSignal()); + else + emit q->readyReadStandardError(QProcess::QPrivateSignal()); return didRead; } /*! \internal */ -bool QProcessPrivate::_q_canReadStandardError() +bool QProcessPrivate::_q_canReadStandardOutput() { - Q_Q(QProcess); - qint64 available = bytesAvailableFromStderr(); - if (available == 0) { - if (stderrChannel.notifier) - stderrChannel.notifier->setEnabled(false); - destroyChannel(&stderrChannel); - return false; - } - - char *ptr = errorReadBuffer.reserve(available); - qint64 readBytes = readFromStderr(ptr, available); - if (readBytes == -1) { - processError = QProcess::ReadError; - q->setErrorString(QProcess::tr("Error reading from process")); - emit q->error(processError); - return false; - } - if (stderrChannel.closed) { - errorReadBuffer.chop(readBytes); - return false; - } - - errorReadBuffer.chop(available - readBytes); + return tryReadFromChannel(&stdoutChannel); +} - bool didRead = false; - if (readBytes == 0) { - if (stderrChannel.notifier) - stderrChannel.notifier->setEnabled(false); - } else if (processChannel == QProcess::StandardError) { - didRead = true; - if (!emittedReadyRead) { - emittedReadyRead = true; - emit q->readyRead(); - emittedReadyRead = false; - } - } - emit q->readyReadStandardError(QProcess::QPrivateSignal()); - return didRead; +/*! + \internal +*/ +bool QProcessPrivate::_q_canReadStandardError() +{ + return tryReadFromChannel(&stderrChannel); } /*! @@ -1009,17 +995,17 @@ bool QProcessPrivate::_q_canWrite() if (stdinChannel.notifier) stdinChannel.notifier->setEnabled(false); - if (writeBuffer.isEmpty()) { + if (stdinChannel.buffer.isEmpty()) { #if defined QPROCESS_DEBUG qDebug("QProcessPrivate::canWrite(), not writing anything (empty write buffer)."); #endif return false; } - qint64 written = writeToStdin(writeBuffer.readPointer(), - writeBuffer.nextDataBlockSize()); + qint64 written = writeToStdin(stdinChannel.buffer.readPointer(), + stdinChannel.buffer.nextDataBlockSize()); if (written < 0) { - destroyChannel(&stdinChannel); + closeChannel(&stdinChannel); processError = QProcess::WriteError; q->setErrorString(QProcess::tr("Error writing to process")); emit q->error(processError); @@ -1031,16 +1017,16 @@ bool QProcessPrivate::_q_canWrite() #endif if (written != 0) { - writeBuffer.free(written); + stdinChannel.buffer.free(written); if (!emittedBytesWritten) { emittedBytesWritten = true; emit q->bytesWritten(written); emittedBytesWritten = false; } } - if (stdinChannel.notifier && !writeBuffer.isEmpty()) + if (stdinChannel.notifier && !stdinChannel.buffer.isEmpty()) stdinChannel.notifier->setEnabled(true); - if (writeBuffer.isEmpty() && stdinChannel.closed) + if (stdinChannel.buffer.isEmpty() && stdinChannel.closed) closeWriteChannel(); return true; } @@ -1163,7 +1149,7 @@ void QProcessPrivate::closeWriteChannel() // instead. flushPipeWriter(); #endif - destroyChannel(&stdinChannel); + closeChannel(&stdinChannel); } /*! @@ -1308,10 +1294,10 @@ void QProcess::setReadChannel(ProcessChannel channel) QByteArray buf = d->buffer.readAll(); if (d->processChannel == QProcess::StandardOutput) { for (int i = buf.size() - 1; i >= 0; --i) - d->outputReadBuffer.ungetChar(buf.at(i)); + d->stdoutChannel.buffer.ungetChar(buf.at(i)); } else { for (int i = buf.size() - 1; i >= 0; --i) - d->errorReadBuffer.ungetChar(buf.at(i)); + d->stderrChannel.buffer.ungetChar(buf.at(i)); } } d->processChannel = channel; @@ -1359,7 +1345,7 @@ void QProcess::closeWriteChannel() { Q_D(QProcess); d->stdinChannel.closed = true; // closing - if (d->writeBuffer.isEmpty()) + if (d->stdinChannel.buffer.isEmpty()) d->closeWriteChannel(); } @@ -1589,8 +1575,8 @@ bool QProcess::canReadLine() const { Q_D(const QProcess); const QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError) - ? &d->errorReadBuffer - : &d->outputReadBuffer; + ? &d->stderrChannel.buffer + : &d->stdoutChannel.buffer; return readBuffer->canReadLine() || QIODevice::canReadLine(); } @@ -1618,8 +1604,8 @@ bool QProcess::atEnd() const { Q_D(const QProcess); const QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError) - ? &d->errorReadBuffer - : &d->outputReadBuffer; + ? &d->stderrChannel.buffer + : &d->stdoutChannel.buffer; return QIODevice::atEnd() && (!isOpen() || readBuffer->isEmpty()); } @@ -1636,8 +1622,8 @@ qint64 QProcess::bytesAvailable() const { Q_D(const QProcess); const QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError) - ? &d->errorReadBuffer - : &d->outputReadBuffer; + ? &d->stderrChannel.buffer + : &d->stdoutChannel.buffer; #if defined QPROCESS_DEBUG qDebug("QProcess::bytesAvailable() == %i (%s)", readBuffer->size(), (d->processChannel == QProcess::StandardError) ? "stderr" : "stdout"); @@ -1650,7 +1636,7 @@ qint64 QProcess::bytesAvailable() const qint64 QProcess::bytesToWrite() const { Q_D(const QProcess); - qint64 size = d->writeBuffer.size(); + qint64 size = d->stdinChannel.buffer.size(); #ifdef Q_OS_WIN size += d->pipeWriterBytesToWrite(); #endif @@ -1897,8 +1883,8 @@ qint64 QProcess::readData(char *data, qint64 maxlen) if (!maxlen) return 0; QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError) - ? &d->errorReadBuffer - : &d->outputReadBuffer; + ? &d->stderrChannel.buffer + : &d->stdoutChannel.buffer; if (maxlen == 1 && !readBuffer->isEmpty()) { int c = readBuffer->getChar(); @@ -1961,7 +1947,7 @@ qint64 QProcess::writeData(const char *data, qint64 len) } if (len == 1) { - d->writeBuffer.putChar(*data); + d->stdinChannel.buffer.putChar(*data); if (d->stdinChannel.notifier) d->stdinChannel.notifier->setEnabled(true); #if defined QPROCESS_DEBUG @@ -1971,7 +1957,7 @@ qint64 QProcess::writeData(const char *data, qint64 len) return 1; } - char *dest = d->writeBuffer.reserve(len); + char *dest = d->stdinChannel.buffer.reserve(len); memcpy(dest, data, len); if (d->stdinChannel.notifier) d->stdinChannel.notifier->setEnabled(true); @@ -2112,8 +2098,8 @@ void QProcessPrivate::start(QIODevice::OpenMode mode) qDebug() << "QProcess::start(" << program << ',' << arguments << ',' << mode << ')'; #endif - outputReadBuffer.clear(); - errorReadBuffer.clear(); + stdoutChannel.buffer.clear(); + stderrChannel.buffer.clear(); if (stdinChannel.type != QProcessPrivate::Channel::Normal) mode &= ~QIODevice::WriteOnly; // not open for writing diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 5d65b2a068..6cd9047c04 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -253,6 +253,9 @@ public: { pipe[0] = INVALID_Q_PIPE; pipe[1] = INVALID_Q_PIPE; +#ifdef Q_OS_WIN + reader = 0; +#endif } void clear(); @@ -282,6 +285,13 @@ public: QString file; QProcessPrivate *process; QSocketNotifier *notifier; +#ifdef Q_OS_WIN + union { + QWindowsPipeReader *reader; + QWindowsPipeWriter *writer; + }; +#endif + QRingBuffer buffer; Q_PIPE pipe[2]; unsigned type : 2; @@ -316,8 +326,10 @@ public: Channel stdinChannel; Channel stdoutChannel; Channel stderrChannel; - bool createChannel(Channel &channel); + bool openChannel(Channel &channel); + void closeChannel(Channel *channel); void closeWriteChannel(); + bool tryReadFromChannel(Channel *channel); // obviously, only stdout and stderr QString program; QStringList arguments; @@ -326,14 +338,9 @@ public: #endif QProcessEnvironment environment; - QRingBuffer outputReadBuffer; - QRingBuffer errorReadBuffer; - QRingBuffer writeBuffer; - Q_PIPE childStartedPipe[2]; Q_PIPE deathPipe[2]; void destroyPipe(Q_PIPE pipe[2]); - void destroyChannel(Channel *channel); QSocketNotifier *startupSocketNotifier; QSocketNotifier *deathNotifier; @@ -341,9 +348,6 @@ public: #ifdef Q_OS_WIN // the wonderful windows notifier QTimer *notifier; - QWindowsPipeReader *stdoutReader; - QWindowsPipeReader *stderrReader; - QWindowsPipeWriter *pipeWriter; QWinEventNotifier *processFinishedNotifier; #endif @@ -383,10 +387,8 @@ public: bool waitForFinished(int msecs = 30000); bool waitForWrite(int msecs = 30000); - qint64 bytesAvailableFromStdout() const; - qint64 bytesAvailableFromStderr() const; - qint64 readFromStdout(char *data, qint64 maxlen); - qint64 readFromStderr(char *data, qint64 maxlen); + qint64 bytesAvailableInChannel(const Channel *channel) const; + qint64 readFromChannel(const Channel *channel, char *data, qint64 maxlen); qint64 writeToStdin(const char *data, qint64 maxlen); void cleanup(); diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 8674371baa..2269740a2f 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -377,7 +377,7 @@ void QProcessPrivate::destroyPipe(int *pipe) } } -void QProcessPrivate::destroyChannel(Channel *channel) +void QProcessPrivate::closeChannel(Channel *channel) { destroyPipe(channel->pipe); } @@ -387,7 +387,7 @@ void QProcessPrivate::destroyChannel(Channel *channel) This function must be called in order: stdin, stdout, stderr */ -bool QProcessPrivate::createChannel(Channel &channel) +bool QProcessPrivate::openChannel(Channel &channel) { Q_Q(QProcess); @@ -573,9 +573,9 @@ void QProcessPrivate::startProcess() processManager()->start(); // Initialize pipes - if (!createChannel(stdinChannel) || - !createChannel(stdoutChannel) || - !createChannel(stderrChannel) || + if (!openChannel(stdinChannel) || + !openChannel(stdoutChannel) || + !openChannel(stderrChannel) || qt_create_pipe(childStartedPipe) != 0 || qt_create_pipe(deathPipe) != 0) { processError = QProcess::FailedToStart; @@ -963,47 +963,32 @@ bool QProcessPrivate::processStarted() return i <= 0; } -qint64 QProcessPrivate::bytesAvailableFromStdout() const +qint64 QProcessPrivate::bytesAvailableInChannel(const Channel *channel) const { + Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE); int nbytes = 0; qint64 available = 0; - if (::ioctl(stdoutChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0) + if (::ioctl(channel->pipe[0], FIONREAD, (char *) &nbytes) >= 0) available = (qint64) nbytes; #if defined (QPROCESS_DEBUG) - qDebug("QProcessPrivate::bytesAvailableFromStdout() == %lld", available); + qDebug("QProcessPrivate::bytesAvailableInChannel(%d) == %lld", channel - &stdinChannel, available); #endif return available; } -qint64 QProcessPrivate::bytesAvailableFromStderr() const +qint64 QProcessPrivate::readFromChannel(const Channel *channel, char *data, qint64 maxlen) { - int nbytes = 0; - qint64 available = 0; - if (::ioctl(stderrChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0) - available = (qint64) nbytes; -#if defined (QPROCESS_DEBUG) - qDebug("QProcessPrivate::bytesAvailableFromStderr() == %lld", available); -#endif - return available; -} - -qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen) -{ - qint64 bytesRead = qt_safe_read(stdoutChannel.pipe[0], data, maxlen); -#if defined QPROCESS_DEBUG - qDebug("QProcessPrivate::readFromStdout(%p \"%s\", %lld) == %lld", - data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead); -#endif - return bytesRead; -} - -qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen) -{ - qint64 bytesRead = qt_safe_read(stderrChannel.pipe[0], data, maxlen); + Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE); + qint64 bytesRead = qt_safe_read(channel->pipe[0], data, maxlen); #if defined QPROCESS_DEBUG - qDebug("QProcessPrivate::readFromStderr(%p \"%s\", %lld) == %lld", + int save_errno = errno; + qDebug("QProcessPrivate::readFromChannel(%d, %p \"%s\", %lld) == %lld", + channel - &stdinChannel, data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead); + errno = save_errno; #endif + if (bytesRead == -1 && errno == EWOULDBLOCK) + return -2; return bytesRead; } @@ -1126,7 +1111,7 @@ bool QProcessPrivate::waitForReadyRead(int msecs) if (stderrChannel.pipe[0] != -1) add_fd(nfds, stderrChannel.pipe[0], &fdread); - if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) + if (!stdinChannel.buffer.isEmpty() && stdinChannel.pipe[1] != -1) add_fd(nfds, stdinChannel.pipe[1], &fdwrite); int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); @@ -1188,7 +1173,7 @@ bool QProcessPrivate::waitForBytesWritten(int msecs) QList<QSocketNotifier *> notifiers = defaultNotifiers(); #endif - while (!writeBuffer.isEmpty()) { + while (!stdinChannel.buffer.isEmpty()) { fd_set fdread; fd_set fdwrite; @@ -1207,7 +1192,7 @@ bool QProcessPrivate::waitForBytesWritten(int msecs) add_fd(nfds, stderrChannel.pipe[0], &fdread); - if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) + if (!stdinChannel.buffer.isEmpty() && stdinChannel.pipe[1] != -1) add_fd(nfds, stdinChannel.pipe[1], &fdwrite); int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); @@ -1282,7 +1267,7 @@ bool QProcessPrivate::waitForFinished(int msecs) if (processState == QProcess::Running) add_fd(nfds, deathPipe[0], &fdread); - if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) + if (!stdinChannel.buffer.isEmpty() && stdinChannel.pipe[1] != -1) add_fd(nfds, stdinChannel.pipe[1], &fdwrite); int timeout = qt_timeout_value(msecs, stopWatch.elapsed()); diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index d7050034bd..7b3f1f8f58 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -158,7 +158,7 @@ static void duplicateStdWriteChannel(Q_PIPE *pipe, DWORD nStdHandle) This function must be called in order: stdin, stdout, stderr */ -bool QProcessPrivate::createChannel(Channel &channel) +bool QProcessPrivate::openChannel(Channel &channel) { Q_Q(QProcess); @@ -180,34 +180,31 @@ bool QProcessPrivate::createChannel(Channel &channel) &channel.pipe[0], 0, TRUE, DUPLICATE_SAME_ACCESS); } } else { - QWindowsPipeReader *pipeReader = 0; if (&channel == &stdoutChannel) { if (processChannelMode != QProcess::ForwardedChannels && processChannelMode != QProcess::ForwardedOutputChannel) { - if (!stdoutReader) { - stdoutReader = new QWindowsPipeReader(q); - q->connect(stdoutReader, SIGNAL(readyRead()), SLOT(_q_canReadStandardOutput())); + if (!stdoutChannel.reader) { + stdoutChannel.reader = new QWindowsPipeReader(q); + q->connect(stdoutChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardOutput())); } - pipeReader = stdoutReader; } else { duplicateStdWriteChannel(channel.pipe, STD_OUTPUT_HANDLE); } } else /* if (&channel == &stderrChannel) */ { if (processChannelMode != QProcess::ForwardedChannels && processChannelMode != QProcess::ForwardedErrorChannel) { - if (!stderrReader) { - stderrReader = new QWindowsPipeReader(q); - q->connect(stderrReader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError())); + if (!stderrChannel.reader) { + stderrChannel.reader = new QWindowsPipeReader(q); + q->connect(stderrChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError())); } - pipeReader = stderrReader; } else { duplicateStdWriteChannel(channel.pipe, STD_ERROR_HANDLE); } } - if (pipeReader) { + if (channel.reader) { qt_create_pipe(channel.pipe, false); - pipeReader->setHandle(channel.pipe[0]); - pipeReader->startAsyncRead(); + channel.reader->setHandle(channel.pipe[0]); + channel.reader->startAsyncRead(); } } @@ -332,25 +329,15 @@ void QProcessPrivate::destroyPipe(Q_PIPE pipe[2]) } } -void QProcessPrivate::destroyChannel(Channel *channel) +void QProcessPrivate::closeChannel(Channel *channel) { if (channel == &stdinChannel) { - if (pipeWriter) { - delete pipeWriter; - pipeWriter = 0; - } - } else if (channel == &stdoutChannel) { - if (stdoutReader) { - stdoutReader->stop(); - stdoutReader->deleteLater(); - stdoutReader = 0; - } - } else if (channel == &stderrChannel) { - if (stderrReader) { - stderrReader->stop(); - stderrReader->deleteLater(); - stderrReader = 0; - } + delete stdinChannel.writer; + stdinChannel.writer = 0; + } else if (channel->reader) { + channel->reader->stop(); + channel->reader->deleteLater(); + channel->reader = 0; } destroyPipe(channel->pipe); } @@ -486,9 +473,9 @@ void QProcessPrivate::startProcess() q->setProcessState(QProcess::Starting); - if (!createChannel(stdinChannel) || - !createChannel(stdoutChannel) || - !createChannel(stderrChannel)) + if (!openChannel(stdinChannel) || + !openChannel(stdoutChannel) || + !openChannel(stderrChannel)) return; QString args = qt_create_commandline(program, arguments); @@ -577,47 +564,25 @@ bool QProcessPrivate::processStarted() return processState == QProcess::Running; } -qint64 QProcessPrivate::bytesAvailableFromStdout() const +qint64 QProcessPrivate::bytesAvailableInChannel(const Channel *channel) const { - if (stdoutChannel.pipe[0] == INVALID_Q_PIPE) - return 0; + Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE); + Q_ASSERT(channel->reader); - if (!stdoutReader) - return 0; - - DWORD bytesAvail = stdoutReader->bytesAvailable(); + DWORD bytesAvail = channel->reader->bytesAvailable(); #if defined QPROCESS_DEBUG - qDebug("QProcessPrivate::bytesAvailableFromStdout() == %d", bytesAvail); + qDebug("QProcessPrivate::bytesAvailableInChannel(%d) == %d", channel - &stdinChannel, bytesAvail); #endif return bytesAvail; } -qint64 QProcessPrivate::bytesAvailableFromStderr() const +qint64 QProcessPrivate::readFromChannel(const Channel *channel, char *data, qint64 maxlen) { - if (stderrChannel.pipe[0] == INVALID_Q_PIPE) - return 0; - - if (!stderrReader) - return 0; - - DWORD bytesAvail = stderrReader->bytesAvailable(); -#if defined QPROCESS_DEBUG - qDebug("QProcessPrivate::bytesAvailableFromStderr() == %d", bytesAvail); -#endif - return bytesAvail; + Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE); + Q_ASSERT(channel->reader); + return channel->reader->read(data, maxlen); } -qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen) -{ - return stdoutReader ? stdoutReader->read(data, maxlen) : 0; -} - -qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen) -{ - return stderrReader ? stderrReader->read(data, maxlen) : 0; -} - - static BOOL QT_WIN_CALLBACK qt_terminateApp(HWND hwnd, LPARAM procId) { DWORD currentProcId = 0; @@ -659,20 +624,20 @@ bool QProcessPrivate::waitForStarted(int) bool QProcessPrivate::drainOutputPipes() { - if (!stdoutReader && !stderrReader) + if (!stdoutChannel.reader && !stderrChannel.reader) return false; bool someReadyReadEmitted = false; forever { bool readyReadEmitted = false; bool readOperationActive = false; - if (stdoutReader) { - readyReadEmitted |= stdoutReader->waitForReadyRead(0); - readOperationActive = stdoutReader && stdoutReader->isReadOperationActive(); + if (stdoutChannel.reader) { + readyReadEmitted |= stdoutChannel.reader->waitForReadyRead(0); + readOperationActive = stdoutChannel.reader && stdoutChannel.reader->isReadOperationActive(); } - if (stderrReader) { - readyReadEmitted |= stderrReader->waitForReadyRead(0); - readOperationActive |= stderrReader && stderrReader->isReadOperationActive(); + if (stderrChannel.reader) { + readyReadEmitted |= stderrChannel.reader->waitForReadyRead(0); + readOperationActive |= stderrChannel.reader && stderrChannel.reader->isReadOperationActive(); } someReadyReadEmitted |= readyReadEmitted; if (!readOperationActive || !readyReadEmitted) @@ -690,13 +655,13 @@ bool QProcessPrivate::waitForReadyRead(int msecs) QIncrementalSleepTimer timer(msecs); forever { - if (!writeBuffer.isEmpty() && !_q_canWrite()) + if (!stdinChannel.buffer.isEmpty() && !_q_canWrite()) return false; - if (pipeWriter && pipeWriter->waitForWrite(0)) + if (stdinChannel.writer && stdinChannel.writer->waitForWrite(0)) timer.resetIncrements(); - if ((stdoutReader && stdoutReader->waitForReadyRead(0)) - || (stderrReader && stderrReader->waitForReadyRead(0))) + if ((stdoutChannel.reader && stdoutChannel.reader->waitForReadyRead(0)) + || (stderrChannel.reader && stderrChannel.reader->waitForReadyRead(0))) return true; if (!pid) @@ -726,12 +691,12 @@ bool QProcessPrivate::waitForBytesWritten(int msecs) forever { // Check if we have any data pending: the pipe writer has // bytes waiting to written, or it has written data since the - // last time we called pipeWriter->waitForWrite(). - bool pendingDataInPipe = pipeWriter && (pipeWriter->bytesToWrite() || pipeWriter->hadWritten()); + // last time we called stdinChannel.writer->waitForWrite(). + bool pendingDataInPipe = stdinChannel.writer && (stdinChannel.writer->bytesToWrite() || stdinChannel.writer->hadWritten()); // If we don't have pending data, and our write buffer is // empty, we fail. - if (!pendingDataInPipe && writeBuffer.isEmpty()) + if (!pendingDataInPipe && stdinChannel.buffer.isEmpty()) return false; // If we don't have pending data and we do have data in our @@ -746,21 +711,21 @@ bool QProcessPrivate::waitForBytesWritten(int msecs) // written. This will succeed if either the pipe writer has // already written the data, or if it manages to write data // within the given timeout. If the write buffer was non-empty - // and the pipeWriter is now dead, that means _q_canWrite() + // and the stdinChannel.writer is now dead, that means _q_canWrite() // destroyed the writer after it successfully wrote the last // batch. - if (!pipeWriter || pipeWriter->waitForWrite(0)) + if (!stdinChannel.writer || stdinChannel.writer->waitForWrite(0)) return true; // If we wouldn't write anything, check if we can read stdout. - if (bytesAvailableFromStdout() != 0) { - _q_canReadStandardOutput(); + if (bytesAvailableInChannel(&stdoutChannel) != 0) { + tryReadFromChannel(&stdoutChannel); timer.resetIncrements(); } // Check if we can read stderr. - if (bytesAvailableFromStderr() != 0) { - _q_canReadStandardError(); + if (bytesAvailableInChannel(&stderrChannel) != 0) { + tryReadFromChannel(&stderrChannel); timer.resetIncrements(); } @@ -795,13 +760,13 @@ bool QProcessPrivate::waitForFinished(int msecs) QIncrementalSleepTimer timer(msecs); forever { - if (!writeBuffer.isEmpty() && !_q_canWrite()) + if (!stdinChannel.buffer.isEmpty() && !_q_canWrite()) return false; - if (pipeWriter && pipeWriter->waitForWrite(0)) + if (stdinChannel.writer && stdinChannel.writer->waitForWrite(0)) timer.resetIncrements(); - if (stdoutReader && stdoutReader->waitForReadyRead(0)) + if (stdoutChannel.reader && stdoutChannel.reader->waitForReadyRead(0)) timer.resetIncrements(); - if (stderrReader && stderrReader->waitForReadyRead(0)) + if (stderrChannel.reader && stderrChannel.reader->waitForReadyRead(0)) timer.resetIncrements(); if (!pid) { @@ -837,33 +802,32 @@ void QProcessPrivate::findExitCode() void QProcessPrivate::flushPipeWriter() { - if (pipeWriter && pipeWriter->bytesToWrite() > 0) { - pipeWriter->waitForWrite(ULONG_MAX); - } + if (stdinChannel.writer && stdinChannel.writer->bytesToWrite() > 0) + stdinChannel.writer->waitForWrite(ULONG_MAX); } qint64 QProcessPrivate::pipeWriterBytesToWrite() const { - return pipeWriter ? pipeWriter->bytesToWrite() : qint64(0); + return stdinChannel.writer ? stdinChannel.writer->bytesToWrite() : qint64(0); } qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen) { Q_Q(QProcess); - if (!pipeWriter) { - pipeWriter = new QWindowsPipeWriter(stdinChannel.pipe[1], q); - pipeWriter->start(); + if (!stdinChannel.writer) { + stdinChannel.writer = new QWindowsPipeWriter(stdinChannel.pipe[1], q); + stdinChannel.writer->start(); } - return pipeWriter->write(data, maxlen); + return stdinChannel.writer->write(data, maxlen); } bool QProcessPrivate::waitForWrite(int msecs) { Q_Q(QProcess); - if (!pipeWriter || pipeWriter->waitForWrite(msecs)) + if (!stdinChannel.writer || stdinChannel.writer->waitForWrite(msecs)) return true; processError = QProcess::Timedout; @@ -875,7 +839,7 @@ void QProcessPrivate::_q_notified() { notifier->stop(); - if (!writeBuffer.isEmpty() && (!pipeWriter || pipeWriter->waitForWrite(0))) + if (!stdinChannel.buffer.isEmpty() && (!stdinChannel.writer || stdinChannel.writer->waitForWrite(0))) _q_canWrite(); if (processState != QProcess::NotRunning) diff --git a/src/corelib/io/qprocess_wince.cpp b/src/corelib/io/qprocess_wince.cpp index ad9a328133..e0bee48598 100644 --- a/src/corelib/io/qprocess_wince.cpp +++ b/src/corelib/io/qprocess_wince.cpp @@ -62,7 +62,7 @@ void QProcessPrivate::destroyPipe(Q_PIPE pipe[2]) Q_UNUSED(pipe); } -void QProcessPrivate::destroyChannel(Channel *channel) +void QProcessPrivate::closeChannel(Channel *channel) { Q_UNUSED(channel); } @@ -174,22 +174,12 @@ bool QProcessPrivate::processStarted() return processState == QProcess::Running; } -qint64 QProcessPrivate::bytesAvailableFromStdout() const +qint64 QProcessPrivate::bytesAvailableInChannel(const Channel *) const { return 0; } -qint64 QProcessPrivate::bytesAvailableFromStderr() const -{ - return 0; -} - -qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen) -{ - return -1; -} - -qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen) +qint64 QProcessPrivate::readFromChannel(const Channel *, char *data, qint64 maxlen) { return -1; } diff --git a/src/corelib/io/qstandardpaths_winrt.cpp b/src/corelib/io/qstandardpaths_winrt.cpp index aa3b710f52..81b9d10baf 100644 --- a/src/corelib/io/qstandardpaths_winrt.cpp +++ b/src/corelib/io/qstandardpaths_winrt.cpp @@ -104,14 +104,23 @@ QString QStandardPaths::writableLocation(StandardLocation type) case GenericCacheLocation: return writableLocation(GenericDataLocation) + QLatin1String("/cache"); - case RuntimeLocation: - case HomeLocation: - result = QDir::homePath(); - break; - case TempLocation: result = QDir::tempPath(); break; + + case ApplicationsLocation: + case DesktopLocation: + case FontsLocation: + case HomeLocation: + case RuntimeLocation: + // these are read-only + break; + + case DocumentsLocation: + case MusicLocation: + case MoviesLocation: + case PicturesLocation: + case DownloadLocation: default: Q_UNIMPLEMENTED(); } diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index 7dd2125e70..d8a3ec9b42 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -132,7 +132,7 @@ qint64 QWindowsPipeReader::bytesAvailable() const qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) { if (pipeBroken && actualReadBufferSize == 0) - return -1; // signal EOF + return 0; // signal EOF qint64 readSoFar; // If startAsyncRead() has read data, copy it to its destination. @@ -159,6 +159,8 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) emitReadyReadTimer->stop(); if (!readSequenceStarted) startAsyncRead(); + if (readSoFar == 0) + return -2; // signal EWOULDBLOCK } return readSoFar; diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 64ad2ff0d3..f38ac7bf26 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -325,8 +325,6 @@ QEventDispatcherWin32Private::~QEventDispatcherWin32Private() { if (internalHwnd) DestroyWindow(internalHwnd); - QString className = QLatin1String("QEventDispatcherWin32_Internal_Widget") + QString::number(quintptr(qt_internal_proc)); - UnregisterClass((wchar_t*)className.utf16(), qWinAppInst()); } void QEventDispatcherWin32Private::activateEventNotifier(QWinEventNotifier * wen) @@ -486,10 +484,26 @@ LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp) #endif } -static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher) +// Provide class name and atom for the message window used by +// QEventDispatcherWin32Private via Q_GLOBAL_STATIC shared between threads. +struct QWindowsMessageWindowClassContext +{ + QWindowsMessageWindowClassContext(); + ~QWindowsMessageWindowClassContext(); + + ATOM atom; + wchar_t *className; +}; + +QWindowsMessageWindowClassContext::QWindowsMessageWindowClassContext() + : atom(0), className(0) { // make sure that multiple Qt's can coexist in the same process - QString className = QLatin1String("QEventDispatcherWin32_Internal_Widget") + QString::number(quintptr(qt_internal_proc)); + const QString qClassName = QStringLiteral("QEventDispatcherWin32_Internal_Widget") + + QString::number(quintptr(qt_internal_proc)); + className = new wchar_t[qClassName.size() + 1]; + qClassName.toWCharArray(className); + className[qClassName.size()] = 0; WNDCLASS wc; wc.style = 0; @@ -501,16 +515,37 @@ static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatch wc.hCursor = 0; wc.hbrBackground = 0; wc.lpszMenuName = NULL; - wc.lpszClassName = reinterpret_cast<const wchar_t *> (className.utf16()); + wc.lpszClassName = className; + atom = RegisterClass(&wc); + if (!atom) { + qErrnoWarning("%s: RegisterClass() failed", Q_FUNC_INFO, qPrintable(qClassName)); + delete [] className; + className = 0; + } +} + +QWindowsMessageWindowClassContext::~QWindowsMessageWindowClassContext() +{ + if (className) { + UnregisterClass(className, qWinAppInst()); + delete [] className; + } +} + +Q_GLOBAL_STATIC(QWindowsMessageWindowClassContext, qWindowsMessageWindowClassContext) - RegisterClass(&wc); +static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher) +{ + QWindowsMessageWindowClassContext *ctx = qWindowsMessageWindowClassContext(); + if (!ctx->atom) + return 0; #ifdef Q_OS_WINCE HWND parent = 0; #else HWND parent = HWND_MESSAGE; #endif - HWND wnd = CreateWindow(wc.lpszClassName, // classname - wc.lpszClassName, // window name + HWND wnd = CreateWindow(ctx->className, // classname + ctx->className, // window name 0, // style 0, 0, 0, 0, // geometry parent, // parent @@ -519,7 +554,8 @@ static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatch 0); // windows creation data. if (!wnd) { - qWarning("QEventDispatcher: Failed to create QEventDispatcherWin32 internal window: %d\n", (int)GetLastError()); + qErrnoWarning("%s: CreateWindow() for QEventDispatcherWin32 internal window failed", Q_FUNC_INFO); + return 0; } #ifdef GWLP_USERDATA @@ -620,7 +656,9 @@ void QEventDispatcherWin32::createInternalHwnd() // setup GetMessage hook needed to drive our posted events d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId()); if (!d->getMessageHook) { - qFatal("Qt: INTERNALL ERROR: failed to install GetMessage hook"); + int errorCode = GetLastError(); + qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s", + errorCode, qPrintable(qt_error_string(errorCode))); } #endif diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index 311ebaa092..cbd3d776a7 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -113,10 +113,8 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) { jclass jQtNative = env->FindClass("org/qtproject/qt5/android/QtNative"); - if (env->ExceptionCheck()) { - env->ExceptionClear(); + if (exceptionCheck(env)) return JNI_ERR; - } jmethodID activityMethodID = env->GetStaticMethodID(jQtNative, "activity", diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index a8e9f4a7e9..6670311353 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -3238,7 +3238,7 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, int method_index_absolute = method_index + method_offset; while (c2) { - if (c2->receiver == receiver && c2->method() == method_index_absolute) + if (!c2->isSlotObject && c2->receiver == receiver && c2->method() == method_index_absolute) return 0; c2 = c2->nextConnectionList; } diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h index de6f65ab7d..de95fcc313 100644 --- a/src/corelib/kernel/qobjectdefs_impl.h +++ b/src/corelib/kernel/qobjectdefs_impl.h @@ -622,7 +622,7 @@ namespace QtPrivate { static char test(...); enum { Ok = sizeof(test(dummy<Functor>())) == sizeof(int), - Value = Ok ? sizeof...(ArgList) : int(ComputeFunctorArgumentCountHelper<Functor, List<ArgList...>, Ok>::Value) + Value = Ok ? int(sizeof...(ArgList)) : int(ComputeFunctorArgumentCountHelper<Functor, List<ArgList...>, Ok>::Value) }; }; diff --git a/src/corelib/kernel/qtcore_eval.cpp b/src/corelib/kernel/qtcore_eval.cpp index 40c1157fb4..a5c4c36638 100644 --- a/src/corelib/kernel/qtcore_eval.cpp +++ b/src/corelib/kernel/qtcore_eval.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE static const char boilerplate_supported_but_time_limited[] = "\nQt %1 Evaluation License\n" - "Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).\n" + "Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).\n" "This trial version may only be used for evaluation purposes\n" "and will shut down after 120 minutes.\n" "Registered to:\n" @@ -65,7 +65,7 @@ static const char boilerplate_supported_but_time_limited[] = static const char boilerplate_supported[] = "\nQt %1 Evaluation License\n" - "Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).\n" + "Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).\n" "This trial version may only be used for evaluation purposes\n" "Registered to:\n" " Licensee: %2\n\n" diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 9736950c89..50281b632a 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -359,7 +359,7 @@ class QLibraryStore { public: inline ~QLibraryStore(); - static inline QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version); + static inline QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version, QLibrary::LoadHints loadHints); static inline void releaseLibrary(QLibraryPrivate *lib); static inline void cleanup(); @@ -438,17 +438,21 @@ QLibraryStore *QLibraryStore::instance() return qt_library_data; } -inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, const QString &version) +inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, const QString &version, + QLibrary::LoadHints loadHints) { QMutexLocker locker(&qt_library_mutex); QLibraryStore *data = instance(); // check if this library is already loaded QLibraryPrivate *lib = 0; - if (Q_LIKELY(data)) + if (Q_LIKELY(data)) { lib = data->libraryMap.value(fileName); + if (lib) + lib->mergeLoadHints(loadHints); + } if (!lib) - lib = new QLibraryPrivate(fileName, version); + lib = new QLibraryPrivate(fileName, version, loadHints); // track this library if (Q_LIKELY(data)) @@ -479,21 +483,34 @@ inline void QLibraryStore::releaseLibrary(QLibraryPrivate *lib) delete lib; } -QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version) +QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints) : pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0), - loadHints(0), + loadHints(loadHints), libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin) -{ } +{ + if (canonicalFileName.isEmpty()) + errorString = QLibrary::tr("The shared library was not found."); +} -QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version) +QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version, + QLibrary::LoadHints loadHints) { - return QLibraryStore::findOrCreate(fileName, version); + return QLibraryStore::findOrCreate(fileName, version, loadHints); } QLibraryPrivate::~QLibraryPrivate() { } +void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh) +{ + // if the library is already loaded, we can't change the load hints + if (pHnd) + return; + + loadHints = lh; +} + QFunctionPointer QLibraryPrivate::resolve(const char *symbol) { if (!pHnd) diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h index 20b0c7e20f..e58d18e87b 100644 --- a/src/corelib/plugin/qlibrary_p.h +++ b/src/corelib/plugin/qlibrary_p.h @@ -94,7 +94,8 @@ public: void release(); QFunctionPointer resolve(const char *); - static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString()); + static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString(), + QLibrary::LoadHints loadHints = 0); static QStringList suffixes_sys(const QString &fullVersion); static QStringList prefixes_sys(); @@ -117,8 +118,9 @@ public: } private: - explicit QLibraryPrivate(const QString &canonicalFileName, const QString &version); + explicit QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints); ~QLibraryPrivate(); + void mergeLoadHints(QLibrary::LoadHints loadHints); bool load_sys(); bool unload_sys(); diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp index e4a1d725ec..2c139669e6 100644 --- a/src/corelib/plugin/qpluginloader.cpp +++ b/src/corelib/plugin/qpluginloader.cpp @@ -352,11 +352,8 @@ void QPluginLoader::setFileName(const QString &fileName) else fn = locatePlugin(fileName); - d = QLibraryPrivate::findOrCreate(fn); - d->loadHints = lh; - if (fn.isEmpty()) - d->errorString = QLibrary::tr("The shared library was not found."); - else + d = QLibraryPrivate::findOrCreate(fn, QString(), lh); + if (!fn.isEmpty()) d->updatePluginState(); #else diff --git a/src/corelib/thread/qatomic.cpp b/src/corelib/thread/qatomic.cpp index 33e85c1505..b2043a45a1 100644 --- a/src/corelib/thread/qatomic.cpp +++ b/src/corelib/thread/qatomic.cpp @@ -58,6 +58,7 @@ \inmodule QtCore \brief The QAtomicInteger class provides platform-independent atomic operations on integers. \ingroup thread + \since 5.3 For atomic operations on pointers, see the QAtomicPointer class. diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index fe5beb1c01..5e3f3a1cab 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -380,7 +380,7 @@ bool QBasicMutex::isRecursive() */ /*! - \fn QMutex *QMutexLocker::mutex() + \fn QMutex *QMutexLocker::mutex() const Returns the mutex on which the QMutexLocker is operating. diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index 0ecc96a9b1..011555f904 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -77,7 +77,7 @@ public: return fastTryLock(); } - bool isRecursive(); + bool isRecursive(); //### Qt6: mark const private: inline bool fastTryLock() Q_DECL_NOTHROW { @@ -186,10 +186,10 @@ public: inline explicit QMutex(RecursionMode mode = NonRecursive) { Q_UNUSED(mode); } - static inline void lock() {} - static inline bool tryLock(int timeout = 0) { Q_UNUSED(timeout); return true; } - static inline void unlock() {} - static inline bool isRecursive() { return true; } + inline void lock() {} + inline bool tryLock(int timeout = 0) { Q_UNUSED(timeout); return true; } + inline void unlock() {} + inline bool isRecursive() { return true; } private: Q_DISABLE_COPY(QMutex) @@ -201,9 +201,9 @@ public: inline explicit QMutexLocker(QMutex *) {} inline ~QMutexLocker() {} - static inline void unlock() {} - static void relock() {} - static inline QMutex *mutex() { return 0; } + inline void unlock() {} + void relock() {} + inline QMutex *mutex() const { return 0; } private: Q_DISABLE_COPY(QMutexLocker) diff --git a/src/corelib/tools/qcollator_icu.cpp b/src/corelib/tools/qcollator_icu.cpp index 407a493d25..23e88b5015 100644 --- a/src/corelib/tools/qcollator_icu.cpp +++ b/src/corelib/tools/qcollator_icu.cpp @@ -75,10 +75,17 @@ void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs) { detach(); - UColAttributeValue val = (cs == Qt::CaseSensitive) ? UCOL_UPPER_FIRST : UCOL_OFF; + // The strength attribute in ICU is rather badly documented. Basically UCOL_PRIMARY + // ignores differences between base characters and accented characters as well as case. + // So A and A-umlaut would compare equal. + // UCOL_SECONDARY ignores case differences. UCOL_TERTIARY is the default in most languages + // and does case sensitive comparison. + // UCOL_QUATERNARY is used as default in a few languages such as Japanese to take care of some + // additional differences in those languages. + UColAttributeValue val = (cs == Qt::CaseSensitive) ? UCOL_DEFAULT_STRENGTH : UCOL_SECONDARY; UErrorCode status = U_ZERO_ERROR; - ucol_setAttribute(d->collator, UCOL_CASE_FIRST, val, &status); + ucol_setAttribute(d->collator, UCOL_STRENGTH, val, &status); if (U_FAILURE(status)) qWarning("ucol_setAttribute: Case First failed: %d", status); } diff --git a/src/corelib/tools/qcollator_macx.cpp b/src/corelib/tools/qcollator_macx.cpp index 8985cd4eba..877510489a 100644 --- a/src/corelib/tools/qcollator_macx.cpp +++ b/src/corelib/tools/qcollator_macx.cpp @@ -128,12 +128,15 @@ bool QCollator::ignorePunctuation() const int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) const { SInt32 result; - return UCCompareText(d->collator.collator, + Boolean equivalent; + UCCompareText(d->collator.collator, reinterpret_cast<const UniChar *>(s1), len1, reinterpret_cast<const UniChar *>(s2), len2, - NULL, + &equivalent, &result); - return result; + if (equivalent) + return 0; + return result < 0 ? -1 : 1; } int QCollator::compare(const QString &str1, const QString &str2) const { diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h index b17c6d2f40..5d25b0add1 100644 --- a/src/corelib/tools/qringbuffer_p.h +++ b/src/corelib/tools/qringbuffer_p.h @@ -90,7 +90,7 @@ public: // special case: it is in the first buffer int nextDataBlockSizeValue = nextDataBlockSize(); - if (pos - head < nextDataBlockSizeValue) { + if (pos < nextDataBlockSizeValue) { length = nextDataBlockSizeValue - pos; return buffers.at(0).constData() + head + pos; } diff --git a/src/corelib/tools/qscopedvaluerollback.cpp b/src/corelib/tools/qscopedvaluerollback.cpp index f37a232985..bd3e03c464 100644 --- a/src/corelib/tools/qscopedvaluerollback.cpp +++ b/src/corelib/tools/qscopedvaluerollback.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE \since 4.8 \ingroup misc - The QScopedAssignment class can be used to revert state when an + The QScopedValueRollback class can be used to revert state when an exception is thrown without needing to write try-catch blocks. It can also be used to manage variables that are temporarily set, diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index 8ce7b63f46..19a1943367 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -220,8 +220,10 @@ || (defined(Q_CC_CLANG) && (__clang_major__ * 100 + __clang_minor__ >= 208)) \ || defined(Q_CC_INTEL)) # define QT_COMPILER_SUPPORTS_X86INTRIN -# ifndef Q_CC_INTEL +# ifdef Q_CC_INTEL // The Intel compiler has no <x86intrin.h> -- all intrinsics are in <immintrin.h>; +# include <immintrin.h> +# else // GCC 4.4 and Clang 2.8 added a few more intrinsics there # include <x86intrin.h> # endif diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index a7f932698b..7aaddb9b52 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -9894,9 +9894,7 @@ QString QString::toHtmlEscaped() const the read-only segment of the compiled object file. For compilers not supporting the creation of compile time strings, QStringLiteral will fall back to - QLatin1String. - - The result of the QStringLiteral expression can be cast into a QString. + QString::fromUtf8(). If you have code looking like: \code |