From 391d2e37f3b301097cd23fdaf99dc34ed6a114a5 Mon Sep 17 00:00:00 2001 From: Thomas McGuire Date: Wed, 26 Sep 2012 17:57:14 +0200 Subject: [PATCH] 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. Change-Id: Ib3a9271c3a6f81c1ea3c21d012c875c7e9bad2ad Reviewed-by: Giuseppe D'Angelo Reviewed-by: Kevin Krammer Reviewed-by: Sean Harmer Reviewed-by: Rafael Roquetto Reviewed-by: Stephen Kelly --- src/corelib/io/qfilesystemengine.cpp | 49 ++++++++++++++++++++++++++++- src/corelib/io/qfilesystemiterator_p.h | 4 +++ 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 74ceeb1..fe06210 100644 --- a/src/corelib/io/qfilesystemengine.cpp +++ b/src/corelib/io/qfilesystemengine.cpp @@ -224,6 +224,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 @@ -277,7 +290,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) +#if defined(Q_OS_QNX) + knownFlagsMask = 0; + entryFlags = 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(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) // 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 87395ec..a68615c 100644 --- a/src/corelib/io/qfilesystemiterator_p.h +++ b/src/corelib/io/qfilesystemiterator_p.h @@ -98,6 +98,10 @@ private: #if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) // for readdir_r QScopedPointer 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; -- 2.7.4