[graphics/digikam] core: Strip C++ namespace prefix from customized thread names
Gilles Caulier <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 741fa3d424dc5b7cb59d9eb58119063eccd7c27e by Gilles Caulier, on behalf of Andreas Winther.
Committed on 17/07/2026 at 04:33.
Pushed by cgilles into branch 'master'.
Strip C++ namespace prefix from customized thread names
Worker thread names taken from ActionJob class names since commit
9a7daeda8c carry a C++ namespace prefix. On Linux the kernel limits
thread names to 15 bytes, so the prefix eats most or all of the
usable length. Jobs implemented by plugins are hit hardest: their
namespaces alone (DigikamGenericTimeAdjustPlugin and similar) exceed
the limit, so all of their threads show up in a process viewer with
the same indistinguishable "DigikamGeneric…" name.
Strip the namespace prefix in
ActionThreadBase::setCurrentThreadName() on all platforms, so that
the significant part of the name survives the platform limits and a
thread carries the same name on every platform.
Extend actionjob_utest with a namespaced job class covering the
stripping, and document the behavior in the API docs.
M +9 -4 core/libs/threads/actionthreadbase.cpp
M +3 -0 core/libs/threads/actionthreadbase.h
M +40 -5 core/tests/multithreading/actionjob_utest.cpp
https://invent.kde.org/graphics/digikam/-/commit/741fa3d424dc5b7cb59d9eb58119063eccd7c27e
diff --git a/core/libs/threads/actionthreadbase.cpp b/core/libs/threads/actionthreadbase.cpp
index 6c6591da6d..18625ec492 100644
--- a/core/libs/threads/actionthreadbase.cpp
+++ b/core/libs/threads/actionthreadbase.cpp
@@ -264,22 +264,27 @@ void ActionThreadBase::run()
void ActionThreadBase::setCurrentThreadName(const QString& name)
{
+ // A name taken from a class name carries a C++ namespace prefix which
+ // eats most of the platform length limits listed in the API docs (15
+ // characters on Linux). Only the last, most significant part is applied.
+
+ const QString threadName = name.section(QLatin1String("::"), -1);
#if defined(Q_OS_LINUX)
- prctl(PR_SET_NAME, (unsigned long)name.toLatin1().constData(), 0, 0, 0);
+ prctl(PR_SET_NAME, (unsigned long)threadName.toLatin1().constData(), 0, 0, 0);
#elif defined(Q_OS_MACOS)
- pthread_setname_np(name.toLatin1().constData());
+ pthread_setname_np(threadName.toLatin1().constData());
#elif defined(Q_OS_WIN)
- SetThreadDescription(GetCurrentThread(), reinterpret_cast<const wchar_t *>(name.utf16()));
+ SetThreadDescription(GetCurrentThread(), reinterpret_cast<const wchar_t *>(threadName.utf16()));
#elif defined(Q_OS_NETBSD)
- pthread_setname_np(pthread_self(), "%s", (void*)name.toLatin1().constData());
+ pthread_setname_np(pthread_self(), "%s", (void*)threadName.toLatin1().constData());
#else
diff --git a/core/libs/threads/actionthreadbase.h b/core/libs/threads/actionthreadbase.h
index 76cf1c6f5a..eb77deebf3 100644
--- a/core/libs/threads/actionthreadbase.h
+++ b/core/libs/threads/actionthreadbase.h
@@ -81,6 +81,9 @@ public:
* Linux: 15 characters max (UTF8).
* macOS: 64 characters max (UTF8).
* Windows: 260 characters max (UTF16).
+ * A C++ namespace prefix in the name (as when the name comes from a class
+ * name) is stripped on all platforms, so that the significant part
+ * survives these limits.
*/
static void setCurrentThreadName(const QString& name);
diff --git a/core/tests/multithreading/actionjob_utest.cpp b/core/tests/multithreading/actionjob_utest.cpp
index e308ee9f59..abbb535db6 100644
--- a/core/tests/multithreading/actionjob_utest.cpp
+++ b/core/tests/multithreading/actionjob_utest.cpp
@@ -84,10 +84,9 @@ static QString currentThreadNameFromOS()
/**
* @brief Minimal ActionJob which records the thread name applied by
- * ActionJob::run(). The class name is at most 15 characters long, so
- * it survives the Linux kernel thread name limit untruncated.
+ * ActionJob::run().
*/
-class FallbackTestJob : public ActionJob
+class NameRecordingJob : public ActionJob
{
Q_OBJECT
@@ -103,6 +102,25 @@ public:
}
};
+/**
+ * @brief The class names below are at most 15 characters long, so they
+ * survive the Linux kernel thread name limit untruncated.
+ */
+class FallbackTestJob : public NameRecordingJob
+{
+ Q_OBJECT
+};
+
+namespace DigikamTests
+{
+
+class ScopedTestJob : public NameRecordingJob
+{
+ Q_OBJECT
+};
+
+} // namespace DigikamTests
+
// -------------------------------------------------------
class ActionJobTest : public QObject
@@ -113,13 +131,14 @@ private Q_SLOTS:
void testExplicitObjectNameIsApplied();
void testUnnamedJobFallsBackToClassName();
+ void testNamespacePrefixIsStrippedFromClassName();
private:
- QString runOnWorkerThread(FallbackTestJob& job);
+ QString runOnWorkerThread(NameRecordingJob& job);
};
-QString ActionJobTest::runOnWorkerThread(FallbackTestJob& job)
+QString ActionJobTest::runOnWorkerThread(NameRecordingJob& job)
{
QScopedPointer<QThread> thread(QThread::create([&job]()
{
@@ -172,6 +191,22 @@ void ActionJobTest::testUnnamedJobFallsBackToClassName()
QCOMPARE(runOnWorkerThread(job), QLatin1String("FallbackTestJob"));
}
+void ActionJobTest::testNamespacePrefixIsStrippedFromClassName()
+{
+#if !defined(Q_OS_LINUX) && !defined(Q_OS_MACOS) && !defined(Q_OS_NETBSD) && !defined(Q_OS_WIN)
+
+ QSKIP("Reading back the current thread name is not supported on this platform");
+
+#endif
+
+ DigikamTests::ScopedTestJob job;
+
+ QVERIFY(job.objectName().isEmpty());
+ QCOMPARE(QString::fromLatin1(job.metaObject()->className()),
+ QLatin1String("DigikamTests::ScopedTestJob"));
+ QCOMPARE(runOnWorkerThread(job), QLatin1String("ScopedTestJob"));
+}
+
// -------------------------------------------------------
QTEST_GUILESS_MAIN(ActionJobTest)