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 <giuseppe.dangelo@kdab.com>
Reviewed-by: Kevin Krammer <kevin.krammer@kdab.com>
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Reviewed-by: Rafael Roquetto <rafael.roquetto@kdab.com>
Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
bb10
Thomas McGuire 2012-09-26 17:57:14 +02:00 committed by The Qt Project
parent b206fba8b1
commit 391d2e37f3
3 changed files with 69 additions and 2 deletions

View File

@ -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<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)
// BSD4 includes Mac OS X
// ### This will clear all entry flags and knownFlagsMask

View File

@ -98,6 +98,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

View File

@ -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;