From 7f1f9e14afe5170faba0c19c0732f54bd7982184 Mon Sep 17 00:00:00 2001 From: Kai Koehne <kai.koehne@nokia.com> Date: Fri, 28 May 2010 13:45:53 +0200 Subject: [PATCH] Fix crashes when loading large .qmlproject's (Mac OS X) There is a hard limit on the number of file handles that can be open at one point per process on Mac OS X (e.g. it's 2560 on Mac OS X Snow Leopard Server, as shown by ulimit -a). Opening one or several .qmlproject's with a large number of directories to watch easily exceeds this. The results are crashes later on, e.g. when threads cannot be created any more. This patch implements a heuristic that the file system watcher used for .qmlproject files never uses more than half the number of available file handles. It also increases the number from rlim_cur to rlim_max - the old code in main.cpp failed, see last section in http://developer.apple.com/maac/library/documentation/Darwin/Reference/ManPages/man2/setrlimit.2.html for details. Reviewed-by: ckamm Task-number: QTCREATORBUG-1487 Task-number: QTCREATORBUG-1486 --- src/app/main.cpp | 3 +- .../fileformat/filesystemwatcher.cpp | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index af205c30fbd..efbbd311deb 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -173,7 +173,8 @@ int main(int argc, char **argv) // increase the number of file that can be opened in Qt Creator. struct rlimit rl; getrlimit(RLIMIT_NOFILE, &rl); - rl.rlim_cur = rl.rlim_max; + + rl.rlim_cur = qMin((rlim_t)OPEN_MAX, rl.rlim_max); setrlimit(RLIMIT_NOFILE, &rl); #endif diff --git a/src/plugins/qmlprojectmanager/fileformat/filesystemwatcher.cpp b/src/plugins/qmlprojectmanager/fileformat/filesystemwatcher.cpp index 1f898ff48f5..eb4b79f1a83 100644 --- a/src/plugins/qmlprojectmanager/fileformat/filesystemwatcher.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/filesystemwatcher.cpp @@ -72,6 +72,19 @@ void FileSystemWatcher::addFile(const QString &file) addFiles(QStringList(file)); } + +#ifdef Q_OS_MAC + +// Returns upper limit of file handles that can be opened by this process at once. Exceeding it will probably result in crashes! +static rlim_t getFileLimit() +{ + struct rlimit rl; + getrlimit(RLIMIT_NOFILE, &rl); + return rl.rlim_cur; +} + +#endif + void FileSystemWatcher::addFiles(const QStringList &files) { QStringList toAdd; @@ -84,6 +97,17 @@ void FileSystemWatcher::addFiles(const QStringList &files) qWarning() << "FileSystemWatcher: File" << file << "is already being watched"; continue; } + +#ifdef Q_OS_MAC + static rlim_t maxFileOpen = getFileLimit(); + // We're potentially watching a _lot_ of directories. This might crash qtcreator when we hit the upper limit. + // Heuristic is therefore: Don't use more than half of the file handles available in this watcher + if ((rlim_t)m_directories.size() + (rlim_t)m_files.size() > maxFileOpen / 2) { + qWarning() << "File" << file << "is not watched: Too many file handles are already open (max is" << maxFileOpen; + break; + } +#endif + m_files.append(file); const int count = ++m_fileCount[file]; @@ -149,6 +173,17 @@ void FileSystemWatcher::addDirectories(const QStringList &directories) qWarning() << "Directory" << directory << "is already being watched"; continue; } + +#ifdef Q_OS_MAC + static rlim_t maxFileOpen = getFileLimit(); + // We're potentially watching a _lot_ of directories. This might crash qtcreator when we hit the upper limit. + // Heuristic is therefore: Don't use more than half of the file handles available in this watcher + if ((rlim_t)m_directories.size() + (rlim_t)m_files.size() > maxFileOpen / 2) { + qWarning() << "Directory" << directory << "is not watched: Too many file handles are already open (max is" << maxFileOpen; + break; + } +#endif + m_directories.append(directory); const int count = ++m_directoryCount[directory]; -- GitLab