diff options
author | Thomas McGuire <thomas.mcguire.qnx@kdab.com> | 2012-10-17 10:29:33 (GMT) |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2012-10-31 00:03:22 (GMT) |
commit | a5e13ebb6080053dc65be30ad8e51010c496fea6 (patch) | |
tree | 55c4672462ede21fce93ec9fea6d51c52362dc4e /src/corelib | |
parent | da113c065991f2e1d25fd507daf79f5aeb691522 (diff) | |
download | Qt-a5e13ebb6080053dc65be30ad8e51010c496fea6.zip Qt-a5e13ebb6080053dc65be30ad8e51010c496fea6.tar.gz Qt-a5e13ebb6080053dc65be30ad8e51010c496fea6.tar.bz2 |
QNX: Use extra information in dirent to avoid stat() calls
This improves iterating over /usr/bin with QDirIterator by more
than half, from 36 to 13 milliseconds.
This is a backport of
qtbase commit 391d2e37f3b301097cd23fdaf99dc34ed6a114a5
Change-Id: I45e9159c82d1840f21dbab81fc39f140490549b7
Reviewed-by: Rafael Roquetto <rafael.roquetto@kdab.com>
Reviewed-by: Kevin Krammer <kevin.krammer@kdab.com>
Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/io/qfilesystemengine.cpp | 49 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemiterator_p.h | 4 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemiterator_unix.cpp | 18 |
3 files changed, 69 insertions, 2 deletions
diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp index 89d9457..2102837 100644 --- a/src/corelib/io/qfilesystemengine.cpp +++ b/src/corelib/io/qfilesystemengine.cpp @@ -232,6 +232,19 @@ bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data) return false; } +#if defined(Q_OS_QNX) +static void fillStat64fromStat32(struct stat64 *statBuf64, const struct stat &statBuf32) +{ + statBuf64->st_mode = statBuf32.st_mode; + statBuf64->st_size = statBuf32.st_size; + statBuf64->st_ctime = statBuf32.st_ctime; + statBuf64->st_mtime = statBuf32.st_mtime; + statBuf64->st_atime = statBuf32.st_atime; + statBuf64->st_uid = statBuf32.st_uid; + statBuf64->st_gid = statBuf32.st_gid; +} +#endif + void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer) { // Permissions @@ -289,7 +302,41 @@ void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer) void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry) { -#if defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4) || defined(Q_OS_SYMBIAN) +#if defined(Q_OS_QNX) + entryFlags = 0; + knownFlagsMask = 0; + for (dirent_extra *extra = _DEXTRA_FIRST(&entry); _DEXTRA_VALID(extra, &entry); + extra = _DEXTRA_NEXT(extra)) { + if (extra->d_type == _DTYPE_STAT || extra->d_type == _DTYPE_LSTAT) { + + const struct dirent_extra_stat * const extra_stat = + reinterpret_cast<struct dirent_extra_stat *>(extra); + + // For symlinks, the extra type _DTYPE_LSTAT doesn't work for filling out the meta data, + // as we need the stat() information there, not the lstat() information. + // In this case, don't use the extra information. + // Unfortunately, readdir() never seems to return extra info of type _DTYPE_STAT, so for + // symlinks, we always incur the cost of an extra stat() call later. + if (S_ISLNK(extra_stat->d_stat.st_mode) && extra->d_type == _DTYPE_LSTAT) + continue; + +#if defined(__EXT_LF64SRC) + // Even with large file support, d_stat is always of type struct stat, not struct stat64, + // so it needs to be converted + struct stat64 statBuf; + fillStat64fromStat32(&statBuf, extra_stat->d_stat); + fillFromStatBuf(statBuf); +#else + fillFromStatBuf(extra_stat->d_stat); +#endif + knownFlagsMask |= QFileSystemMetaData::PosixStatFlags; + if (!S_ISLNK(extra_stat->d_stat.st_mode)) { + knownFlagsMask |= QFileSystemMetaData::ExistsAttribute; + entryFlags |= QFileSystemMetaData::ExistsAttribute; + } + } + } +#elif defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4) || defined(Q_OS_SYMBIAN) // BSD4 includes Mac OS X // ### This will clear all entry flags and knownFlagsMask diff --git a/src/corelib/io/qfilesystemiterator_p.h b/src/corelib/io/qfilesystemiterator_p.h index 00d7108..bb2af60 100644 --- a/src/corelib/io/qfilesystemiterator_p.h +++ b/src/corelib/io/qfilesystemiterator_p.h @@ -106,6 +106,10 @@ private: #if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) // for readdir_r QScopedPointer<QT_DIRENT, QScopedPointerPodDeleter> mt_file; +#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R) + // for _readdir_r + size_t direntSize; +#endif #endif int lastError; #endif diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp index 9ab186d..28f5e36 100644 --- a/src/corelib/io/qfilesystemiterator_unix.cpp +++ b/src/corelib/io/qfilesystemiterator_unix.cpp @@ -54,6 +54,9 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi : nativePath(entry.nativeFilePath()) , dir(0) , dirEntry(0) +#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R) + , direntSize(0) +#endif , lastError(0) { Q_UNUSED(filters) @@ -78,6 +81,15 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi Q_CHECK_PTR(p); mt_file.reset(p); +#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R) + direntSize = maxPathName; + + // Include extra stat information in the readdir() call (d_stat member of dirent_extra_stat). + // This is used in QFileSystemMetaData::fillFromDirEnt() to avoid extra stat() calls when iterating + // over directories + if (dircntl(dir, D_SETFLAG, D_FLAG_STAT) == -1) + lastError = errno; +#endif #endif } } @@ -93,7 +105,11 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa if (!dir) return false; -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) +#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R) + lastError = _readdir_r(dir, mt_file.data(), &dirEntry, direntSize); + if (lastError) + return false; +#elif defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) lastError = QT_READDIR_R(dir, mt_file.data(), &dirEntry); if (lastError) return false; |