diff options
author | João Abecasis <joao@abecasis.name> | 2009-11-04 15:30:38 (GMT) |
---|---|---|
committer | João Abecasis <joao@abecasis.name> | 2009-11-04 19:21:56 (GMT) |
commit | c08e708037d33271825ce6a6a1ac640e96b70c36 (patch) | |
tree | ace4fe99046134dd10ae8d182e7cb8bf532abd52 /src/corelib | |
parent | d1ffc7422e71e42a329f7a9c78b6e584109169f3 (diff) | |
download | Qt-c08e708037d33271825ce6a6a1ac640e96b70c36.zip Qt-c08e708037d33271825ce6a6a1ac640e96b70c36.tar.gz Qt-c08e708037d33271825ce6a6a1ac640e96b70c36.tar.bz2 |
Remove 4k-chunking in QFSFileEngine::read/writeFdFh
This was a serious performance issue on Symbian and not necessarily
optimal on other platforms. For the time being, we'll allow the OS to
read/write as much as it can.
Otherwise cleaned up the code, adding checks for invalid len arguments.
Task-number: QT-2347
Reviewed-by: Peter Hartmann
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/io/qfsfileengine.cpp | 163 |
1 files changed, 78 insertions, 85 deletions
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index fb096a7..7ea1815 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -622,71 +622,55 @@ qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len) { Q_Q(QFSFileEngine); - // Buffered stdlib mode. + if (len < 0 || len != qint64(size_t(len))) { + q->setError(QFile::ReadError, qt_error_string(EINVAL)); + return -1; + } + + qint64 readBytes = 0; + bool eof = false; + if (fh) { - qint64 readBytes = 0; - qint64 read = 0; - int retry = 0; + // Buffered stdlib mode. - // Read in blocks of 4k to avoid platform limitations (Windows - // commonly bails out if you read or write too large blocks at once). - qint64 bytesToRead; + size_t result; + bool retry = true; do { - if (retry == 1) - retry = 2; - - bytesToRead = qMin<qint64>(4096, len - read); - do { - readBytes = fread(data + read, 1, size_t(bytesToRead), fh); - } while (readBytes == 0 && !feof(fh) && errno == EINTR); - - if (readBytes > 0) { - read += readBytes; - } else if (!retry && feof(fh)) { - // Synchronize and try again (just once though). - if (++retry == 1) - QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); + result = fread(data + readBytes, 1, size_t(len - readBytes), fh); + eof = feof(fh); + if (retry && eof && result == 0) { + // On Mac OS, this is needed, e.g., if a file was written to + // through another stream since our last read. See test + // tst_QFile::appendAndRead + QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); // re-sync stream. + retry = false; + continue; } - } while (retry == 1 || (readBytes == bytesToRead && read < len)); + readBytes += result; + } while (!eof && (result == 0 ? errno == EINTR : readBytes < len)); - // Return the number of bytes read, or if nothing was read, return -1 - // if an error occurred, or 0 if we detected EOF. - if (read == 0) { - q->setError(QFile::ReadError, qt_error_string(int(errno))); - if (!feof(fh)) - read = -1; - } - return read; - } + } else if (fd != -1) { + // Unbuffered stdio mode. - // Unbuffered stdio mode. - qint64 ret = 0; - if (len) { +#ifdef Q_OS_WIN int result; - qint64 read = 0; - errno = 0; - - // Read in blocks of 4k to avoid platform limitations (Windows - // commonly bails out if you read or write too large blocks at once). +#else + ssize_t result; +#endif do { - qint64 bytesToRead = qMin<qint64>(4096, len - read); - do { - result = QT_READ(fd, data + read, int(bytesToRead)); - } while (result == -1 && errno == EINTR); - if (result > 0) - read += result; - } while (result > 0 && read < len); - - // Return the number of bytes read, or if nothing was read, return -1 - // if an error occurred. - if (read > 0) { - ret += read; - } else if (read == 0 && result < 0) { - ret = -1; - q->setError(QFile::ReadError, qt_error_string(errno)); - } + result = QT_READ(fd, data + readBytes, size_t(len - readBytes)); + } while ((result == -1 && errno == EINTR) + || (result > 0 && (readBytes += result) < len)); + + eof = !(result == -1); } - return ret; + + if (!eof && readBytes == 0) { + readBytes = -1; + q->setError(QFile::ReadError, qt_error_string(errno)); + } + + return readBytes; } /*! @@ -766,36 +750,45 @@ qint64 QFSFileEngine::write(const char *data, qint64 len) qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len) { Q_Q(QFSFileEngine); - qint64 result; - qint64 written = 0; - do { - // Write blocks of 4k to avoid platform limitations (Windows commonly - // bails out if you read or write too large blocks at once). - qint64 bytesToWrite = qMin<qint64>(4096, len - written); - if (fh) { - do { - // Buffered stdlib mode. - result = qint64(fwrite(data + written, 1, size_t(bytesToWrite), fh)); - } while (result == 0 && errno == EINTR); - if (bytesToWrite > 0 && result == 0) - result = -1; - } else { - do { - // Unbuffered stdio mode. - result = QT_WRITE(fd, data + written, bytesToWrite); - } while (result == -1 && errno == EINTR); - } - if (result > 0) - written += qint64(result); - } while (written < len && result > 0); - - // If we read anything, return that with success. Otherwise, set an error, - // and return the last return value. - if (result > 0) - return written; - q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, qt_error_string(errno)); - return result; + if (len < 0 || len != qint64(size_t(len))) { + q->setError(QFile::WriteError, qt_error_string(EINVAL)); + return -1; + } + + qint64 writtenBytes = 0; + + if (fh) { + // Buffered stdlib mode. + + size_t result; + bool eof; + do { + result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh); + writtenBytes += result; + eof = feof(fh); + } while (!eof && (result == 0 ? errno == EINTR : writtenBytes < len)); + + } else if (fd != -1) { + // Unbuffered stdio mode. + +#ifdef Q_OS_WIN + int result; +#else + ssize_t result; +#endif + do { + result = QT_WRITE(fd, data + writtenBytes, size_t(len - writtenBytes)); + } while ((result == -1 && errno == EINTR) + || (result > 0 && (writtenBytes += result) < len)); + } + + if (writtenBytes == 0) { + writtenBytes = -1; + q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, qt_error_string(errno)); + } + + return writtenBytes; } /*! |