[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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.