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
parent
b206fba8b1
commit
391d2e37f3
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue