changeset 6732:b72dc46eb85c

OrthancPluginClearCurrentThreadName
author Alain Mazy <am@orthanc.team>
date Tue, 21 Apr 2026 15:56:02 +0200
parents d691dafe5ca8
children 73cb29fd7eb5
files NEWS OrthancFramework/Sources/HttpServer/HttpServer.cpp OrthancFramework/Sources/Logging.cpp OrthancServer/Plugins/Engine/OrthancPlugins.cpp OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h OrthancServer/Plugins/Samples/DelayedDeletion/Plugin.cpp
diffstat 6 files changed, 48 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Tue Apr 21 12:49:25 2026 +0200
+++ b/NEWS	Tue Apr 21 15:56:02 2026 +0200
@@ -30,6 +30,13 @@
 * Fix Orthanc::ImageAccessor that was broken in Orthanc Framework 1.12.11
 
 
+Plugin SDK
+----------
+
+* Added OrthancPluginClearCurrentThreadName() to avoid storing thousands of thread
+  names when dynamically creating/killing threads in a plugin.
+
+
 Version 1.12.11 (2026-04-14)
 ============================
 
--- a/OrthancFramework/Sources/HttpServer/HttpServer.cpp	Tue Apr 21 12:49:25 2026 +0200
+++ b/OrthancFramework/Sources/HttpServer/HttpServer.cpp	Tue Apr 21 15:56:02 2026 +0200
@@ -2469,6 +2469,7 @@
 
   void HttpServer::UpdateCurrentThreadName()
   {
+    // threads are created in CivetWeb -> assign them a name the first time they are used
     if (!Logging::HasCurrentThreadName())
     {
       boost::mutex::scoped_lock lock(threadCounterMutex_);
--- a/OrthancFramework/Sources/Logging.cpp	Tue Apr 21 12:49:25 2026 +0200
+++ b/OrthancFramework/Sources/Logging.cpp	Tue Apr 21 15:56:02 2026 +0200
@@ -504,6 +504,7 @@
     _OrthancPluginService_LogError = 3,
     _OrthancPluginService_SetCurrentThreadName = 44,
     _OrthancPluginService_LogMessage = 45,
+    _OrthancPluginService_ClearCurrentThreadName = 64,
     _OrthancPluginService_INTERNAL = 0x7fffffff
   } _OrthancPluginService;
 
@@ -570,6 +571,7 @@
 static OrthancPluginContext*                    pluginContext_ = NULL;    // this is != NULL only when running from a plugin
 static std::string                              pluginName_;              // this string can only be non-empty if running from a plugin
 static bool                                     hasOrthancAdvancedLogging_ = false;  // Whether the Orthanc runtime is >= 1.12.4
+static bool                                     hasClearThreadName_ = false;  // Whether the Orthanc runtime is >= 1.12.12
 static boost::recursive_mutex                   threadNamesMutex_;
 static std::map<boost::thread::id, std::string> threadNames_;
 static bool                                     enableThreadNames_ = true;
@@ -695,10 +697,18 @@
 
     void ClearCurrentThreadName()
     {
-      boost::thread::id threadId = boost::this_thread::get_id();
+      if (pluginContext_ == NULL)
+      {
+        boost::thread::id threadId = boost::this_thread::get_id();
 
-      boost::recursive_mutex::scoped_lock lock(threadNamesMutex_);
-      threadNames_.erase(threadId);
+        boost::recursive_mutex::scoped_lock lock(threadNamesMutex_);
+        threadNames_.erase(threadId);
+      }
+      else if (hasClearThreadName_) // only recent runtimes support it (from 1.12.12)
+      {
+        pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_ClearCurrentThreadName, NULL);
+      }
+
     }
 
     static std::string GetCurrentThreadName()
@@ -848,6 +858,7 @@
 
       // The value "hasOrthancAdvancedLogging_" is cached to avoid computing it on every logged message
       hasOrthancAdvancedLogging_ = Toolbox::IsVersionAbove(pluginContext_->orthancVersion, 1, 12, 4);
+      hasClearThreadName_ = Toolbox::IsVersionAbove(pluginContext_->orthancVersion, 1, 12, 12);
 
       EnableInfoLevel(true);  // allow the plugin to log at info level (but the Orthanc Core still decides of the level)
     }
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Tue Apr 21 12:49:25 2026 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Tue Apr 21 15:56:02 2026 +0200
@@ -6143,6 +6143,12 @@
         return true;
       }
 
+      case _OrthancPluginService_ClearCurrentThreadName:
+      {
+        Logging::ClearCurrentThreadName();
+        return true;
+      }
+
       case _OrthancPluginService_AdoptDicomInstance:
       {
         const _OrthancPluginAdoptDicomInstance& p = *reinterpret_cast<const _OrthancPluginAdoptDicomInstance*>(parameters);
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Apr 21 12:49:25 2026 +0200
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Apr 21 15:56:02 2026 +0200
@@ -528,6 +528,7 @@
     _OrthancPluginService_EmitAuditLog = 61,                        /* New in Orthanc 1.12.9 */
     _OrthancPluginService_ReserveQueueValue = 62,                   /* New in Orthanc 1.12.10 */
     _OrthancPluginService_AcknowledgeQueueValue = 63,               /* New in Orthanc 1.12.10 */
+    _OrthancPluginService_ClearCurrentThreadName = 64,              /* New in Orthanc 1.12.12 */
 
     /* Registration of callbacks */
     _OrthancPluginService_RegisterRestCallback = 1000,
@@ -11188,6 +11189,24 @@
     return context->InvokeService(context, _OrthancPluginService_RegisterStorageCommitmentScpCallback2, &params);
   }
 
+  /**
+   * @brief Clear the name of the current thread.
+   *
+   * This function releases the resources allocated to store the threa
+   * name.  This function must only be called from threads that the plugin 
+   * has created itself when the thread is reaching its end of life.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @return 0 if success, other value if error.
+   * @ingroup Toolbox
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.12")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginClearCurrentThreadName(
+    OrthancPluginContext*  context)
+  {
+    return context->InvokeService(context, _OrthancPluginService_ClearCurrentThreadName, NULL);
+  }
+
 #ifdef  __cplusplus
 }
 #endif
--- a/OrthancServer/Plugins/Samples/DelayedDeletion/Plugin.cpp	Tue Apr 21 12:49:25 2026 +0200
+++ b/OrthancServer/Plugins/Samples/DelayedDeletion/Plugin.cpp	Tue Apr 21 15:56:02 2026 +0200
@@ -188,7 +188,7 @@
 
 static void DeletionWorker()
 {
-  OrthancPluginSetCurrentThreadName(OrthancPlugins::GetGlobalContext(), "DELETION");
+  Orthanc::Logging::ScopedThreadNameSetter setter("DELETION");
 
   static const unsigned int GRANULARITY = 100;  // In milliseconds