From 6b7bc8fef47c8f2503b9f1084ae57fe5703e4eeb Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Thu, 26 Mar 2026 12:28:23 +0100
Subject: [PATCH 01/37] Added new timer class for idle transport purging
* TAO/tao/Transport_Idle_Timer.cpp:
* TAO/tao/Transport_Idle_Timer.h:
Added.
* TAO/tao/Cache_Entries_T.inl:
* TAO/tao/Transport.cpp:
* TAO/tao/Transport.h:
* TAO/tao/Transport_Cache_Manager_T.h:
* TAO/tao/Transport_Cache_Manager_T.inl:
* TAO/tao/tao.mpc:
---
TAO/tao/Cache_Entries_T.inl | 6 +--
TAO/tao/Transport.cpp | 38 +++++++++++++++-
TAO/tao/Transport.h | 16 ++++---
TAO/tao/Transport_Cache_Manager_T.h | 3 ++
TAO/tao/Transport_Cache_Manager_T.inl | 11 +++++
TAO/tao/Transport_Idle_Timer.cpp | 37 ++++++++++++++++
TAO/tao/Transport_Idle_Timer.h | 64 +++++++++++++++++++++++++++
TAO/tao/tao.mpc | 2 +
8 files changed, 168 insertions(+), 9 deletions(-)
create mode 100644 TAO/tao/Transport_Idle_Timer.cpp
create mode 100644 TAO/tao/Transport_Idle_Timer.h
diff --git a/TAO/tao/Cache_Entries_T.inl b/TAO/tao/Cache_Entries_T.inl
index 411c7d0e0ffd3..1472f36a051f4 100644
--- a/TAO/tao/Cache_Entries_T.inl
+++ b/TAO/tao/Cache_Entries_T.inl
@@ -8,7 +8,7 @@ namespace TAO
{
template ACE_INLINE
Cache_IntId_T::Cache_IntId_T ()
- : transport_ (0),
+ : transport_ (nullptr),
recycle_state_ (ENTRY_UNKNOWN),
is_connected_ (false)
{
@@ -16,7 +16,7 @@ namespace TAO
template ACE_INLINE
Cache_IntId_T::Cache_IntId_T (const Cache_IntId_T &rhs)
- : transport_ (0),
+ : transport_ (nullptr),
recycle_state_ (ENTRY_UNKNOWN),
is_connected_ (false)
{
@@ -75,7 +75,7 @@ namespace TAO
{
// Yield ownership of the TAO_Transport object.
transport_type *val = this->transport_;
- this->transport_ = 0;
+ this->transport_ = nullptr;
return val;
}
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index 49683ddaef425..4421af69f6c57 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -127,8 +127,8 @@ TAO_Transport::TAO_Transport (CORBA::ULong tag,
, tail_ (nullptr)
, incoming_message_queue_ (orb_core)
, current_deadline_ (ACE_Time_Value::zero)
- , flush_timer_id_ (-1)
, transport_timer_ (this)
+ , transport_idle_timer_ (this)
, handler_lock_ (orb_core->resource_factory ()->create_cached_connection_lock ())
, id_ ((size_t) this)
, purging_order_ (0)
@@ -957,6 +957,42 @@ TAO_Transport::handle_timeout (const ACE_Time_Value & /* current_time */,
return 0;
}
+int
+TAO_Transport::handle_idle_timeout (const ACE_Time_Value & /* current_time */, const void */*act*/)
+{
+ if (TAO_debug_level > 6)
+ {
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_idle_timeout, ")
+ ACE_TEXT ("idle timer expired, closing transport\n"),
+ this->id ()));
+ }
+
+ // Confirm transport is still idle under the handler lock to
+ // prevent a race with find_idle_transport_i().
+ {
+ ACE_GUARD_RETURN (ACE_Lock, mon, *this->handler_lock_, 0);
+ if (!this->transport_cache_manager ().is_idle (this->cache_map_entry_))
+ {
+ if (TAO_debug_level > 0)
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_idle_timeout, ")
+ ACE_TEXT ("idle_timeout, transport is not idle, don't close it\n"),
+ this->id ()));
+
+ return 0; // Raced — transport is busy now; leave it open
+ }
+ }
+
+
+ // Purge from cache then close the underlying socket.
+ // close_connection() is safe to call from the reactor thread.
+ (void) this->purge_entry ();
+ (void) this->close_connection ();
+
+ return 0;
+}
+
TAO_Transport::Drain_Result
TAO_Transport::drain_queue (TAO::Transport::Drain_Constraints const & dc)
{
diff --git a/TAO/tao/Transport.h b/TAO/tao/Transport.h
index 4268a2767464f..2523c5d2b80c3 100644
--- a/TAO/tao/Transport.h
+++ b/TAO/tao/Transport.h
@@ -1,6 +1,3 @@
-// -*- C++ -*-
-
-//=============================================================================
/**
* @file Transport.h
*
@@ -9,7 +6,6 @@
*
* @author Fred Kuhns
*/
-//=============================================================================
#ifndef TAO_TRANSPORT_H
#define TAO_TRANSPORT_H
@@ -23,6 +19,7 @@
#endif /* ACE_LACKS_PRAGMA_ONCE */
#include "tao/Transport_Timer.h"
+#include "tao/Transport_Idle_Timer.h"
#include "tao/Incoming_Message_Queue.h"
#include "tao/Incoming_Message_Stack.h"
#include "tao/Message_Semantics.h"
@@ -853,6 +850,9 @@ class TAO_Export TAO_Transport
*/
int handle_timeout (const ACE_Time_Value ¤t_time, const void* act);
+ /// Timeout called when the idle timer expired for this transport
+ int handle_idle_timeout (const ACE_Time_Value ¤t_time, const void* act);
+
/// Accessor to recv_buffer_size_
size_t recv_buffer_size () const;
@@ -1120,11 +1120,17 @@ class TAO_Export TAO_Transport
ACE_Time_Value current_deadline_;
/// The timer ID
- long flush_timer_id_;
+ long flush_timer_id_ { -1 };
+
+ /// The idle timer ID
+ long idle_timer_id_ { -1 };
/// The adapter used to receive timeout callbacks from the Reactor
TAO_Transport_Timer transport_timer_;
+ /// The adapter used to receive idle timeout callbacks from the Reactor
+ TAO::Transport_Idle_Timer transport_idle_timer_;
+
/// Lock that insures that activities that *might* use handler-related
/// resources (such as a connection handler) get serialized.
/**
diff --git a/TAO/tao/Transport_Cache_Manager_T.h b/TAO/tao/Transport_Cache_Manager_T.h
index cfd2ba1662d69..6d80ecb7e2037 100644
--- a/TAO/tao/Transport_Cache_Manager_T.h
+++ b/TAO/tao/Transport_Cache_Manager_T.h
@@ -133,6 +133,9 @@ namespace TAO
/// Make the entry idle and ready for use.
int make_idle (HASH_MAP_ENTRY *&entry);
+ /// Check if the entry is idle
+ bool is_idle (HASH_MAP_ENTRY *&entry) const;
+
/// Modify the state setting on the provided entry.
void set_entry_state (HASH_MAP_ENTRY *&entry,
TAO::Cache_Entries_State state);
diff --git a/TAO/tao/Transport_Cache_Manager_T.inl b/TAO/tao/Transport_Cache_Manager_T.inl
index d992671e8a820..1198f98314cf9 100644
--- a/TAO/tao/Transport_Cache_Manager_T.inl
+++ b/TAO/tao/Transport_Cache_Manager_T.inl
@@ -87,6 +87,17 @@ namespace TAO
return this->make_idle_i (entry);
}
+ template
+ ACE_INLINE bool
+ Transport_Cache_Manager_T::is_idle (HASH_MAP_ENTRY *&entry) const
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Lock, guard, *this->cache_lock_, false));
+ if (entry == nullptr) // in case someone beat us to it (entry is reference to transport member)
+ return false;
+
+ return entry->item ().recycle_state () == ENTRY_IDLE_AND_PURGABLE;
+ }
+
template
ACE_INLINE typename Transport_Cache_Manager_T::Find_Result
Transport_Cache_Manager_T::find (transport_descriptor_type *prop,
diff --git a/TAO/tao/Transport_Idle_Timer.cpp b/TAO/tao/Transport_Idle_Timer.cpp
new file mode 100644
index 0000000000000..a7e4751f1d451
--- /dev/null
+++ b/TAO/tao/Transport_Idle_Timer.cpp
@@ -0,0 +1,37 @@
+#include "tao/Transport_Idle_Timer.h"
+#include "tao/Transport.h"
+#include "tao/ORB_Core.h"
+#include "tao/debug.h"
+#include "ace/Reactor.h"
+
+TAO_BEGIN_VERSIONED_NAMESPACE_DECL
+
+namespace TAO
+{
+ Transport_Idle_Timer::Transport_Idle_Timer (TAO_Transport *transport)
+ : transport_ (transport)
+ {
+ }
+
+ int
+ Transport_Idle_Timer::handle_timeout (const ACE_Time_Value ¤t_time, const void* act)
+ {
+ return this->transport_->handle_idle_timeout (current_time, act);
+ }
+
+ void
+ Transport_Idle_Timer::cancel ()
+ {
+ // if (this->timer_id_ != -1 && this->transport_)
+ // {
+ // ACE_Reactor *reactor = this->transport_->orb_core ()->reactor ();
+ // if (reactor)
+ // {
+ // reactor->cancel_timer (this->timer_id_);
+ // this->timer_id_ = -1;
+ // }
+ // }
+ }
+}
+
+TAO_END_VERSIONED_NAMESPACE_DECL
diff --git a/TAO/tao/Transport_Idle_Timer.h b/TAO/tao/Transport_Idle_Timer.h
new file mode 100644
index 0000000000000..6183e45d2fb50
--- /dev/null
+++ b/TAO/tao/Transport_Idle_Timer.h
@@ -0,0 +1,64 @@
+/**
+ * @file Transport_Idle_Timer.h
+ *
+ * Reactor timer that fires when a transport has been idle for the
+ * configured transport_idl_timeout period and triggers auto-close.
+ *
+ * @author Johnny Willemsen
+ */
+
+#ifndef TAO_TRANSPORT_IDLE_TIMER_H
+#define TAO_TRANSPORT_IDLE_TIMER_H
+
+#include /**/ "ace/pre.h"
+
+#include "ace/Event_Handler.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "tao/orbconf.h"
+
+TAO_BEGIN_VERSIONED_NAMESPACE_DECL
+
+class TAO_Transport;
+
+namespace TAO
+{
+ /**
+ * @class Transport_Idle_Timer
+ *
+ * @brief One-shot reactor timer that closes an idle transport.
+ *
+ * Created by TAO_Transport::schedule_idle_timer() when a transport
+ * enters the ENTRY_IDLE_AND_PURGABLE state. Cancelled if the
+ * transport is reacquired for a new request before the timer fires.
+ */
+ class Transport_Idle_Timer : public ACE_Event_Handler
+ {
+ public:
+ explicit Transport_Idle_Timer (TAO_Transport *transport);
+ ~Transport_Idle_Timer () override = default;
+
+ /// Reactor callback — close the transport if still idle.
+ int handle_timeout (const ACE_Time_Value ¤t_time,
+ const void *act = nullptr) override;
+
+ /// Cancel a pending timer (safe to call even if not armed).
+ void cancel ();
+
+ /// Record the timer ID returned by schedule_timer().
+ void timer_id (long id) { timer_id_ = id; }
+ long timer_id () const { return timer_id_; }
+
+ private:
+ // todo, var
+ TAO_Transport *transport_; ///< Non-owning pointer
+ long timer_id_ { -1 }; ///< -1 when not armed
+ };
+}
+
+TAO_END_VERSIONED_NAMESPACE_DECL
+
+#endif /* TAO_IDLE_TRANSPORT_TIMER_H */
diff --git a/TAO/tao/tao.mpc b/TAO/tao/tao.mpc
index 53f1b6a23f903..5ce2243e0380a 100644
--- a/TAO/tao/tao.mpc
+++ b/TAO/tao/tao.mpc
@@ -307,6 +307,7 @@ project(TAO) : acelib, install, tao_output, taodefaults, pidl, extra_core, taoid
Transport_Acceptor.cpp
Transport_Connector.cpp
Transport_Descriptor_Interface.cpp
+ Transport_Idle_Timer.cpp
Transport_Mux_Strategy.cpp
Transport_Queueing_Strategies.cpp
Transport_Selection_Guard.cpp
@@ -633,6 +634,7 @@ project(TAO) : acelib, install, tao_output, taodefaults, pidl, extra_core, taoid
Transport_Cache_Manager_T.h
Transport_Connector.h
Transport_Descriptor_Interface.h
+ Transport_Idle_Timer.cpp
Transport.h
Transport_Mux_Strategy.h
Transport_Queueing_Strategies.h
From c7bab8262dd27a138d6a12a2dc7aabd62284a91b Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Thu, 26 Mar 2026 12:31:39 +0100
Subject: [PATCH 02/37] Use TAO namespace
* TAO/tao/Transport.h:
* TAO/tao/Transport_Idle_Timer.h:
* TAO/tao/Transport_Timer.cpp:
* TAO/tao/Transport_Timer.h:
---
TAO/tao/Transport.h | 2 +-
TAO/tao/Transport_Idle_Timer.h | 3 +-
TAO/tao/Transport_Timer.cpp | 19 +++++++------
TAO/tao/Transport_Timer.h | 52 ++++++++++++++++------------------
4 files changed, 37 insertions(+), 39 deletions(-)
diff --git a/TAO/tao/Transport.h b/TAO/tao/Transport.h
index 2523c5d2b80c3..2ebc1e898fc00 100644
--- a/TAO/tao/Transport.h
+++ b/TAO/tao/Transport.h
@@ -1126,7 +1126,7 @@ class TAO_Export TAO_Transport
long idle_timer_id_ { -1 };
/// The adapter used to receive timeout callbacks from the Reactor
- TAO_Transport_Timer transport_timer_;
+ TAO::Transport_Timer transport_timer_;
/// The adapter used to receive idle timeout callbacks from the Reactor
TAO::Transport_Idle_Timer transport_idle_timer_;
diff --git a/TAO/tao/Transport_Idle_Timer.h b/TAO/tao/Transport_Idle_Timer.h
index 6183e45d2fb50..6f946cbafb81d 100644
--- a/TAO/tao/Transport_Idle_Timer.h
+++ b/TAO/tao/Transport_Idle_Timer.h
@@ -11,14 +11,13 @@
#define TAO_TRANSPORT_IDLE_TIMER_H
#include /**/ "ace/pre.h"
-
#include "ace/Event_Handler.h"
#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */
-#include "tao/orbconf.h"
+#include /**/ "tao/Versioned_Namespace.h"
TAO_BEGIN_VERSIONED_NAMESPACE_DECL
diff --git a/TAO/tao/Transport_Timer.cpp b/TAO/tao/Transport_Timer.cpp
index 081692f209b40..e58b11fc269c8 100644
--- a/TAO/tao/Transport_Timer.cpp
+++ b/TAO/tao/Transport_Timer.cpp
@@ -1,19 +1,20 @@
-// -*- C++ -*-
#include "tao/Transport_Timer.h"
#include "tao/Transport.h"
TAO_BEGIN_VERSIONED_NAMESPACE_DECL
-TAO_Transport_Timer::TAO_Transport_Timer (TAO_Transport *transport)
- : transport_ (transport)
+namespace TAO
{
-}
+ Transport_Timer::Transport_Timer (TAO_Transport *transport)
+ : transport_ (transport)
+ {
+ }
-int
-TAO_Transport_Timer::handle_timeout (const ACE_Time_Value ¤t_time,
- const void *act)
-{
- return this->transport_->handle_timeout (current_time, act);
+ int
+ Transport_Timer::handle_timeout (const ACE_Time_Value ¤t_time, const void *act)
+ {
+ return this->transport_->handle_timeout (current_time, act);
+ }
}
TAO_END_VERSIONED_NAMESPACE_DECL
diff --git a/TAO/tao/Transport_Timer.h b/TAO/tao/Transport_Timer.h
index 89babfd0de6c7..0ca68a8ef3c76 100644
--- a/TAO/tao/Transport_Timer.h
+++ b/TAO/tao/Transport_Timer.h
@@ -1,12 +1,8 @@
-// -*- C++ -*-
-
-//=============================================================================
/**
* @file Transport_Timer.h
*
* @author Carlos O'Ryan
*/
-//=============================================================================
#ifndef TAO_TRANSPORT_TIMER_H
#define TAO_TRANSPORT_TIMER_H
@@ -18,37 +14,39 @@
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */
-#include /**/ "tao/TAO_Export.h"
#include /**/ "tao/Versioned_Namespace.h"
TAO_BEGIN_VERSIONED_NAMESPACE_DECL
class TAO_Transport;
-/**
- * @class TAO_Transport_Timer
- *
- * @brief Allows TAO_Transport instances to receive timeout
- * notifications from the Reactor. In other words, implements
- * the Adapter Role, of the Adapter Pattern, where the Adaptee
- * is a TAO_Transport and the client is the Reactor.
- */
-class TAO_Transport_Timer : public ACE_Event_Handler
+namespace TAO
{
-public:
- /// Constructor
/**
- * @param transport The adaptee
- */
- explicit TAO_Transport_Timer (TAO_Transport *transport);
-
- /// Receive timeout events from the Reactor and forward them to the
- /// TAO_Transport
- int handle_timeout (const ACE_Time_Value ¤t_time, const void *act) override;
-private:
- /// The Adaptee
- TAO_Transport *transport_;
-};
+ * @class Transport_Timer
+ *
+ * @brief Allows TAO_Transport instances to receive timeout
+ * notifications from the Reactor. In other words, implements
+ * the Adapter Role, of the Adapter Pattern, where the Adaptee
+ * is a TAO_Transport and the client is the Reactor.
+ */
+ class Transport_Timer : public ACE_Event_Handler
+ {
+ public:
+ /// Constructor
+ /**
+ * @param transport The adaptee
+ */
+ explicit Transport_Timer (TAO_Transport *transport);
+
+ /// Receive timeout events from the Reactor and forward them to the
+ /// TAO_Transport
+ int handle_timeout (const ACE_Time_Value ¤t_time, const void *act) override;
+ private:
+ /// The Adaptee
+ TAO_Transport *transport_;
+ };
+}
TAO_END_VERSIONED_NAMESPACE_DECL
From e61960a6dd8246736e51ccda6b27a7b339896658 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Thu, 26 Mar 2026 12:54:05 +0100
Subject: [PATCH 03/37] Commandline flag
* TAO/tao/Transport_Cache_Manager_T.inl:
* TAO/tao/default_resource.cpp:
* TAO/tao/default_resource.h:
---
TAO/tao/Transport_Cache_Manager_T.inl | 1 +
TAO/tao/default_resource.cpp | 14 +++++++++++++-
TAO/tao/default_resource.h | 5 +++++
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/TAO/tao/Transport_Cache_Manager_T.inl b/TAO/tao/Transport_Cache_Manager_T.inl
index 1198f98314cf9..894d19fc3da00 100644
--- a/TAO/tao/Transport_Cache_Manager_T.inl
+++ b/TAO/tao/Transport_Cache_Manager_T.inl
@@ -95,6 +95,7 @@ namespace TAO
if (entry == nullptr) // in case someone beat us to it (entry is reference to transport member)
return false;
+ // @todo check if the state is idle and purgable, if so, then make the state so that it can't be used to make this atomic
return entry->item ().recycle_state () == ENTRY_IDLE_AND_PURGABLE;
}
diff --git a/TAO/tao/default_resource.cpp b/TAO/tao/default_resource.cpp
index 7cecdeb7be8bf..17c4b1a2d0d76 100644
--- a/TAO/tao/default_resource.cpp
+++ b/TAO/tao/default_resource.cpp
@@ -322,7 +322,6 @@ TAO_Default_Resource_Factory::init (int argc, ACE_TCHAR *argv[])
else
this->report_option_value_error (ACE_TEXT("-ORBConnectionCacheMax"), argv[curarg]);
}
-
else if (ACE_OS::strcasecmp (argv[curarg],
ACE_TEXT("-ORBConnectionCachePurgePercentage")) == 0)
{
@@ -484,6 +483,14 @@ TAO_Default_Resource_Factory::init (int argc, ACE_TCHAR *argv[])
ACE_TEXT ("Zero copy writes unsupported on this platform\n")));
#endif /* TAO_HAS_SENDFILE==1 */
}
+ else if (0 == ACE_OS::strcasecmp (argv[curarg], ACE_TEXT("-ORBTransportIdleTimeout")))
+ {
+ ++curarg;
+ if (curarg < argc)
+ this->transport_idle_timeout_ = ACE_OS::atoi (argv[curarg]);
+ else
+ this->report_option_value_error (ACE_TEXT("-ORBTransportIdleTimeout"), argv[curarg]);
+ }
else if (ACE_OS::strncmp (argv[curarg],
ACE_TEXT ("-ORB"),
4) == 0)
@@ -1217,6 +1224,11 @@ TAO_Default_Resource_Factory::drop_replies_during_shutdown () const
return this->drop_replies_;
}
+int TAO_Default_Resource_Factory::transport_idle_timeout () const
+{
+ return this->transport_idle_timeout_;
+}
+
// ****************************************************************
ACE_STATIC_SVC_DEFINE (TAO_Default_Resource_Factory,
diff --git a/TAO/tao/default_resource.h b/TAO/tao/default_resource.h
index 4f20cb03d58c5..5e4ece6025c92 100644
--- a/TAO/tao/default_resource.h
+++ b/TAO/tao/default_resource.h
@@ -184,6 +184,7 @@ class TAO_Export TAO_Default_Resource_Factory
CORBA::ULong max_message_size) const;
virtual void disable_factory ();
virtual bool drop_replies_during_shutdown () const;
+ virtual int transport_idle_timeout () const;
//@}
protected:
@@ -314,6 +315,10 @@ class TAO_Export TAO_Default_Resource_Factory
/// Flag to indicate whether replies should be dropped during ORB
/// shutdown.
bool drop_replies_;
+
+ /// Amount of seconds after which an idle transport will be closed
+ /// 0 means no closing of idle connections (default)
+ int transport_idle_timeout_ { 0 };
};
ACE_STATIC_SVC_DECLARE_EXPORT (TAO, TAO_Default_Resource_Factory)
From 4313626e44d42665e710d79eb9e276ee769f3d32 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Thu, 26 Mar 2026 13:04:41 +0100
Subject: [PATCH 04/37] Schedule timer on making idle
* TAO/tao/Resource_Factory.h:
* TAO/tao/Transport.cpp:
* TAO/tao/Transport.h:
---
TAO/tao/Resource_Factory.h | 2 ++
TAO/tao/Transport.cpp | 29 ++++++++++++++++++++++++++++-
TAO/tao/Transport.h | 6 ++----
3 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/TAO/tao/Resource_Factory.h b/TAO/tao/Resource_Factory.h
index 7e06b646e7df8..44df9ae369173 100644
--- a/TAO/tao/Resource_Factory.h
+++ b/TAO/tao/Resource_Factory.h
@@ -254,6 +254,8 @@ class TAO_Export TAO_Resource_Factory : public ACE_Service_Object
/// replies during shutdown.
virtual bool drop_replies_during_shutdown () const = 0;
+ virtual int transport_idle_timeout () const = 0;
+
protected:
/**
* Loads the default protocols. This method is used so that the
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index 4421af69f6c57..2ec9a15e92ebc 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -547,7 +547,12 @@ TAO_Transport::make_idle ()
this->id ()));
}
- return this->transport_cache_manager ().make_idle (this->cache_map_entry_);
+ int const result = this->transport_cache_manager ().make_idle (this->cache_map_entry_);
+ if (result == 0)
+ {
+ this->schedule_idle_timer ();
+ }
+ return result;
}
int
@@ -2910,4 +2915,26 @@ TAO_Transport::connection_closed_on_read () const
return connection_closed_on_read_;
}
+void
+TAO_Transport::schedule_idle_timer ()
+{
+ int const timeout_sec = this->orb_core_->resource_factory ()->transport_idle_timeout ();
+ if (timeout_sec >= 0)
+ {
+ ACE_Reactor *reactor = this->orb_core_->reactor ();
+ const ACE_Time_Value tv (static_cast (timeout_sec));
+ this->idle_timer_id_= reactor->schedule_timer (std::addressof(this->transport_idle_timer_), nullptr, tv);
+
+ if (TAO_debug_level > 0)
+ {
+ TAOLIB_ERROR ((LM_ERROR,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::schedule_idle_timer , ")
+ ACE_TEXT ("schedule for idle with timerid [%d] ")
+ ACE_TEXT ("in the reactor.\n"),
+ this->id (), this->idle_timer_id_));
+ }
+ }
+}
+
+
TAO_END_VERSIONED_NAMESPACE_DECL
diff --git a/TAO/tao/Transport.h b/TAO/tao/Transport.h
index 2ebc1e898fc00..79848540c6891 100644
--- a/TAO/tao/Transport.h
+++ b/TAO/tao/Transport.h
@@ -1058,10 +1058,8 @@ class TAO_Export TAO_Transport
*/
bool using_blocking_io_for_asynch_messages() const;
- /*
- * Specialization hook to add concrete private methods from
- * TAO's protocol implementation onto the base Transport class
- */
+ /// Helper method to schedule a timer when the transport is made idle
+ void schedule_idle_timer ();
protected:
/// IOP protocol tag.
From 9c8c4b3324c435bc3646e156f94056ae21c56613 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Thu, 26 Mar 2026 13:09:20 +0100
Subject: [PATCH 05/37] Add cancel timer
* TAO/tao/Transport.cpp:
* TAO/tao/Transport.h:
* TAO/tao/Transport_Idle_Timer.cpp:
* TAO/tao/Transport_Idle_Timer.h:
---
TAO/tao/Transport.cpp | 25 +++++++++++++++++++++++--
TAO/tao/Transport.h | 3 +++
TAO/tao/Transport_Idle_Timer.cpp | 14 --------------
TAO/tao/Transport_Idle_Timer.h | 8 --------
4 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index 2ec9a15e92ebc..c76b7c85b1286 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -2925,16 +2925,37 @@ TAO_Transport::schedule_idle_timer ()
const ACE_Time_Value tv (static_cast (timeout_sec));
this->idle_timer_id_= reactor->schedule_timer (std::addressof(this->transport_idle_timer_), nullptr, tv);
- if (TAO_debug_level > 0)
+ if (TAO_debug_level > 6)
{
TAOLIB_ERROR ((LM_ERROR,
ACE_TEXT ("TAO (%P|%t) - Transport[%d]::schedule_idle_timer , ")
- ACE_TEXT ("schedule for idle with timerid [%d] ")
+ ACE_TEXT ("schedule idle timer with id [%d] ")
ACE_TEXT ("in the reactor.\n"),
this->id (), this->idle_timer_id_));
}
}
}
+void
+TAO_Transport::cancel_idle_timer ()
+{
+ if (this->idle_timer_id_ != -1)
+ {
+ ACE_Reactor *reactor = this->orb_core ()->reactor ();
+ if (reactor)
+ {
+ if (TAO_debug_level > 6)
+ {
+ TAOLIB_ERROR ((LM_ERROR,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::cancel_idle_timer , ")
+ ACE_TEXT ("cancel idle timer with id [%d] ")
+ ACE_TEXT ("from the reactor.\n"),
+ this->id (), this->idle_timer_id_));
+ }
+ reactor->cancel_timer (this->idle_timer_id_);
+ this->idle_timer_id_ = -1;
+ }
+ }
+}
TAO_END_VERSIONED_NAMESPACE_DECL
diff --git a/TAO/tao/Transport.h b/TAO/tao/Transport.h
index 79848540c6891..a39588552b081 100644
--- a/TAO/tao/Transport.h
+++ b/TAO/tao/Transport.h
@@ -1061,6 +1061,9 @@ class TAO_Export TAO_Transport
/// Helper method to schedule a timer when the transport is made idle
void schedule_idle_timer ();
+ /// Helper method to cancel the timer when the transport is not idle anymore
+ void cancel_idle_timer ();
+
protected:
/// IOP protocol tag.
CORBA::ULong const tag_;
diff --git a/TAO/tao/Transport_Idle_Timer.cpp b/TAO/tao/Transport_Idle_Timer.cpp
index a7e4751f1d451..d55483700f91c 100644
--- a/TAO/tao/Transport_Idle_Timer.cpp
+++ b/TAO/tao/Transport_Idle_Timer.cpp
@@ -18,20 +18,6 @@ namespace TAO
{
return this->transport_->handle_idle_timeout (current_time, act);
}
-
- void
- Transport_Idle_Timer::cancel ()
- {
- // if (this->timer_id_ != -1 && this->transport_)
- // {
- // ACE_Reactor *reactor = this->transport_->orb_core ()->reactor ();
- // if (reactor)
- // {
- // reactor->cancel_timer (this->timer_id_);
- // this->timer_id_ = -1;
- // }
- // }
- }
}
TAO_END_VERSIONED_NAMESPACE_DECL
diff --git a/TAO/tao/Transport_Idle_Timer.h b/TAO/tao/Transport_Idle_Timer.h
index 6f946cbafb81d..21a27c401200d 100644
--- a/TAO/tao/Transport_Idle_Timer.h
+++ b/TAO/tao/Transport_Idle_Timer.h
@@ -44,17 +44,9 @@ namespace TAO
int handle_timeout (const ACE_Time_Value ¤t_time,
const void *act = nullptr) override;
- /// Cancel a pending timer (safe to call even if not armed).
- void cancel ();
-
- /// Record the timer ID returned by schedule_timer().
- void timer_id (long id) { timer_id_ = id; }
- long timer_id () const { return timer_id_; }
-
private:
// todo, var
TAO_Transport *transport_; ///< Non-owning pointer
- long timer_id_ { -1 }; ///< -1 when not armed
};
}
From cacbcdb44d518f4dd473812be34a9251431265ad Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Thu, 26 Mar 2026 13:20:37 +0100
Subject: [PATCH 06/37] Added cancel of idle timer on transport usage
* TAO/tao/Transport.cpp:
* TAO/tao/Transport.h:
* TAO/tao/Transport_Cache_Manager_T.cpp:
* TAO/tao/Transport_Connector.cpp:
---
TAO/tao/Transport.cpp | 7 ++++---
TAO/tao/Transport.h | 6 +++---
TAO/tao/Transport_Cache_Manager_T.cpp | 7 +++++--
TAO/tao/Transport_Connector.cpp | 3 +--
4 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index c76b7c85b1286..0f6ca01a8deca 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -325,6 +325,9 @@ void
TAO_Transport::close_connection ()
{
this->connection_handler_i ()->close_connection ();
+
+ // Cancel any pending time
+ this->cancel_idle_timer ();
}
int
@@ -2849,9 +2852,7 @@ TAO_Transport::post_open (size_t id)
true);
// update transport cache to make this entry available
- this->transport_cache_manager ().set_entry_state (
- this->cache_map_entry_,
- TAO::ENTRY_IDLE_AND_PURGABLE);
+ this->transport_cache_manager ().set_entry_state (this->cache_map_entry_, TAO::ENTRY_IDLE_AND_PURGABLE);
return true;
}
diff --git a/TAO/tao/Transport.h b/TAO/tao/Transport.h
index a39588552b081..bc32a6ef3fd8a 100644
--- a/TAO/tao/Transport.h
+++ b/TAO/tao/Transport.h
@@ -896,6 +896,9 @@ class TAO_Export TAO_Transport
/// Transport statistics
TAO::Transport::Stats* stats () const;
+ /// Helper method to cancel the timer when the transport is not idle anymore
+ void cancel_idle_timer ();
+
private:
/// Helper method that returns the Transport Cache Manager.
TAO::Transport_Cache_Manager &transport_cache_manager ();
@@ -1061,9 +1064,6 @@ class TAO_Export TAO_Transport
/// Helper method to schedule a timer when the transport is made idle
void schedule_idle_timer ();
- /// Helper method to cancel the timer when the transport is not idle anymore
- void cancel_idle_timer ();
-
protected:
/// IOP protocol tag.
CORBA::ULong const tag_;
diff --git a/TAO/tao/Transport_Cache_Manager_T.cpp b/TAO/tao/Transport_Cache_Manager_T.cpp
index 156e24adcf6ba..6d92c293ca7bd 100644
--- a/TAO/tao/Transport_Cache_Manager_T.cpp
+++ b/TAO/tao/Transport_Cache_Manager_T.cpp
@@ -227,9 +227,9 @@ namespace TAO
transport_type *&transport,
size_t &busy_count)
{
- if (prop == 0)
+ if (prop == nullptr)
{
- transport = 0;
+ transport = nullptr;
return CACHE_FOUND_NONE;
}
@@ -299,6 +299,9 @@ namespace TAO
found = CACHE_FOUND_AVAILABLE;
found_entry = entry;
entry->item ().recycle_state (ENTRY_BUSY);
+ // We found a transport we can use, so cancel its idle timer
+ // with the lock held
+ entry->item().transport ()->cancel_idle_timer ();
if (TAO_debug_level > 6)
{
diff --git a/TAO/tao/Transport_Connector.cpp b/TAO/tao/Transport_Connector.cpp
index 9d920a75c559d..f4b9aaeccf11d 100644
--- a/TAO/tao/Transport_Connector.cpp
+++ b/TAO/tao/Transport_Connector.cpp
@@ -705,8 +705,7 @@ TAO_Connector::connect (TAO::Profile_Transport_Resolver *r,
}
else // not making new connection
{
- (void) this->wait_for_transport (r, base_transport,
- timeout, true);
+ (void) this->wait_for_transport (r, base_transport, timeout, true);
base_transport->remove_reference ();
}
}
From 8798127d5570d03a122dfb6ec722035125ce5f24 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 27 Mar 2026 14:50:23 +0100
Subject: [PATCH 07/37] Add missing post include
* TAO/tao/Transport_Idle_Timer.h:
---
TAO/tao/Transport_Idle_Timer.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/TAO/tao/Transport_Idle_Timer.h b/TAO/tao/Transport_Idle_Timer.h
index 21a27c401200d..02ab714ee4e25 100644
--- a/TAO/tao/Transport_Idle_Timer.h
+++ b/TAO/tao/Transport_Idle_Timer.h
@@ -52,4 +52,6 @@ namespace TAO
TAO_END_VERSIONED_NAMESPACE_DECL
+#include /**/ "ace/post.h"
+
#endif /* TAO_IDLE_TRANSPORT_TIMER_H */
From c718855e6b5992f7b2ab5db17db41edc64bdae43 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 27 Mar 2026 14:53:51 +0100
Subject: [PATCH 08/37] Starter unit test
---
TAO/tests/Transport_Idle_Timeout/Echo_i.cpp | 63 ++++
TAO/tests/Transport_Idle_Timeout/Echo_i.h | 39 +++
.../Idle_Transport_Timeout.mpc | 32 ++
TAO/tests/Transport_Idle_Timeout/client.cpp | 329 ++++++++++++++++++
TAO/tests/Transport_Idle_Timeout/run_test.pl | 120 +++++++
TAO/tests/Transport_Idle_Timeout/server.cpp | 93 +++++
TAO/tests/Transport_Idle_Timeout/svc.conf | 8 +
.../Transport_Idle_Timeout/svc_disabled.conf | 8 +
TAO/tests/Transport_Idle_Timeout/test.idl | 24 ++
9 files changed, 716 insertions(+)
create mode 100644 TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
create mode 100644 TAO/tests/Transport_Idle_Timeout/Echo_i.h
create mode 100644 TAO/tests/Transport_Idle_Timeout/Idle_Transport_Timeout.mpc
create mode 100644 TAO/tests/Transport_Idle_Timeout/client.cpp
create mode 100644 TAO/tests/Transport_Idle_Timeout/run_test.pl
create mode 100644 TAO/tests/Transport_Idle_Timeout/server.cpp
create mode 100644 TAO/tests/Transport_Idle_Timeout/svc.conf
create mode 100644 TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
create mode 100644 TAO/tests/Transport_Idle_Timeout/test.idl
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
new file mode 100644
index 0000000000000..181c4ce9e8690
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
@@ -0,0 +1,63 @@
+#include "Echo_i.h"
+#include "tao/ORB_Core.h"
+#include "tao/Transport_Cache_Manager_T.h"
+#include "tao/debug.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_string.h"
+
+Echo_i::Echo_i (CORBA::ORB_ptr orb)
+ : orb_ (CORBA::ORB::_duplicate (orb))
+{
+}
+
+char *
+Echo_i::ping (const char *msg)
+{
+ if (TAO_debug_level > 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Echo_i::ping (%C)\n"), msg));
+ return CORBA::string_dup (msg);
+}
+
+CORBA::Long
+Echo_i::cache_size ()
+{
+ // Walk the transport cache of the server-side ORB and count entries
+ // that are in the ENTRY_IDLE_AND_PURGABLE state.
+ //
+ // TAO_Transport_Cache_Manager stores its map in orb_core->lane_resources()
+ // (or the global resource set for the default thread pool). The public
+ // API exposes current_size() on the underlying ACE_Hash_Map, which counts
+ // ALL entries (idle + busy + closed). To count only idle entries we call
+ // the transport cache's cache_idle_transport() helper; however the cleanest
+ // portable path for a test is to use the purge_entry / is_entry_idle APIs.
+ //
+ // For simplicity — and to avoid reaching into internal template
+ // instantiations — we use the documented public accessor
+ // TAO_ORB_Core::transport_cache() together with its current_size()
+ // method. The test compares before/after values: after one ping the
+ // count must be >= 1; after the idle timeout has fired it must be 0.
+ //
+ // Note: current_size() returns the total map size (idle + busy).
+ // Because the test serialises its calls, at the point cache_size() is
+ // invoked no request is in flight, so all entries are idle.
+
+ TAO_ORB_Core *core = orb_->orb_core ();
+
+ CORBA::Long n = static_cast (
+ core->lane_resources ().transport_cache ().current_size ());
+
+ if (TAO_debug_level > 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Echo_i::cache_size () -> %d\n"), (int)n));
+
+ return n;
+}
+
+void
+Echo_i::shutdown ()
+{
+ if (TAO_debug_level > 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Echo_i::shutdown ()\n")));
+ orb_->shutdown (false);
+}
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.h b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
new file mode 100644
index 0000000000000..0a639804d5d28
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
@@ -0,0 +1,39 @@
+// -*- C++ -*-
+// TAO/tests/Idle_Transport_Timeout/Echo_i.h
+
+#ifndef IDLE_TRANSPORT_TIMEOUT_ECHO_I_H
+#define IDLE_TRANSPORT_TIMEOUT_ECHO_I_H
+
+#include "testS.h"
+#include "tao/ORB_Core.h"
+#include "tao/Transport_Cache_Manager_T.h"
+
+/**
+ * @class Echo_i
+ *
+ * @brief Servant implementation for Test::Echo.
+ *
+ * Provides ping/cache_size/shutdown operations used by the
+ * Idle_Transport_Timeout regression test.
+ */
+class Echo_i : public virtual POA_Test::Echo
+{
+public:
+ explicit Echo_i (CORBA::ORB_ptr orb);
+
+ // Test::Echo operations
+ char *ping (const char *msg) override;
+
+ /// Return the number of transport-cache entries that are currently
+ /// in the ENTRY_IDLE_AND_PURGABLE state. The test uses this to
+ /// confirm that a transport has been created (cache_size > 0) and
+ /// later that it has been closed by the idle timer (cache_size == 0).
+ CORBA::Long cache_size () override;
+
+ void shutdown () override;
+
+private:
+ CORBA::ORB_var orb_;
+};
+
+#endif /* IDLE_TRANSPORT_TIMEOUT_ECHO_I_H */
diff --git a/TAO/tests/Transport_Idle_Timeout/Idle_Transport_Timeout.mpc b/TAO/tests/Transport_Idle_Timeout/Idle_Transport_Timeout.mpc
new file mode 100644
index 0000000000000..4a250549f88f2
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/Idle_Transport_Timeout.mpc
@@ -0,0 +1,32 @@
+project(*idl): taoidldefaults {
+ IDL_Files {
+ test.idl
+ }
+ custom_only = 1
+}
+
+project(*server): taoserver {
+ after += *idl
+ Source_Files {
+ server.cpp
+ Echo_i.cpp
+ testS.cpp
+ testC.cpp
+ }
+ Header_Files {
+ Echo_i.h
+ testS.h
+ testC.h
+ }
+}
+
+project(*client): taoclient {
+ after += *idl
+ Source_Files {
+ client.cpp
+ testC.cpp
+ }
+ Header_Files {
+ testC.h
+ }
+}
diff --git a/TAO/tests/Transport_Idle_Timeout/client.cpp b/TAO/tests/Transport_Idle_Timeout/client.cpp
new file mode 100644
index 0000000000000..709358a0fdb75
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/client.cpp
@@ -0,0 +1,329 @@
+// Regression-test client for the TAO idle-transport-timeout feature.
+//
+// Test scenarios (executed in order):
+//
+// TC-1 Basic idle close
+// Make one ping; verify server-side cache_size == 1; sleep past
+// the timeout; verify cache_size == 0 (transport closed by timer).
+//
+// TC-2 Reconnect after idle close
+// After TC-1, ping again; verify cache_size == 1 again (new
+// transport created transparently). Confirms TRANSIENT is not
+// raised by the reconnect path.
+//
+// TC-3 Timer cancellation on reuse
+// Ping rapidly N times in a tight loop; the transport is
+// continuously reacquired so the idle timer is cancelled and
+// rescheduled each cycle. After the loop, sleep just under the
+// timeout and verify cache_size == 1 (connection still alive).
+// Then sleep past the timeout and verify cache_size == 0.
+//
+// TC-4 Disabled timeout (opt-out)
+// A second ORB is initialised with -ORBIdleTransportTimeout 0.
+// After sleeping well past the default 60 s timeout (we use a
+// short test timeout of 3 s so the second ORB uses 0 = disabled),
+// cache_size still reflects the connection is open.
+// NOTE: This scenario requires a separate server run with
+// -ORBIdleTransportTimeout 0 in its svc.conf; run_test.pl
+// handles this. Within this binary TC-4 is a command-line flag.
+//
+// Usage:
+// client -k -t [-n ] [-d]
+//
+// -t The idle timeout configured on the *server* (default: 3).
+// The client sleeps for (timeout + 2) seconds to give the
+// reactor sufficient time to fire the timer.
+// -n Number of rapid-fire pings in TC-3 (default: 10).
+// -d Run TC-4 (disabled-timeout) scenario instead of TC-1..3.
+
+#include "testC.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Log_Msg.h"
+
+// ---------------------------------------------------------------------------
+// Helpers
+// ---------------------------------------------------------------------------
+
+/// Sleep for @a seconds, spinning on reactor events so that the server's
+/// reactor thread (which fires the idle timer) is not blocked.
+/// We cannot use ACE_OS::sleep() alone because in a single-process test
+/// harness the reactor runs in the same thread. For a two-process test
+/// the sleep is fine; for safety we drain reactor events anyway.
+static void
+sleep_with_reactor (CORBA::ORB_ptr orb, int seconds)
+{
+ ACE_Time_Value deadline =
+ ACE_OS::gettimeofday () + ACE_Time_Value (seconds);
+
+ while (ACE_OS::gettimeofday () < deadline)
+ {
+ ACE_Time_Value tv (0, 50000); // 50 ms slices
+ orb->perform_work (tv);
+ }
+}
+
+/// Verify an expected value and print PASS/FAIL. Returns false on failure.
+static bool
+check (const char *label, CORBA::Long got, CORBA::Long expected)
+{
+ if (got == expected)
+ {
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" [PASS] %C : cache_size = %d (expected %d)\n"),
+ label, (int)got, (int)expected));
+ return true;
+ }
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" [FAIL] %C : cache_size = %d (expected %d)\n"),
+ label, (int)got, (int)expected));
+ return false;
+}
+
+// ---------------------------------------------------------------------------
+// Argument parsing
+// ---------------------------------------------------------------------------
+
+static const char *ior = nullptr;
+static int timeout_sec = 3; // must match server svc.conf value
+static int loop_count = 10;
+static bool disabled_tc = false;
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("k:t:n:d"));
+ int c;
+ while ((c = get_opts ()) != -1)
+ switch (c)
+ {
+ case 'k': ior = get_opts.opt_arg (); break;
+ case 't': timeout_sec = ACE_OS::atoi (get_opts.opt_arg ()); break;
+ case 'n': loop_count = ACE_OS::atoi (get_opts.opt_arg ()); break;
+ case 'd': disabled_tc = true; break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Usage: client -k [-t ] [-n ] [-d]\n")),
+ -1);
+ }
+ if (ior == nullptr)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("client: -k is required\n")), -1);
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// TC-1 : Basic idle close
+// ---------------------------------------------------------------------------
+// Steps:
+// 1. Ping once -> transport created, server cache_size must be 1.
+// 2. Sleep (timeout + 2s) -> idle timer fires on the server.
+// 3. cache_size must be 0 -> transport closed by timer.
+// ---------------------------------------------------------------------------
+static bool
+tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
+{
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-1: Basic idle close ===\n")));
+ bool ok = true;
+
+ // --- Step 1: establish a transport ---
+ CORBA::String_var reply = echo->ping ("hello");
+
+ if (ACE_OS::strcmp (reply.in (), "hello") != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT (" [FAIL] TC-1 ping returned wrong value\n")));
+ return false;
+ }
+
+ CORBA::Long sz = echo->cache_size ();
+ ok &= check ("TC-1 after ping (expect 1)", sz, 1);
+
+ // --- Step 2: idle sleep ---
+ const int sleep_sec = timeout_sec + 2;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" sleeping %d s for idle timer to fire...\n"),
+ sleep_sec));
+ sleep_with_reactor (orb, sleep_sec);
+
+ // --- Step 3: cache must be empty now ---
+ sz = echo->cache_size ();
+ ok &= check ("TC-1 after idle timeout (expect 0)", sz, 0);
+
+ return ok;
+}
+
+// ---------------------------------------------------------------------------
+// TC-2 : Reconnect after idle close
+// ---------------------------------------------------------------------------
+// Steps:
+// 1. Ping (reconnects transparently after TC-1 closed the transport).
+// 2. cache_size must be 1 again.
+// ---------------------------------------------------------------------------
+static bool
+tc2_reconnect (CORBA::ORB_ptr /*orb*/, Test::Echo_ptr echo)
+{
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-2: Reconnect after idle close ===\n")));
+ bool ok = true;
+
+ // A new ping must succeed without TRANSIENT even though TC-1 caused the
+ // server to close the connection. TAO's reconnect logic handles this.
+ CORBA::String_var reply = echo->ping ("reconnect");
+
+ if (ACE_OS::strcmp (reply.in (), "reconnect") != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT (" [FAIL] TC-2 ping returned wrong value\n")));
+ return false;
+ }
+
+ CORBA::Long sz = echo->cache_size ();
+ ok &= check ("TC-2 after reconnect ping (expect 1)", sz, 1);
+
+ return ok;
+}
+
+// ---------------------------------------------------------------------------
+// TC-3 : Timer cancellation on continuous reuse
+// ---------------------------------------------------------------------------
+// Steps:
+// 1. Send N pings in rapid succession. Each one reacquires the transport
+// (BUSY), cancels the idle timer, then releases back to idle and
+// reschedules the timer. No close should occur mid-loop.
+// 2. Sleep (timeout - 1)s — still within the window, cache must be 1.
+// 3. Sleep another 3s — now past the timeout, cache must be 0.
+// ---------------------------------------------------------------------------
+static bool
+tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("\n=== TC-3: Timer cancellation on reuse (%d pings) ===\n"),
+ loop_count));
+ bool ok = true;
+
+ // Rapid-fire loop — transport reused each time
+ for (int i = 0; i < loop_count; ++i)
+ {
+ CORBA::String_var reply = echo->ping ("loop");
+ if (ACE_OS::strcmp (reply.in (), "loop") != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT (" [FAIL] TC-3 ping %d bad reply\n"), i));
+ ok = false;
+ }
+ }
+
+ // Immediately after the loop the transport returned to idle and the
+ // timer was (re)started. Cache must show 1 entry.
+ CORBA::Long sz = echo->cache_size ();
+ ok &= check ("TC-3 immediately after loop (expect 1)", sz, 1);
+
+ // Sleep to just before the expected timeout
+ const int pre_sleep = (timeout_sec > 1) ? timeout_sec - 1 : 1;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" sleeping %d s (pre-timeout)...\n"), pre_sleep));
+ sleep_with_reactor (orb, pre_sleep);
+
+ sz = echo->cache_size ();
+ ok &= check ("TC-3 before timeout (expect 1)", sz, 1);
+
+ // Sleep past the remainder of the timeout
+ const int post_sleep = 3;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" sleeping %d s (post-timeout)...\n"), post_sleep));
+ sleep_with_reactor (orb, post_sleep);
+
+ sz = echo->cache_size ();
+ ok &= check ("TC-3 after timeout (expect 0)", sz, 0);
+
+ return ok;
+}
+
+// ---------------------------------------------------------------------------
+// TC-4 : Disabled timeout (opt-out)
+// ---------------------------------------------------------------------------
+// The server is started with -ORBIdleTransportTimeout 0 for this scenario.
+// After sleeping well past the default timeout, the transport must still
+// be present (i.e. not closed).
+// ---------------------------------------------------------------------------
+static bool
+tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
+{
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-4: Disabled timeout ===\n")));
+ bool ok = true;
+
+ CORBA::String_var reply = echo->ping ("disabled");
+ if (ACE_OS::strcmp (reply.in (), "disabled") != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT (" [FAIL] TC-4 ping bad reply\n")));
+ return false;
+ }
+
+ CORBA::Long sz = echo->cache_size ();
+ ok &= check ("TC-4 after ping (expect 1)", sz, 1);
+
+ // With timeout disabled the connection must survive beyond the default 60 s.
+ // We use a short wall-clock sleep equal to (timeout_sec + 2) — when
+ // run_test.pl invokes TC-4 the server timeout is 0, so the timer never
+ // fires regardless.
+ const int sleep_sec = timeout_sec + 2;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" sleeping %d s (timeout should NOT fire)...\n"),
+ sleep_sec));
+ sleep_with_reactor (orb, sleep_sec);
+
+ sz = echo->cache_size ();
+ ok &= check ("TC-4 after sleep with timeout=0 (expect 1)", sz, 1);
+
+ return ok;
+}
+
+// ---------------------------------------------------------------------------
+// main
+// ---------------------------------------------------------------------------
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ try
+ {
+ CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);
+
+ if (parse_args (argc, argv) != 0)
+ return 1;
+
+ CORBA::Object_var obj = orb->string_to_object (ior);
+ Test::Echo_var echo = Test::Echo::_narrow (obj.in ());
+
+ if (CORBA::is_nil (echo.in ()))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Narrow to Test::Echo failed\n")), 1);
+
+ bool all_pass = true;
+
+ if (disabled_tc)
+ {
+ // TC-4 only — server was started without idle timeout
+ all_pass &= tc4_disabled_timeout (orb.in (), echo.in ());
+ }
+ else
+ {
+ // TC-1, TC-2, TC-3 in sequence
+ all_pass &= tc1_basic_idle_close (orb.in (), echo.in ());
+ all_pass &= tc2_reconnect (orb.in (), echo.in ());
+ all_pass &= tc3_timer_cancel_on_reuse (orb.in (), echo.in ());
+ }
+
+ // Shut down the server
+ echo->shutdown ();
+
+ orb->destroy ();
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("\n=== Overall result: %C ===\n"),
+ all_pass ? "PASS" : "FAIL"));
+ return all_pass ? 0 : 1;
+ }
+ catch (const CORBA::Exception &ex)
+ {
+ ex._tao_print_exception (ACE_TEXT ("client exception"));
+ return 1;
+ }
+}
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
new file mode 100644
index 0000000000000..28832cb6775d8
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/run_test.pl
@@ -0,0 +1,120 @@
+#!/usr/bin/perl
+# TAO/tests/Idle_Transport_Timeout/run_test.pl
+#
+# Test driver for the idle-transport-timeout regression test.
+# Follows the standard TAO test-script conventions used throughout
+# TAO/tests/ (PerlACE helpers, two-process server/client, IOR handshake).
+#
+# Scenarios driven:
+# 1. TC-1, TC-2, TC-3 — timeout enabled (3 s), normal close/reconnect/reuse
+# 2. TC-4 — timeout disabled (0), connection must persist
+
+use strict;
+use lib "$ENV{ACE_ROOT}/bin";
+use PerlACE::TestTarget;
+
+# ---------------------------------------------------------------------------
+# Helpers
+# ---------------------------------------------------------------------------
+
+my $ior_file = "test.ior";
+my $timeout_sec = 3; # must match svc.conf value
+my $status = 0;
+
+sub run_scenario {
+ my ($label, $svc_conf, $extra_client_args) = @_;
+
+ print "\n### $label ###\n";
+
+ my $server = PerlACE::TestTarget::create_target (1) || die "Cannot create server target";
+ my $client = PerlACE::TestTarget::create_target (2) || die "Cannot create client target";
+
+ my $server_ior = $server->LocalFile ($ior_file);
+ my $client_ior = $client->LocalFile ($ior_file);
+
+ $server->DeleteFile ($ior_file);
+ $client->DeleteFile ($ior_file);
+
+ my $SV = $server->CreateProcess (
+ "server",
+ "-ORBSvcConf $svc_conf -o $server_ior"
+ );
+
+ my $CL = $client->CreateProcess (
+ "client",
+ "-ORBSvcConf $svc_conf -k file://$client_ior -t $timeout_sec $extra_client_args"
+ );
+
+ # Start server
+ my $server_status = $SV->Spawn ();
+ if ($server_status != 0) {
+ print STDERR "ERROR: server Spawn returned $server_status\n";
+ return 1;
+ }
+
+ # Wait for IOR file to appear (up to 30 s)
+ if ($server->WaitForFileTimed ($ior_file,
+ $server->ProcessStartWaitInterval ()) == -1) {
+ print STDERR "ERROR: IOR file '$server_ior' not created\n";
+ $SV->Kill (); $SV->TimedWait (1);
+ return 1;
+ }
+
+ # Transfer IOR file to client (no-op on single-host runs)
+ if ($server->GetFile ($ior_file) == -1) {
+ print STDERR "ERROR: server GetFile '$ior_file' failed\n";
+ $SV->Kill (); $SV->TimedWait (1);
+ return 1;
+ }
+ if ($client->PutFile ($ior_file) == -1) {
+ print STDERR "ERROR: client PutFile '$ior_file' failed\n";
+ $SV->Kill (); $SV->TimedWait (1);
+ return 1;
+ }
+
+ # Run client — allow generous wall-clock budget:
+ # TC-1+TC-2+TC-3: ~3*(timeout+2) + 3 slack = ~20 s for timeout=3
+ # TC-4: timeout+2 + 3 slack = ~8 s
+ my $client_budget = ($extra_client_args =~ /-d/) ? 15 : 60;
+ my $client_status = $CL->SpawnWaitKill ($client->ProcessStartWaitInterval ()
+ + $client_budget);
+ if ($client_status != 0) {
+ print STDERR "ERROR: client returned $client_status\n";
+ $status = 1;
+ }
+
+ # Wait for server to exit (it calls orb->shutdown() on receiving shutdown())
+ my $server_exit = $SV->WaitKill ($server->ProcessStopWaitInterval ());
+ if ($server_exit != 0) {
+ print STDERR "ERROR: server returned $server_exit\n";
+ $status = 1;
+ }
+
+ $server->DeleteFile ($ior_file);
+ $client->DeleteFile ($ior_file);
+
+ return $status;
+}
+
+# ---------------------------------------------------------------------------
+# Scenario 1: TC-1, TC-2, TC-3 (timeout enabled)
+# ---------------------------------------------------------------------------
+run_scenario (
+ "TC-1/TC-2/TC-3: idle timeout enabled (${timeout_sec}s)",
+ "svc.conf",
+ ""
+);
+
+# ---------------------------------------------------------------------------
+# Scenario 2: TC-4 (timeout disabled)
+# ---------------------------------------------------------------------------
+run_scenario (
+ "TC-4: idle timeout disabled",
+ "svc_disabled.conf",
+ "-d"
+);
+
+# ---------------------------------------------------------------------------
+# Final result
+# ---------------------------------------------------------------------------
+exit $status;
diff --git a/TAO/tests/Transport_Idle_Timeout/server.cpp b/TAO/tests/Transport_Idle_Timeout/server.cpp
new file mode 100644
index 0000000000000..c770dbdec4f2c
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/server.cpp
@@ -0,0 +1,93 @@
+// Regression-test server for the idle-transport-timeout feature.
+//
+// Writes its IOR to a file so that run_test.pl (and the client) can
+// locate it. Accepts a configurable svc.conf via -ORBSvcConf so the
+// test driver can set -ORBIdleTransportTimeout to a small value.
+
+#include "Echo_i.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/Log_Msg.h"
+
+static const ACE_TCHAR *ior_output_file = ACE_TEXT ("test.ior");
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("o:"));
+ int c;
+ while ((c = get_opts ()) != -1)
+ switch (c)
+ {
+ case 'o':
+ ior_output_file = get_opts.opt_arg ();
+ break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Usage: server [-o ]\n")),
+ -1);
+ }
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ try
+ {
+ CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);
+
+ if (parse_args (argc, argv) != 0)
+ return 1;
+
+ CORBA::Object_var poa_object =
+ orb->resolve_initial_references ("RootPOA");
+
+ PortableServer::POA_var root_poa =
+ PortableServer::POA::_narrow (poa_object.in ());
+
+ if (CORBA::is_nil (root_poa.in ()))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Nil RootPOA\n")), 1);
+
+ PortableServer::POAManager_var mgr = root_poa->the_POAManager ();
+
+ Echo_i *echo_impl = nullptr;
+ ACE_NEW_RETURN (echo_impl, Echo_i (orb.in ()), 1);
+ PortableServer::ServantBase_var owner (echo_impl);
+
+ PortableServer::ObjectId_var oid =
+ root_poa->activate_object (echo_impl);
+
+ CORBA::Object_var obj = root_poa->id_to_reference (oid.in ());
+ Test::Echo_var echo = Test::Echo::_narrow (obj.in ());
+
+ CORBA::String_var ior = orb->object_to_string (echo.in ());
+
+ // Write IOR to file so the test driver and client can find it
+ FILE *f = ACE_OS::fopen (ior_output_file, ACE_TEXT ("w"));
+ if (f == nullptr)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Cannot open output file '%s'\n"),
+ ior_output_file), 1);
+ ACE_OS::fprintf (f, "%s", ior.in ());
+ ACE_OS::fclose (f);
+
+ mgr->activate ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) server: IOR written to '%s'\n"),
+ ior_output_file));
+
+ orb->run ();
+
+ root_poa->destroy (true, true);
+ orb->destroy ();
+ }
+ catch (const CORBA::Exception &ex)
+ {
+ ex._tao_print_exception (ACE_TEXT ("server exception"));
+ return 1;
+ }
+ return 0;
+}
diff --git a/TAO/tests/Transport_Idle_Timeout/svc.conf b/TAO/tests/Transport_Idle_Timeout/svc.conf
new file mode 100644
index 0000000000000..227e25275a069
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/svc.conf
@@ -0,0 +1,8 @@
+# TAO/tests/Idle_Transport_Timeout/svc.conf
+#
+# Used by server and client for TC-1, TC-2, TC-3.
+# Sets a short idle timeout (3 seconds) so the test completes quickly.
+# LRU purging strategy is kept at its default size so capacity-based
+# purging never fires during the test (we want only timer-based close).
+
+static Resource_Factory "-ORBConnectionPurgingStrategy lru -ORBConnectionCacheMax 200 -ORBIdleTransportTimeout 3"
diff --git a/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
new file mode 100644
index 0000000000000..b8d56a1d5860b
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
@@ -0,0 +1,8 @@
+# TAO/tests/Idle_Transport_Timeout/svc_disabled.conf
+#
+# Used by server and client for TC-4 (disabled idle timeout).
+# Setting -ORBIdleTransportTimeout 0 disables the feature entirely;
+# transports must persist even after the normal 60 s default would
+# have fired.
+
+static Resource_Factory "-ORBConnectionPurgingStrategy lru -ORBConnectionCacheMax 200 -ORBIdleTransportTimeout 0"
diff --git a/TAO/tests/Transport_Idle_Timeout/test.idl b/TAO/tests/Transport_Idle_Timeout/test.idl
new file mode 100644
index 0000000000000..c13574e39bcad
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/test.idl
@@ -0,0 +1,24 @@
+// -*- IDL -*-
+// TAO/tests/Idle_Transport_Timeout/test.idl
+//
+// Simple interface used by the idle-transport-timeout regression test.
+// The server exposes a single 'ping' operation so the client can
+// establish a real IIOP connection, then go silent and let the idle
+// timer fire.
+
+module Test
+{
+ interface Echo
+ {
+ /// Returns its argument unchanged. Used to force a real round-trip
+ /// so that a transport is created and placed in the cache.
+ string ping (in string msg);
+
+ /// Ask the server to print its current transport-cache size.
+ /// Returns the number of IDLE entries visible to the server ORB.
+ long cache_size ();
+
+ /// Orderly shutdown.
+ oneway void shutdown ();
+ };
+};
From fbc35c85da402f5bff6ef4557ba4ac38ed4b64a4 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 27 Mar 2026 15:06:04 +0100
Subject: [PATCH 09/37] Test extension
* TAO/tests/Transport_Idle_Timeout/Echo_i.cpp:
* TAO/tests/Transport_Idle_Timeout/client.cpp:
* TAO/tests/Transport_Idle_Timeout/run_test.pl:
* TAO/tests/Transport_Idle_Timeout/server.cpp:
* TAO/tests/Transport_Idle_Timeout/svc.conf:
* TAO/tests/Transport_Idle_Timeout/svc_disabled.conf:
---
TAO/tests/Transport_Idle_Timeout/Echo_i.cpp | 1 +
TAO/tests/Transport_Idle_Timeout/client.cpp | 7 ++++---
TAO/tests/Transport_Idle_Timeout/run_test.pl | 17 +++++++++++++----
TAO/tests/Transport_Idle_Timeout/server.cpp | 2 +-
TAO/tests/Transport_Idle_Timeout/svc.conf | 2 +-
.../Transport_Idle_Timeout/svc_disabled.conf | 7 +++----
6 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
index 181c4ce9e8690..e61e119666060 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
@@ -1,6 +1,7 @@
#include "Echo_i.h"
#include "tao/ORB_Core.h"
#include "tao/Transport_Cache_Manager_T.h"
+#include "tao/Thread_Lane_Resources.h"
#include "tao/debug.h"
#include "ace/Log_Msg.h"
#include "ace/OS_NS_string.h"
diff --git a/TAO/tests/Transport_Idle_Timeout/client.cpp b/TAO/tests/Transport_Idle_Timeout/client.cpp
index 709358a0fdb75..c157c8fe307ce 100644
--- a/TAO/tests/Transport_Idle_Timeout/client.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/client.cpp
@@ -19,12 +19,12 @@
// Then sleep past the timeout and verify cache_size == 0.
//
// TC-4 Disabled timeout (opt-out)
-// A second ORB is initialised with -ORBIdleTransportTimeout 0.
+// A second ORB is initialised with -ORBTransportIdleTimeout 0.
// After sleeping well past the default 60 s timeout (we use a
// short test timeout of 3 s so the second ORB uses 0 = disabled),
// cache_size still reflects the connection is open.
// NOTE: This scenario requires a separate server run with
-// -ORBIdleTransportTimeout 0 in its svc.conf; run_test.pl
+// -ORBTransportIdleTimeout 0 in its svc.conf; run_test.pl
// handles this. Within this binary TC-4 is a command-line flag.
//
// Usage:
@@ -40,6 +40,7 @@
#include "ace/Get_Opt.h"
#include "ace/OS_NS_unistd.h"
#include "ace/Log_Msg.h"
+#include "ace/OS_NS_sys_time.h"
// ---------------------------------------------------------------------------
// Helpers
@@ -239,7 +240,7 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// ---------------------------------------------------------------------------
// TC-4 : Disabled timeout (opt-out)
// ---------------------------------------------------------------------------
-// The server is started with -ORBIdleTransportTimeout 0 for this scenario.
+// The server is started with -ORBTransportIdleTimeout 0 for this scenario.
// After sleeping well past the default timeout, the transport must still
// be present (i.e. not closed).
// ---------------------------------------------------------------------------
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
index 28832cb6775d8..7b9ecd8ce0299 100644
--- a/TAO/tests/Transport_Idle_Timeout/run_test.pl
+++ b/TAO/tests/Transport_Idle_Timeout/run_test.pl
@@ -1,6 +1,5 @@
#!/usr/bin/perl
-# TAO/tests/Idle_Transport_Timeout/run_test.pl
-#
+
# Test driver for the idle-transport-timeout regression test.
# Follows the standard TAO test-script conventions used throughout
# TAO/tests/ (PerlACE helpers, two-process server/client, IOR handshake).
@@ -20,6 +19,16 @@
my $ior_file = "test.ior";
my $timeout_sec = 3; # must match svc.conf value
my $status = 0;
+my $debug_level = '0';
+my $cdebug_level = '0';
+foreach my $i (@ARGV) {
+ if ($i eq '-debug') {
+ $debug_level = '10';
+ }
+ if ($i eq '-cdebug') {
+ $cdebug_level = '10';
+ }
+}
sub run_scenario {
my ($label, $svc_conf, $extra_client_args) = @_;
@@ -37,12 +46,12 @@ sub run_scenario {
my $SV = $server->CreateProcess (
"server",
- "-ORBSvcConf $svc_conf -o $server_ior"
+ "-ORBdebuglevel $debug_level -ORBSvcConf $svc_conf -o $server_ior"
);
my $CL = $client->CreateProcess (
"client",
- "-ORBSvcConf $svc_conf -k file://$client_ior -t $timeout_sec $extra_client_args"
+ "-ORBdebuglevel $cdebug_level -ORBSvcConf $svc_conf -k file://$client_ior -t $timeout_sec $extra_client_args"
);
# Start server
diff --git a/TAO/tests/Transport_Idle_Timeout/server.cpp b/TAO/tests/Transport_Idle_Timeout/server.cpp
index c770dbdec4f2c..f2e10bb28c67d 100644
--- a/TAO/tests/Transport_Idle_Timeout/server.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/server.cpp
@@ -2,7 +2,7 @@
//
// Writes its IOR to a file so that run_test.pl (and the client) can
// locate it. Accepts a configurable svc.conf via -ORBSvcConf so the
-// test driver can set -ORBIdleTransportTimeout to a small value.
+// test driver can set -ORBTransportIdleTimeout to a small value.
#include "Echo_i.h"
#include "ace/Get_Opt.h"
diff --git a/TAO/tests/Transport_Idle_Timeout/svc.conf b/TAO/tests/Transport_Idle_Timeout/svc.conf
index 227e25275a069..18d39ddd0e9aa 100644
--- a/TAO/tests/Transport_Idle_Timeout/svc.conf
+++ b/TAO/tests/Transport_Idle_Timeout/svc.conf
@@ -5,4 +5,4 @@
# LRU purging strategy is kept at its default size so capacity-based
# purging never fires during the test (we want only timer-based close).
-static Resource_Factory "-ORBConnectionPurgingStrategy lru -ORBConnectionCacheMax 200 -ORBIdleTransportTimeout 3"
+static Resource_Factory "-ORBConnectionPurgingStrategy lru -ORBConnectionCacheMax 200 -ORBTransportIdleTimeout 3"
diff --git a/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
index b8d56a1d5860b..38104e31d8d43 100644
--- a/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
+++ b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
@@ -1,8 +1,7 @@
# TAO/tests/Idle_Transport_Timeout/svc_disabled.conf
#
# Used by server and client for TC-4 (disabled idle timeout).
-# Setting -ORBIdleTransportTimeout 0 disables the feature entirely;
-# transports must persist even after the normal 60 s default would
-# have fired.
+# Setting -ORBTransportIdleTimeout 0 disables the feature entirely;
+# transports must persist
-static Resource_Factory "-ORBConnectionPurgingStrategy lru -ORBConnectionCacheMax 200 -ORBIdleTransportTimeout 0"
+static Resource_Factory "-ORBConnectionPurgingStrategy lru -ORBConnectionCacheMax 200 -ORBTransportIdleTimeout 0"
From adbd880d3b3872f03d309710e182a09ba5421619 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 27 Mar 2026 15:52:49 +0100
Subject: [PATCH 10/37] Storing work in progress
* TAO/tao/Transport.cpp:
---
TAO/tao/Transport.cpp | 79 +++++++++++++++++++++++++------------------
1 file changed, 46 insertions(+), 33 deletions(-)
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index 0f6ca01a8deca..d00f263972b94 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -183,7 +183,7 @@ TAO_Transport::~TAO_Transport ()
{
if (TAO_debug_level > 9)
{
- TAOLIB_DEBUG ((LM_DEBUG, ACE_TEXT ("TAO (%P|%t) - Transport[%d]::~Transport\n"),
+ TAOLIB_DEBUG ((LM_DEBUG, ACE_TEXT ("TAO (%P|%t) - Transport[%d]::~Transport, start\n"),
this->id_));
}
@@ -217,6 +217,11 @@ TAO_Transport::~TAO_Transport ()
#if TAO_HAS_TRANSPORT_CURRENT == 1
delete this->stats_;
#endif /* TAO_HAS_TRANSPORT_CURRENT == 1 */
+ if (TAO_debug_level > 9)
+ {
+ TAOLIB_DEBUG ((LM_DEBUG, ACE_TEXT ("TAO (%P|%t) - Transport[%d]::~Transport, end\n"),
+ this->id_));
+ }
}
void
@@ -324,10 +329,17 @@ TAO_Transport::register_if_necessary ()
void
TAO_Transport::close_connection ()
{
- this->connection_handler_i ()->close_connection ();
+ if (TAO_debug_level > 4)
+ {
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::close_connection\n"),
+ this->id ()));
+ }
// Cancel any pending time
this->cancel_idle_timer ();
+
+ this->connection_handler_i ()->close_connection ();
}
int
@@ -378,8 +390,7 @@ TAO_Transport::register_handler ()
this->ws_->is_registered (true);
// Register the handler with the reactor
- return r->register_handler (this->event_handler_i (),
- ACE_Event_Handler::READ_MASK);
+ return r->register_handler (this->event_handler_i (), ACE_Event_Handler::READ_MASK);
}
int
@@ -860,7 +871,7 @@ TAO_Transport::schedule_output_i ()
ACE_Event_Handler * const eh = this->event_handler_i ();
ACE_Reactor * const reactor = eh->reactor ();
- if (reactor == nullptr)
+ if (!reactor)
{
if (TAO_debug_level > 1)
{
@@ -948,17 +959,17 @@ TAO_Transport::handle_timeout (const ACE_Time_Value & /* current_time */,
// pending.
this->reset_flush_timer ();
- TAO_Flushing_Strategy *flushing_strategy =
- this->orb_core ()->flushing_strategy ();
+ TAO_Flushing_Strategy *flushing_strategy = this->orb_core ()->flushing_strategy ();
int const result = flushing_strategy->schedule_output (this);
if (result == TAO_Flushing_Strategy::MUST_FLUSH)
{
typedef ACE_Reverse_Lock TAO_REVERSE_LOCK;
TAO_REVERSE_LOCK reverse (*this->handler_lock_);
ACE_GUARD_RETURN (TAO_REVERSE_LOCK, ace_mon, reverse, -1);
- if (flushing_strategy->flush_transport (this, nullptr) == -1) {
- return -1;
- }
+ if (flushing_strategy->flush_transport (this, nullptr) == -1)
+ {
+ return -1;
+ }
}
}
@@ -976,29 +987,32 @@ TAO_Transport::handle_idle_timeout (const ACE_Time_Value & /* current_time */, c
this->id ()));
}
- // Confirm transport is still idle under the handler lock to
- // prevent a race with find_idle_transport_i().
+ // Timer has expired, so setting the idle timer id back to -1
+ this->idle_timer_id_ = -1;
+ this->add_reference (); // hack
+
+ // Confirm transport is still idle under the handler lock to
+ // prevent a race with find_idle_transport_i().
+ {
+ ACE_GUARD_RETURN (ACE_Lock, mon, *this->handler_lock_, 0);
+ if (!this->transport_cache_manager ().is_idle (this->cache_map_entry_))
{
- ACE_GUARD_RETURN (ACE_Lock, mon, *this->handler_lock_, 0);
- if (!this->transport_cache_manager ().is_idle (this->cache_map_entry_))
- {
- if (TAO_debug_level > 0)
- TAOLIB_DEBUG ((LM_DEBUG,
- ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_idle_timeout, ")
- ACE_TEXT ("idle_timeout, transport is not idle, don't close it\n"),
- this->id ()));
+ if (TAO_debug_level > 0)
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_idle_timeout, ")
+ ACE_TEXT ("idle_timeout, transport is not idle, don't close it\n"),
+ this->id ()));
- return 0; // Raced — transport is busy now; leave it open
- }
+ return 0; // Raced — transport is busy now; leave it open
}
+ }
-
- // Purge from cache then close the underlying socket.
- // close_connection() is safe to call from the reactor thread.
- (void) this->purge_entry ();
- (void) this->close_connection ();
-
- return 0;
+ // Purge from cache then close the underlying socket.
+ // close_connection() is safe to call from the reactor thread.
+ (void) this->purge_entry ();
+ (void) this->close_connection ();
+ this->remove_reference (); // hack
+ return 0;
}
TAO_Transport::Drain_Result
@@ -2773,8 +2787,7 @@ TAO_Transport::pre_close ()
// of the is_connected_ flag, so that during cache lookups the cache
// manager doesn't need to be burdened by the lock in is_connected().
this->is_connected_ = false;
- this->transport_cache_manager ().mark_connected (this->cache_map_entry_,
- false);
+ this->transport_cache_manager ().mark_connected (this->cache_map_entry_, false);
this->purge_entry ();
{
ACE_MT (ACE_GUARD (ACE_Lock, guard, *this->handler_lock_));
@@ -2920,7 +2933,7 @@ void
TAO_Transport::schedule_idle_timer ()
{
int const timeout_sec = this->orb_core_->resource_factory ()->transport_idle_timeout ();
- if (timeout_sec >= 0)
+ if (timeout_sec > 0)
{
ACE_Reactor *reactor = this->orb_core_->reactor ();
const ACE_Time_Value tv (static_cast (timeout_sec));
@@ -2948,7 +2961,7 @@ TAO_Transport::cancel_idle_timer ()
if (TAO_debug_level > 6)
{
TAOLIB_ERROR ((LM_ERROR,
- ACE_TEXT ("TAO (%P|%t) - Transport[%d]::cancel_idle_timer , ")
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::cancel_idle_timer, ")
ACE_TEXT ("cancel idle timer with id [%d] ")
ACE_TEXT ("from the reactor.\n"),
this->id (), this->idle_timer_id_));
From 266e5b0121d9053e6385978cb317bc45419af03e Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Sat, 28 Mar 2026 10:46:52 +0100
Subject: [PATCH 11/37] Add new test
* TAO/bin/tao_orb_tests.lst:
---
TAO/bin/tao_orb_tests.lst | 1 +
1 file changed, 1 insertion(+)
diff --git a/TAO/bin/tao_orb_tests.lst b/TAO/bin/tao_orb_tests.lst
index cc91442dd809a..ef5528073cbf4 100644
--- a/TAO/bin/tao_orb_tests.lst
+++ b/TAO/bin/tao_orb_tests.lst
@@ -431,6 +431,7 @@ TAO/tests/TransportCurrent/Framework/run_test.pl -static: !DISABLE_TRANSPORT_CUR
TAO/tests/TransportCurrent/IIOP/run_test.pl -dynamic: !DISABLE_TRANSPORT_CURRENT !STATIC !CORBA_E_COMPACT !CORBA_E_MICRO !DISABLE_INTERCEPTORS !MINIMUM
TAO/tests/TransportCurrent/IIOP/run_test.pl -static: !DISABLE_TRANSPORT_CURRENT STATIC !CORBA_E_COMPACT !CORBA_E_MICRO !DISABLE_INTERCEPTORS !MINIMUM
TAO/tests/Transport_Cache_Manager/run_test.pl
+TAO/tests/Transport_Idle_Timeout/run_test.pl
TAO/tests/UNKNOWN_Exception/run_test.pl:
TAO/tests/Native_Exceptions/run_test.pl:
TAO/tests/Servant_To_Reference_Test/run_test.pl: !MINIMUM !CORBA_E_COMPACT !CORBA_E_MICRO !ST
From 30d5cb476e11d89da45b1ee6ac569ed313a15cc4 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Mon, 30 Mar 2026 14:46:46 +0200
Subject: [PATCH 12/37] Test improvements and cleanup
* TAO/tests/Transport_Idle_Timeout/Echo_i.cpp:
* TAO/tests/Transport_Idle_Timeout/Echo_i.h:
* TAO/tests/Transport_Idle_Timeout/client.cpp:
* TAO/tests/Transport_Idle_Timeout/test.idl:
---
TAO/tests/Transport_Idle_Timeout/Echo_i.cpp | 38 ---------------
TAO/tests/Transport_Idle_Timeout/Echo_i.h | 6 ---
TAO/tests/Transport_Idle_Timeout/client.cpp | 54 +++++++++++----------
TAO/tests/Transport_Idle_Timeout/test.idl | 4 --
4 files changed, 29 insertions(+), 73 deletions(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
index e61e119666060..80637e977d404 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
@@ -1,7 +1,4 @@
#include "Echo_i.h"
-#include "tao/ORB_Core.h"
-#include "tao/Transport_Cache_Manager_T.h"
-#include "tao/Thread_Lane_Resources.h"
#include "tao/debug.h"
#include "ace/Log_Msg.h"
#include "ace/OS_NS_string.h"
@@ -20,41 +17,6 @@ Echo_i::ping (const char *msg)
return CORBA::string_dup (msg);
}
-CORBA::Long
-Echo_i::cache_size ()
-{
- // Walk the transport cache of the server-side ORB and count entries
- // that are in the ENTRY_IDLE_AND_PURGABLE state.
- //
- // TAO_Transport_Cache_Manager stores its map in orb_core->lane_resources()
- // (or the global resource set for the default thread pool). The public
- // API exposes current_size() on the underlying ACE_Hash_Map, which counts
- // ALL entries (idle + busy + closed). To count only idle entries we call
- // the transport cache's cache_idle_transport() helper; however the cleanest
- // portable path for a test is to use the purge_entry / is_entry_idle APIs.
- //
- // For simplicity — and to avoid reaching into internal template
- // instantiations — we use the documented public accessor
- // TAO_ORB_Core::transport_cache() together with its current_size()
- // method. The test compares before/after values: after one ping the
- // count must be >= 1; after the idle timeout has fired it must be 0.
- //
- // Note: current_size() returns the total map size (idle + busy).
- // Because the test serialises its calls, at the point cache_size() is
- // invoked no request is in flight, so all entries are idle.
-
- TAO_ORB_Core *core = orb_->orb_core ();
-
- CORBA::Long n = static_cast (
- core->lane_resources ().transport_cache ().current_size ());
-
- if (TAO_debug_level > 0)
- ACE_DEBUG ((LM_DEBUG,
- ACE_TEXT ("Echo_i::cache_size () -> %d\n"), (int)n));
-
- return n;
-}
-
void
Echo_i::shutdown ()
{
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.h b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
index 0a639804d5d28..f96ce84428959 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.h
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
@@ -24,12 +24,6 @@ class Echo_i : public virtual POA_Test::Echo
// Test::Echo operations
char *ping (const char *msg) override;
- /// Return the number of transport-cache entries that are currently
- /// in the ENTRY_IDLE_AND_PURGABLE state. The test uses this to
- /// confirm that a transport has been created (cache_size > 0) and
- /// later that it has been closed by the idle timer (cache_size == 0).
- CORBA::Long cache_size () override;
-
void shutdown () override;
private:
diff --git a/TAO/tests/Transport_Idle_Timeout/client.cpp b/TAO/tests/Transport_Idle_Timeout/client.cpp
index c157c8fe307ce..28102d02b18ff 100644
--- a/TAO/tests/Transport_Idle_Timeout/client.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/client.cpp
@@ -41,6 +41,9 @@
#include "ace/OS_NS_unistd.h"
#include "ace/Log_Msg.h"
#include "ace/OS_NS_sys_time.h"
+#include "tao/ORB_Core.h"
+#include "tao/Transport_Cache_Manager_T.h"
+#include "tao/Thread_Lane_Resources.h"
// ---------------------------------------------------------------------------
// Helpers
@@ -66,21 +69,29 @@ sleep_with_reactor (CORBA::ORB_ptr orb, int seconds)
/// Verify an expected value and print PASS/FAIL. Returns false on failure.
static bool
-check (const char *label, CORBA::Long got, CORBA::Long expected)
+check (const char *label, size_t got, size_t expected)
{
if (got == expected)
{
ACE_DEBUG ((LM_INFO,
- ACE_TEXT (" [PASS] %C : cache_size = %d (expected %d)\n"),
- label, (int)got, (int)expected));
+ ACE_TEXT (" [PASS] %C : cache_size = %B (expected %B)\n"),
+ label, got, expected));
return true;
}
ACE_ERROR ((LM_ERROR,
- ACE_TEXT (" [FAIL] %C : cache_size = %d (expected %d)\n"),
- label, (int)got, (int)expected));
+ ACE_TEXT (" [FAIL] %C : cache_size = %B (expected %B)\n"),
+ label, got, expected));
return false;
}
+/// Retrieve the current size of the cache in the client
+size_t
+cache_size(CORBA::ORB_ptr orb)
+{
+ TAO_ORB_Core *core = orb->orb_core ();
+ return core->lane_resources ().transport_cache ().current_size ();
+}
+
// ---------------------------------------------------------------------------
// Argument parsing
// ---------------------------------------------------------------------------
@@ -136,8 +147,8 @@ tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
return false;
}
- CORBA::Long sz = echo->cache_size ();
- ok &= check ("TC-1 after ping (expect 1)", sz, 1);
+ reply = echo->ping ("hello");
+ ok &= check ("TC-1 after ping (expect 1)", cache_size(orb), 1);
// --- Step 2: idle sleep ---
const int sleep_sec = timeout_sec + 2;
@@ -147,8 +158,7 @@ tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
sleep_with_reactor (orb, sleep_sec);
// --- Step 3: cache must be empty now ---
- sz = echo->cache_size ();
- ok &= check ("TC-1 after idle timeout (expect 0)", sz, 0);
+ ok &= check ("TC-1 after idle timeout (expect 0)", cache_size(orb), 0);
return ok;
}
@@ -161,7 +171,7 @@ tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// 2. cache_size must be 1 again.
// ---------------------------------------------------------------------------
static bool
-tc2_reconnect (CORBA::ORB_ptr /*orb*/, Test::Echo_ptr echo)
+tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
{
ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-2: Reconnect after idle close ===\n")));
bool ok = true;
@@ -176,8 +186,7 @@ tc2_reconnect (CORBA::ORB_ptr /*orb*/, Test::Echo_ptr echo)
return false;
}
- CORBA::Long sz = echo->cache_size ();
- ok &= check ("TC-2 after reconnect ping (expect 1)", sz, 1);
+ ok &= check ("TC-2 after reconnect ping (expect 1)", cache_size(orb), 1);
return ok;
}
@@ -190,7 +199,7 @@ tc2_reconnect (CORBA::ORB_ptr /*orb*/, Test::Echo_ptr echo)
// (BUSY), cancels the idle timer, then releases back to idle and
// reschedules the timer. No close should occur mid-loop.
// 2. Sleep (timeout - 1)s — still within the window, cache must be 1.
-// 3. Sleep another 3s — now past the timeout, cache must be 0.
+// 3. Sleep another 4s — now past the timeout, cache must be 0.
// ---------------------------------------------------------------------------
static bool
tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
@@ -213,8 +222,7 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// Immediately after the loop the transport returned to idle and the
// timer was (re)started. Cache must show 1 entry.
- CORBA::Long sz = echo->cache_size ();
- ok &= check ("TC-3 immediately after loop (expect 1)", sz, 1);
+ ok &= check ("TC-3 immediately after loop (expect 1)", cache_size(orb), 1);
// Sleep to just before the expected timeout
const int pre_sleep = (timeout_sec > 1) ? timeout_sec - 1 : 1;
@@ -222,17 +230,15 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
ACE_TEXT (" sleeping %d s (pre-timeout)...\n"), pre_sleep));
sleep_with_reactor (orb, pre_sleep);
- sz = echo->cache_size ();
- ok &= check ("TC-3 before timeout (expect 1)", sz, 1);
+ ok &= check ("TC-3 before timeout (expect 1)", cache_size(orb), 1);
// Sleep past the remainder of the timeout
- const int post_sleep = 3;
+ const int post_sleep = 4;
ACE_DEBUG ((LM_INFO,
ACE_TEXT (" sleeping %d s (post-timeout)...\n"), post_sleep));
sleep_with_reactor (orb, post_sleep);
- sz = echo->cache_size ();
- ok &= check ("TC-3 after timeout (expect 0)", sz, 0);
+ ok &= check ("TC-3 after timeout (expect 0)", cache_size(orb), 0);
return ok;
}
@@ -257,10 +263,9 @@ tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
return false;
}
- CORBA::Long sz = echo->cache_size ();
- ok &= check ("TC-4 after ping (expect 1)", sz, 1);
+ ok &= check ("TC-4 after ping (expect 1)", cache_size(orb), 1);
- // With timeout disabled the connection must survive beyond the default 60 s.
+ // With timeout disabled the connection must never be closed.
// We use a short wall-clock sleep equal to (timeout_sec + 2) — when
// run_test.pl invokes TC-4 the server timeout is 0, so the timer never
// fires regardless.
@@ -270,8 +275,7 @@ tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
sleep_sec));
sleep_with_reactor (orb, sleep_sec);
- sz = echo->cache_size ();
- ok &= check ("TC-4 after sleep with timeout=0 (expect 1)", sz, 1);
+ ok &= check ("TC-4 after sleep with timeout=0 (expect 1)", cache_size(orb), 1);
return ok;
}
diff --git a/TAO/tests/Transport_Idle_Timeout/test.idl b/TAO/tests/Transport_Idle_Timeout/test.idl
index c13574e39bcad..e6a3429170ee3 100644
--- a/TAO/tests/Transport_Idle_Timeout/test.idl
+++ b/TAO/tests/Transport_Idle_Timeout/test.idl
@@ -14,10 +14,6 @@ module Test
/// so that a transport is created and placed in the cache.
string ping (in string msg);
- /// Ask the server to print its current transport-cache size.
- /// Returns the number of IDLE entries visible to the server ORB.
- long cache_size ();
-
/// Orderly shutdown.
oneway void shutdown ();
};
From d57b5ece5ff2d9ced3116b625015e0e69aa5048f Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Mon, 30 Mar 2026 15:44:37 +0200
Subject: [PATCH 13/37] Move add/remove ref to idle timer
* TAO/tao/Transport.cpp:
* TAO/tao/Transport_Idle_Timer.cpp:
* TAO/tests/Transport_Idle_Timeout/run_test.pl:
---
TAO/tao/Transport.cpp | 3 +--
TAO/tao/Transport_Idle_Timer.cpp | 10 +++++++++-
TAO/tests/Transport_Idle_Timeout/run_test.pl | 0
3 files changed, 10 insertions(+), 3 deletions(-)
mode change 100644 => 100755 TAO/tests/Transport_Idle_Timeout/run_test.pl
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index d00f263972b94..58531a6623701 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -989,7 +989,6 @@ TAO_Transport::handle_idle_timeout (const ACE_Time_Value & /* current_time */, c
// Timer has expired, so setting the idle timer id back to -1
this->idle_timer_id_ = -1;
- this->add_reference (); // hack
// Confirm transport is still idle under the handler lock to
// prevent a race with find_idle_transport_i().
@@ -1011,7 +1010,7 @@ TAO_Transport::handle_idle_timeout (const ACE_Time_Value & /* current_time */, c
// close_connection() is safe to call from the reactor thread.
(void) this->purge_entry ();
(void) this->close_connection ();
- this->remove_reference (); // hack
+
return 0;
}
diff --git a/TAO/tao/Transport_Idle_Timer.cpp b/TAO/tao/Transport_Idle_Timer.cpp
index d55483700f91c..0fafd882b45f6 100644
--- a/TAO/tao/Transport_Idle_Timer.cpp
+++ b/TAO/tao/Transport_Idle_Timer.cpp
@@ -16,7 +16,15 @@ namespace TAO
int
Transport_Idle_Timer::handle_timeout (const ACE_Time_Value ¤t_time, const void* act)
{
- return this->transport_->handle_idle_timeout (current_time, act);
+ // Hold a reference to the transport to prevent its destruction, because that would
+ // also destruct this idle timer object
+ this->transport_->add_reference ();
+
+ int const retval = this->transport_->handle_idle_timeout (current_time, act);
+
+ this->transport_->remove_reference ();
+
+ return retval;
}
}
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
old mode 100644
new mode 100755
From 7f66766479bf95295fdfc75634cffdfd1744e1ff Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Mon, 30 Mar 2026 15:49:02 +0200
Subject: [PATCH 14/37] Document new flag
* TAO/docs/Options.html:
---
TAO/docs/Options.html | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/TAO/docs/Options.html b/TAO/docs/Options.html
index 55d091eac2122..6c4db94b3a050 100644
--- a/TAO/docs/Options.html
+++ b/TAO/docs/Options.html
@@ -1388,6 +1388,12 @@
to your config.h file.
+
+ -ORBTransportIdleTimeout number |
+ Number of seconds after which idle connections are closed and purged from
+ the transport cache. By default idle connections are kept until they are
+ explicitly closed or purged because the transport cache is almost full. |
+
From 5e8ce3d6d9eb2eb027ae68ae83a162191cfe3cc4 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Mon, 30 Mar 2026 16:19:58 +0200
Subject: [PATCH 15/37] Docu changes
* TAO/tao/Transport_Idle_Timer.h:
---
TAO/tao/Transport_Idle_Timer.h | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/TAO/tao/Transport_Idle_Timer.h b/TAO/tao/Transport_Idle_Timer.h
index 02ab714ee4e25..b6ffbff174736 100644
--- a/TAO/tao/Transport_Idle_Timer.h
+++ b/TAO/tao/Transport_Idle_Timer.h
@@ -1,7 +1,7 @@
/**
* @file Transport_Idle_Timer.h
*
- * Reactor timer that fires when a transport has been idle for the
+ * Reactor timer that fires when a transport has been idle for the
* configured transport_idl_timeout period and triggers auto-close.
*
* @author Johnny Willemsen
@@ -44,9 +44,15 @@ namespace TAO
int handle_timeout (const ACE_Time_Value ¤t_time,
const void *act = nullptr) override;
+ Transport_Idle_Timer () = delete;
+ Transport_Idle_Timer (const Transport_Idle_Timer &) = delete;
+ Transport_Idle_Timer &operator= (const Transport_Idle_Timer &) = delete;
+ Transport_Idle_Timer (Transport_Idle_Timer &&) = delete;
+ Transport_Idle_Timer &operator= (Transport_Idle_Timer &&) = delete;
+
private:
- // todo, var
- TAO_Transport *transport_; ///< Non-owning pointer
+ /// Transport this idle timer works on
+ TAO_Transport *transport_;
};
}
@@ -54,4 +60,4 @@ TAO_END_VERSIONED_NAMESPACE_DECL
#include /**/ "ace/post.h"
-#endif /* TAO_IDLE_TRANSPORT_TIMER_H */
+#endif /* TAO_TRANSPORT_IDLE_TIMER_H */
From 5fafd7776f7d78f1d52d34b418eb57f86a154fd2 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Mon, 30 Mar 2026 17:09:11 +0200
Subject: [PATCH 16/37] Cleanup
* TAO/tests/Transport_Idle_Timeout/Echo_i.h:
* TAO/tests/Transport_Idle_Timeout/svc.conf:
* TAO/tests/Transport_Idle_Timeout/svc_disabled.conf:
* TAO/tests/Transport_Idle_Timeout/test.idl:
---
TAO/tests/Transport_Idle_Timeout/Echo_i.h | 3 ---
TAO/tests/Transport_Idle_Timeout/svc.conf | 2 --
TAO/tests/Transport_Idle_Timeout/svc_disabled.conf | 2 --
TAO/tests/Transport_Idle_Timeout/test.idl | 3 ---
4 files changed, 10 deletions(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.h b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
index f96ce84428959..884bb4dbcf2da 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.h
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
@@ -1,6 +1,3 @@
-// -*- C++ -*-
-// TAO/tests/Idle_Transport_Timeout/Echo_i.h
-
#ifndef IDLE_TRANSPORT_TIMEOUT_ECHO_I_H
#define IDLE_TRANSPORT_TIMEOUT_ECHO_I_H
diff --git a/TAO/tests/Transport_Idle_Timeout/svc.conf b/TAO/tests/Transport_Idle_Timeout/svc.conf
index 18d39ddd0e9aa..b94824e9a07f3 100644
--- a/TAO/tests/Transport_Idle_Timeout/svc.conf
+++ b/TAO/tests/Transport_Idle_Timeout/svc.conf
@@ -1,5 +1,3 @@
-# TAO/tests/Idle_Transport_Timeout/svc.conf
-#
# Used by server and client for TC-1, TC-2, TC-3.
# Sets a short idle timeout (3 seconds) so the test completes quickly.
# LRU purging strategy is kept at its default size so capacity-based
diff --git a/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
index 38104e31d8d43..ead3f93c9bf22 100644
--- a/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
+++ b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
@@ -1,5 +1,3 @@
-# TAO/tests/Idle_Transport_Timeout/svc_disabled.conf
-#
# Used by server and client for TC-4 (disabled idle timeout).
# Setting -ORBTransportIdleTimeout 0 disables the feature entirely;
# transports must persist
diff --git a/TAO/tests/Transport_Idle_Timeout/test.idl b/TAO/tests/Transport_Idle_Timeout/test.idl
index e6a3429170ee3..0bbd3a1473745 100644
--- a/TAO/tests/Transport_Idle_Timeout/test.idl
+++ b/TAO/tests/Transport_Idle_Timeout/test.idl
@@ -1,6 +1,3 @@
-// -*- IDL -*-
-// TAO/tests/Idle_Transport_Timeout/test.idl
-//
// Simple interface used by the idle-transport-timeout regression test.
// The server exposes a single 'ping' operation so the client can
// establish a real IIOP connection, then go silent and let the idle
From 00ff5077f3835d4cec2c0c096aa38021b15828a5 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Mon, 30 Mar 2026 17:10:01 +0200
Subject: [PATCH 17/37] fixed fguzz
* TAO/tao/Transport_Idle_Timer.h:
---
TAO/tao/Transport_Idle_Timer.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TAO/tao/Transport_Idle_Timer.h b/TAO/tao/Transport_Idle_Timer.h
index b6ffbff174736..097286616ef58 100644
--- a/TAO/tao/Transport_Idle_Timer.h
+++ b/TAO/tao/Transport_Idle_Timer.h
@@ -52,7 +52,7 @@ namespace TAO
private:
/// Transport this idle timer works on
- TAO_Transport *transport_;
+ TAO_Transport *transport_;
};
}
From b93d27461fc210fe33fbd8cc270723f8b652cc75 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Tue, 31 Mar 2026 10:15:38 +0200
Subject: [PATCH 18/37] Rework test for more features
* TAO/tests/Transport_Idle_Timeout/Echo_i.cpp:
* TAO/tests/Transport_Idle_Timeout/Echo_i.h:
* TAO/tests/Transport_Idle_Timeout/client.cpp:
* TAO/tests/Transport_Idle_Timeout/test.idl:
---
TAO/tests/Transport_Idle_Timeout/Echo_i.cpp | 7 ++--
TAO/tests/Transport_Idle_Timeout/Echo_i.h | 2 +-
TAO/tests/Transport_Idle_Timeout/client.cpp | 37 ++++-----------------
TAO/tests/Transport_Idle_Timeout/test.idl | 10 +++---
4 files changed, 17 insertions(+), 39 deletions(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
index 80637e977d404..7fd9a93a6e9d7 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
@@ -8,13 +8,12 @@ Echo_i::Echo_i (CORBA::ORB_ptr orb)
{
}
-char *
-Echo_i::ping (const char *msg)
+void
+Echo_i::ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected)
{
if (TAO_debug_level > 0)
ACE_DEBUG ((LM_DEBUG,
- ACE_TEXT ("Echo_i::ping (%C)\n"), msg));
- return CORBA::string_dup (msg);
+ ACE_TEXT ("Echo_i::ping, sleep time (%d), cache size expected (%d)\n"), sleep_time, cache_size_expected));
}
void
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.h b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
index 884bb4dbcf2da..7e76d1272bf10 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.h
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
@@ -19,7 +19,7 @@ class Echo_i : public virtual POA_Test::Echo
explicit Echo_i (CORBA::ORB_ptr orb);
// Test::Echo operations
- char *ping (const char *msg) override;
+ void ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected) override;
void shutdown () override;
diff --git a/TAO/tests/Transport_Idle_Timeout/client.cpp b/TAO/tests/Transport_Idle_Timeout/client.cpp
index 28102d02b18ff..e3d9c46b122cc 100644
--- a/TAO/tests/Transport_Idle_Timeout/client.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/client.cpp
@@ -139,19 +139,12 @@ tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
bool ok = true;
// --- Step 1: establish a transport ---
- CORBA::String_var reply = echo->ping ("hello");
+ echo->ping (0, 1);
- if (ACE_OS::strcmp (reply.in (), "hello") != 0)
- {
- ACE_ERROR ((LM_ERROR, ACE_TEXT (" [FAIL] TC-1 ping returned wrong value\n")));
- return false;
- }
-
- reply = echo->ping ("hello");
ok &= check ("TC-1 after ping (expect 1)", cache_size(orb), 1);
// --- Step 2: idle sleep ---
- const int sleep_sec = timeout_sec + 2;
+ int const sleep_sec = timeout_sec + 2;
ACE_DEBUG ((LM_INFO,
ACE_TEXT (" sleeping %d s for idle timer to fire...\n"),
sleep_sec));
@@ -178,13 +171,7 @@ tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// A new ping must succeed without TRANSIENT even though TC-1 caused the
// server to close the connection. TAO's reconnect logic handles this.
- CORBA::String_var reply = echo->ping ("reconnect");
-
- if (ACE_OS::strcmp (reply.in (), "reconnect") != 0)
- {
- ACE_ERROR ((LM_ERROR, ACE_TEXT (" [FAIL] TC-2 ping returned wrong value\n")));
- return false;
- }
+ echo->ping (0, 1);
ok &= check ("TC-2 after reconnect ping (expect 1)", cache_size(orb), 1);
@@ -212,12 +199,7 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// Rapid-fire loop — transport reused each time
for (int i = 0; i < loop_count; ++i)
{
- CORBA::String_var reply = echo->ping ("loop");
- if (ACE_OS::strcmp (reply.in (), "loop") != 0)
- {
- ACE_ERROR ((LM_ERROR, ACE_TEXT (" [FAIL] TC-3 ping %d bad reply\n"), i));
- ok = false;
- }
+ echo->ping (0, 1);
}
// Immediately after the loop the transport returned to idle and the
@@ -225,7 +207,7 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
ok &= check ("TC-3 immediately after loop (expect 1)", cache_size(orb), 1);
// Sleep to just before the expected timeout
- const int pre_sleep = (timeout_sec > 1) ? timeout_sec - 1 : 1;
+ int const pre_sleep = (timeout_sec > 1) ? timeout_sec - 1 : 1;
ACE_DEBUG ((LM_INFO,
ACE_TEXT (" sleeping %d s (pre-timeout)...\n"), pre_sleep));
sleep_with_reactor (orb, pre_sleep);
@@ -233,7 +215,7 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
ok &= check ("TC-3 before timeout (expect 1)", cache_size(orb), 1);
// Sleep past the remainder of the timeout
- const int post_sleep = 4;
+ int constexpr post_sleep = 4;
ACE_DEBUG ((LM_INFO,
ACE_TEXT (" sleeping %d s (post-timeout)...\n"), post_sleep));
sleep_with_reactor (orb, post_sleep);
@@ -256,12 +238,7 @@ tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-4: Disabled timeout ===\n")));
bool ok = true;
- CORBA::String_var reply = echo->ping ("disabled");
- if (ACE_OS::strcmp (reply.in (), "disabled") != 0)
- {
- ACE_ERROR ((LM_ERROR, ACE_TEXT (" [FAIL] TC-4 ping bad reply\n")));
- return false;
- }
+ echo->ping (0, 1);
ok &= check ("TC-4 after ping (expect 1)", cache_size(orb), 1);
diff --git a/TAO/tests/Transport_Idle_Timeout/test.idl b/TAO/tests/Transport_Idle_Timeout/test.idl
index 0bbd3a1473745..4f4dbf4bfd97a 100644
--- a/TAO/tests/Transport_Idle_Timeout/test.idl
+++ b/TAO/tests/Transport_Idle_Timeout/test.idl
@@ -1,4 +1,4 @@
-// Simple interface used by the idle-transport-timeout regression test.
+// Simple interface used by the transport idle timeout regression test.
// The server exposes a single 'ping' operation so the client can
// establish a real IIOP connection, then go silent and let the idle
// timer fire.
@@ -7,9 +7,11 @@ module Test
{
interface Echo
{
- /// Returns its argument unchanged. Used to force a real round-trip
- /// so that a transport is created and placed in the cache.
- string ping (in string msg);
+ /// Ping the server, sleeps the number of seconds as passed with the call.
+ /// Sleeping means running the reactor to make sure idle connections are purged
+ /// Pass in the cache size we expect just before returning the call on the server
+ /// side
+ void ping (in long sleep_time, in long cache_size_expected);
/// Orderly shutdown.
oneway void shutdown ();
From 2b8198cf3d2689fe8943d533c94243186736bf0a Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Tue, 31 Mar 2026 10:39:27 +0200
Subject: [PATCH 19/37] Test infrastructure extensions
* TAO/tests/Transport_Idle_Timeout/Echo_i.cpp:
* TAO/tests/Transport_Idle_Timeout/Echo_i.h:
* TAO/tests/Transport_Idle_Timeout/client.cpp:
* TAO/tests/Transport_Idle_Timeout/test.idl:
---
TAO/tests/Transport_Idle_Timeout/Echo_i.cpp | 51 ++++++++++++++++++++-
TAO/tests/Transport_Idle_Timeout/Echo_i.h | 2 +-
TAO/tests/Transport_Idle_Timeout/client.cpp | 12 ++---
TAO/tests/Transport_Idle_Timeout/test.idl | 2 +-
4 files changed, 58 insertions(+), 9 deletions(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
index 7fd9a93a6e9d7..1b9d25a768342 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
@@ -2,18 +2,67 @@
#include "tao/debug.h"
#include "ace/Log_Msg.h"
#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_sys_time.h"
+#include "tao/ORB_Core.h"
+#include "tao/Transport_Cache_Manager_T.h"
+#include "tao/Thread_Lane_Resources.h"
+
+/// Sleep for @a seconds, spinning on reactor events so that the server's
+/// reactor thread (which fires the idle timer) is not blocked.
+/// We cannot use ACE_OS::sleep() alone because in a single-process test
+/// harness the reactor runs in the same thread. For a two-process test
+/// the sleep is fine; for safety we drain reactor events anyway.
+void
+sleep_with_reactor (CORBA::ORB_ptr orb, int seconds)
+{
+ ACE_Time_Value deadline =
+ ACE_OS::gettimeofday () + ACE_Time_Value (seconds);
+
+ while (ACE_OS::gettimeofday () < deadline)
+ {
+ ACE_Time_Value tv (0, 50000); // 50 ms slices
+ orb->perform_work (tv);
+ }
+}
+
+size_t
+cache_size(CORBA::ORB_ptr orb)
+{
+ TAO_ORB_Core *core = orb->orb_core ();
+ return core->lane_resources ().transport_cache ().current_size ();
+}
+
+bool
+check (const char *label, size_t got, size_t expected)
+{
+ if (got == expected)
+ {
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" [PASS] %C : cache_size = %B (expected %B)\n"),
+ label, got, expected));
+ return true;
+ }
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" [FAIL] %C : cache_size = %B (expected %B)\n"),
+ label, got, expected));
+ return false;
+}
Echo_i::Echo_i (CORBA::ORB_ptr orb)
: orb_ (CORBA::ORB::_duplicate (orb))
{
}
-void
+bool
Echo_i::ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected)
{
if (TAO_debug_level > 0)
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("Echo_i::ping, sleep time (%d), cache size expected (%d)\n"), sleep_time, cache_size_expected));
+
+ sleep_with_reactor (this->orb_, sleep_time);
+
+ return check ("ping", cache_size(this->orb_), cache_size_expected);
}
void
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.h b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
index 7e76d1272bf10..148d44eb27c5c 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.h
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
@@ -19,7 +19,7 @@ class Echo_i : public virtual POA_Test::Echo
explicit Echo_i (CORBA::ORB_ptr orb);
// Test::Echo operations
- void ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected) override;
+ bool ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected) override;
void shutdown () override;
diff --git a/TAO/tests/Transport_Idle_Timeout/client.cpp b/TAO/tests/Transport_Idle_Timeout/client.cpp
index e3d9c46b122cc..d32ea99cc8965 100644
--- a/TAO/tests/Transport_Idle_Timeout/client.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/client.cpp
@@ -54,7 +54,7 @@
/// We cannot use ACE_OS::sleep() alone because in a single-process test
/// harness the reactor runs in the same thread. For a two-process test
/// the sleep is fine; for safety we drain reactor events anyway.
-static void
+void
sleep_with_reactor (CORBA::ORB_ptr orb, int seconds)
{
ACE_Time_Value deadline =
@@ -68,7 +68,7 @@ sleep_with_reactor (CORBA::ORB_ptr orb, int seconds)
}
/// Verify an expected value and print PASS/FAIL. Returns false on failure.
-static bool
+bool
check (const char *label, size_t got, size_t expected)
{
if (got == expected)
@@ -139,7 +139,7 @@ tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
bool ok = true;
// --- Step 1: establish a transport ---
- echo->ping (0, 1);
+ ok &= echo->ping (0, 1);
ok &= check ("TC-1 after ping (expect 1)", cache_size(orb), 1);
@@ -171,7 +171,7 @@ tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// A new ping must succeed without TRANSIENT even though TC-1 caused the
// server to close the connection. TAO's reconnect logic handles this.
- echo->ping (0, 1);
+ ok &= echo->ping (0, 1);
ok &= check ("TC-2 after reconnect ping (expect 1)", cache_size(orb), 1);
@@ -199,7 +199,7 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// Rapid-fire loop — transport reused each time
for (int i = 0; i < loop_count; ++i)
{
- echo->ping (0, 1);
+ ok &= echo->ping (0, 1);
}
// Immediately after the loop the transport returned to idle and the
@@ -238,7 +238,7 @@ tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-4: Disabled timeout ===\n")));
bool ok = true;
- echo->ping (0, 1);
+ ok &= echo->ping (0, 1);
ok &= check ("TC-4 after ping (expect 1)", cache_size(orb), 1);
diff --git a/TAO/tests/Transport_Idle_Timeout/test.idl b/TAO/tests/Transport_Idle_Timeout/test.idl
index 4f4dbf4bfd97a..f5604db5feb5e 100644
--- a/TAO/tests/Transport_Idle_Timeout/test.idl
+++ b/TAO/tests/Transport_Idle_Timeout/test.idl
@@ -11,7 +11,7 @@ module Test
/// Sleeping means running the reactor to make sure idle connections are purged
/// Pass in the cache size we expect just before returning the call on the server
/// side
- void ping (in long sleep_time, in long cache_size_expected);
+ boolean ping (in long sleep_time, in long cache_size_expected);
/// Orderly shutdown.
oneway void shutdown ();
From 0e7d800fa0bb989e294d2293063e5a8928031562 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Tue, 31 Mar 2026 12:44:58 +0200
Subject: [PATCH 20/37] Removed disabled test, default
* TAO/tests/Transport_Idle_Timeout/svc_disabled.conf:
Deleted.
* TAO/tests/Transport_Idle_Timeout/run_test.pl:
---
TAO/tests/Transport_Idle_Timeout/run_test.pl | 9 ---------
TAO/tests/Transport_Idle_Timeout/svc_disabled.conf | 5 -----
2 files changed, 14 deletions(-)
delete mode 100644 TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
index 7b9ecd8ce0299..c661555fa73f6 100755
--- a/TAO/tests/Transport_Idle_Timeout/run_test.pl
+++ b/TAO/tests/Transport_Idle_Timeout/run_test.pl
@@ -114,15 +114,6 @@ sub run_scenario {
""
);
-# ---------------------------------------------------------------------------
-# Scenario 2: TC-4 (timeout disabled)
-# ---------------------------------------------------------------------------
-run_scenario (
- "TC-4: idle timeout disabled",
- "svc_disabled.conf",
- "-d"
-);
-
# ---------------------------------------------------------------------------
# Final result
# ---------------------------------------------------------------------------
diff --git a/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
deleted file mode 100644
index ead3f93c9bf22..0000000000000
--- a/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
+++ /dev/null
@@ -1,5 +0,0 @@
-# Used by server and client for TC-4 (disabled idle timeout).
-# Setting -ORBTransportIdleTimeout 0 disables the feature entirely;
-# transports must persist
-
-static Resource_Factory "-ORBConnectionPurgingStrategy lru -ORBConnectionCacheMax 200 -ORBTransportIdleTimeout 0"
From 31046bdf8070bf7a510a4c26d7129724b005e2fb Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Tue, 31 Mar 2026 13:14:33 +0200
Subject: [PATCH 21/37] Test infrastructure
* TAO/tests/Transport_Idle_Timeout/svc_disabled.conf:
Added.
* TAO/tests/Transport_Idle_Timeout/Echo_i.cpp:
* TAO/tests/Transport_Idle_Timeout/Echo_i.h:
* TAO/tests/Transport_Idle_Timeout/client.cpp:
* TAO/tests/Transport_Idle_Timeout/run_test.pl:
* TAO/tests/Transport_Idle_Timeout/svc.conf:
* TAO/tests/Transport_Idle_Timeout/test.idl:
---
TAO/tests/Transport_Idle_Timeout/Echo_i.cpp | 10 ++++++-
TAO/tests/Transport_Idle_Timeout/Echo_i.h | 2 +-
TAO/tests/Transport_Idle_Timeout/client.cpp | 27 ++++++++++---------
TAO/tests/Transport_Idle_Timeout/run_test.pl | 9 +++++++
TAO/tests/Transport_Idle_Timeout/svc.conf | 4 +--
.../Transport_Idle_Timeout/svc_disabled.conf | 5 ++++
TAO/tests/Transport_Idle_Timeout/test.idl | 2 +-
7 files changed, 41 insertions(+), 18 deletions(-)
create mode 100644 TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
index 1b9d25a768342..8613f467215b3 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
@@ -54,7 +54,7 @@ Echo_i::Echo_i (CORBA::ORB_ptr orb)
}
bool
-Echo_i::ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected)
+Echo_i::ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected, ::Test::Echo_ptr server, ::CORBA::Long sleep_time_server)
{
if (TAO_debug_level > 0)
ACE_DEBUG ((LM_DEBUG,
@@ -62,6 +62,14 @@ Echo_i::ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected)
sleep_with_reactor (this->orb_, sleep_time);
+ if (!CORBA::is_nil(server))
+ {
+ if (sleep_time_server > 0)
+ {
+ sleep_with_reactor (this->orb_, sleep_time_server);
+ }
+ }
+
return check ("ping", cache_size(this->orb_), cache_size_expected);
}
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.h b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
index 148d44eb27c5c..0c25be997ec04 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.h
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
@@ -19,7 +19,7 @@ class Echo_i : public virtual POA_Test::Echo
explicit Echo_i (CORBA::ORB_ptr orb);
// Test::Echo operations
- bool ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected) override;
+ bool ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected, ::Test::Echo_ptr server, ::CORBA::Long sleep_time_server) override;
void shutdown () override;
diff --git a/TAO/tests/Transport_Idle_Timeout/client.cpp b/TAO/tests/Transport_Idle_Timeout/client.cpp
index d32ea99cc8965..3ee6d936355b3 100644
--- a/TAO/tests/Transport_Idle_Timeout/client.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/client.cpp
@@ -21,7 +21,7 @@
// TC-4 Disabled timeout (opt-out)
// A second ORB is initialised with -ORBTransportIdleTimeout 0.
// After sleeping well past the default 60 s timeout (we use a
-// short test timeout of 3 s so the second ORB uses 0 = disabled),
+// short test timeout of 1 s so the second ORB uses 0 = disabled),
// cache_size still reflects the connection is open.
// NOTE: This scenario requires a separate server run with
// -ORBTransportIdleTimeout 0 in its svc.conf; run_test.pl
@@ -133,13 +133,13 @@ parse_args (int argc, ACE_TCHAR *argv[])
// 3. cache_size must be 0 -> transport closed by timer.
// ---------------------------------------------------------------------------
static bool
-tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
+tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
{
ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-1: Basic idle close ===\n")));
bool ok = true;
// --- Step 1: establish a transport ---
- ok &= echo->ping (0, 1);
+ ok &= echo->ping (0, 1, echo2, 0);
ok &= check ("TC-1 after ping (expect 1)", cache_size(orb), 1);
@@ -164,14 +164,14 @@ tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// 2. cache_size must be 1 again.
// ---------------------------------------------------------------------------
static bool
-tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
+tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
{
ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-2: Reconnect after idle close ===\n")));
bool ok = true;
// A new ping must succeed without TRANSIENT even though TC-1 caused the
// server to close the connection. TAO's reconnect logic handles this.
- ok &= echo->ping (0, 1);
+ ok &= echo->ping (0, 1, echo2, 0);
ok &= check ("TC-2 after reconnect ping (expect 1)", cache_size(orb), 1);
@@ -189,7 +189,7 @@ tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// 3. Sleep another 4s — now past the timeout, cache must be 0.
// ---------------------------------------------------------------------------
static bool
-tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
+tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
{
ACE_DEBUG ((LM_INFO,
ACE_TEXT ("\n=== TC-3: Timer cancellation on reuse (%d pings) ===\n"),
@@ -199,7 +199,7 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// Rapid-fire loop — transport reused each time
for (int i = 0; i < loop_count; ++i)
{
- ok &= echo->ping (0, 1);
+ ok &= echo->ping (0, 1, echo2, 0);
}
// Immediately after the loop the transport returned to idle and the
@@ -233,12 +233,12 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
// be present (i.e. not closed).
// ---------------------------------------------------------------------------
static bool
-tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
+tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
{
ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-4: Disabled timeout ===\n")));
bool ok = true;
- ok &= echo->ping (0, 1);
+ ok &= echo->ping (0, 1, echo2, 0);
ok &= check ("TC-4 after ping (expect 1)", cache_size(orb), 1);
@@ -273,6 +273,7 @@ ACE_TMAIN (int argc, ACE_TCHAR *argv[])
CORBA::Object_var obj = orb->string_to_object (ior);
Test::Echo_var echo = Test::Echo::_narrow (obj.in ());
+ Test::Echo_var echo2{};
if (CORBA::is_nil (echo.in ()))
ACE_ERROR_RETURN ((LM_ERROR,
@@ -283,14 +284,14 @@ ACE_TMAIN (int argc, ACE_TCHAR *argv[])
if (disabled_tc)
{
// TC-4 only — server was started without idle timeout
- all_pass &= tc4_disabled_timeout (orb.in (), echo.in ());
+ all_pass &= tc4_disabled_timeout (orb.in (), echo.in (), echo2.in ());
}
else
{
// TC-1, TC-2, TC-3 in sequence
- all_pass &= tc1_basic_idle_close (orb.in (), echo.in ());
- all_pass &= tc2_reconnect (orb.in (), echo.in ());
- all_pass &= tc3_timer_cancel_on_reuse (orb.in (), echo.in ());
+ all_pass &= tc1_basic_idle_close (orb.in (), echo.in (), echo2.in ());
+ all_pass &= tc2_reconnect (orb.in (), echo.in (), echo2.in ());
+ all_pass &= tc3_timer_cancel_on_reuse (orb.in (), echo.in (), echo2.in ());
}
// Shut down the server
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
index c661555fa73f6..7b9ecd8ce0299 100755
--- a/TAO/tests/Transport_Idle_Timeout/run_test.pl
+++ b/TAO/tests/Transport_Idle_Timeout/run_test.pl
@@ -114,6 +114,15 @@ sub run_scenario {
""
);
+# ---------------------------------------------------------------------------
+# Scenario 2: TC-4 (timeout disabled)
+# ---------------------------------------------------------------------------
+run_scenario (
+ "TC-4: idle timeout disabled",
+ "svc_disabled.conf",
+ "-d"
+);
+
# ---------------------------------------------------------------------------
# Final result
# ---------------------------------------------------------------------------
diff --git a/TAO/tests/Transport_Idle_Timeout/svc.conf b/TAO/tests/Transport_Idle_Timeout/svc.conf
index b94824e9a07f3..8aba047832d0c 100644
--- a/TAO/tests/Transport_Idle_Timeout/svc.conf
+++ b/TAO/tests/Transport_Idle_Timeout/svc.conf
@@ -1,6 +1,6 @@
# Used by server and client for TC-1, TC-2, TC-3.
-# Sets a short idle timeout (3 seconds) so the test completes quickly.
+# Sets a short idle timeout (2 seconds) so the test completes quickly.
# LRU purging strategy is kept at its default size so capacity-based
# purging never fires during the test (we want only timer-based close).
-static Resource_Factory "-ORBConnectionPurgingStrategy lru -ORBConnectionCacheMax 200 -ORBTransportIdleTimeout 3"
+static Resource_Factory "-ORBTransportIdleTimeout 3"
diff --git a/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
new file mode 100644
index 0000000000000..04b60678dd487
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
@@ -0,0 +1,5 @@
+# Used by server and client for TC-4 (disabled idle timeout, default).
+# Setting -ORBTransportIdleTimeout 0 disables the feature entirely;
+# transports must persist
+
+static Resource_Factory "-ORBConnectionPurgingStrategy lru -ORBConnectionCacheMax 200 -ORBTransportIdleTimeout 0"
diff --git a/TAO/tests/Transport_Idle_Timeout/test.idl b/TAO/tests/Transport_Idle_Timeout/test.idl
index f5604db5feb5e..29fa44fde4d7b 100644
--- a/TAO/tests/Transport_Idle_Timeout/test.idl
+++ b/TAO/tests/Transport_Idle_Timeout/test.idl
@@ -11,7 +11,7 @@ module Test
/// Sleeping means running the reactor to make sure idle connections are purged
/// Pass in the cache size we expect just before returning the call on the server
/// side
- boolean ping (in long sleep_time, in long cache_size_expected);
+ boolean ping (in long sleep_time, in long cache_size_expected, in Echo server, in long sleep_time_server);
/// Orderly shutdown.
oneway void shutdown ();
From c7c77cbf623996def48d1da91df57eaaac0f06be Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Tue, 31 Mar 2026 14:01:14 +0200
Subject: [PATCH 22/37] Add special client for testing with multiple servers,
mixing basic and multiple gets too complicated for a unit test
* TAO/tests/Transport_Idle_Timeout/client_multiple.cpp:
Added.
* TAO/tests/Transport_Idle_Timeout/Echo_i.cpp:
* TAO/tests/Transport_Idle_Timeout/Idle_Transport_Timeout.mpc:
* TAO/tests/Transport_Idle_Timeout/client.cpp:
* TAO/tests/Transport_Idle_Timeout/run_test.pl:
* TAO/tests/Transport_Idle_Timeout/svc.conf:
* TAO/tests/Transport_Idle_Timeout/svc_disabled.conf:
---
TAO/tests/Transport_Idle_Timeout/Echo_i.cpp | 1 +
.../Idle_Transport_Timeout.mpc | 12 +
TAO/tests/Transport_Idle_Timeout/client.cpp | 7 +-
.../client_multiple.cpp | 326 ++++++++++++++++++
TAO/tests/Transport_Idle_Timeout/run_test.pl | 147 +++++++-
TAO/tests/Transport_Idle_Timeout/svc.conf | 2 -
.../Transport_Idle_Timeout/svc_disabled.conf | 2 +-
7 files changed, 479 insertions(+), 18 deletions(-)
create mode 100644 TAO/tests/Transport_Idle_Timeout/client_multiple.cpp
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
index 8613f467215b3..0f6631997a5b5 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
@@ -64,6 +64,7 @@ Echo_i::ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected, ::Tes
if (!CORBA::is_nil(server))
{
+ server->ping(sleep_time, 0, Test::Echo::_nil(), 0);
if (sleep_time_server > 0)
{
sleep_with_reactor (this->orb_, sleep_time_server);
diff --git a/TAO/tests/Transport_Idle_Timeout/Idle_Transport_Timeout.mpc b/TAO/tests/Transport_Idle_Timeout/Idle_Transport_Timeout.mpc
index 4a250549f88f2..9ea88aa41362d 100644
--- a/TAO/tests/Transport_Idle_Timeout/Idle_Transport_Timeout.mpc
+++ b/TAO/tests/Transport_Idle_Timeout/Idle_Transport_Timeout.mpc
@@ -30,3 +30,15 @@ project(*client): taoclient {
testC.h
}
}
+
+project(*client_multiple): taoclient {
+ exename = client_multiple
+ after += *idl
+ Source_Files {
+ client_multiple.cpp
+ testC.cpp
+ }
+ Header_Files {
+ testC.h
+ }
+}
diff --git a/TAO/tests/Transport_Idle_Timeout/client.cpp b/TAO/tests/Transport_Idle_Timeout/client.cpp
index 3ee6d936355b3..fecfc07e20913 100644
--- a/TAO/tests/Transport_Idle_Timeout/client.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/client.cpp
@@ -104,7 +104,7 @@ static bool disabled_tc = false;
static int
parse_args (int argc, ACE_TCHAR *argv[])
{
- ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("k:t:n:d"));
+ ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("k:l:t:n:d"));
int c;
while ((c = get_opts ()) != -1)
switch (c)
@@ -272,8 +272,8 @@ ACE_TMAIN (int argc, ACE_TCHAR *argv[])
return 1;
CORBA::Object_var obj = orb->string_to_object (ior);
- Test::Echo_var echo = Test::Echo::_narrow (obj.in ());
- Test::Echo_var echo2{};
+ Test::Echo_var echo = Test::Echo::_narrow (obj.in ());
+ Test::Echo_var echo2;
if (CORBA::is_nil (echo.in ()))
ACE_ERROR_RETURN ((LM_ERROR,
@@ -295,6 +295,7 @@ ACE_TMAIN (int argc, ACE_TCHAR *argv[])
}
// Shut down the server
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Shutting down echo\n")));
echo->shutdown ();
orb->destroy ();
diff --git a/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp b/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp
new file mode 100644
index 0000000000000..72b2ffabbd48d
--- /dev/null
+++ b/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp
@@ -0,0 +1,326 @@
+// Regression-test client for the TAO idle-transport-timeout feature.
+//
+// Test scenarios (executed in order):
+//
+// TC-1 Basic idle close
+// Make one ping; verify server-side cache_size == 1; sleep past
+// the timeout; verify cache_size == 0 (transport closed by timer).
+//
+// TC-2 Reconnect after idle close
+// After TC-1, ping again; verify cache_size == 1 again (new
+// transport created transparently). Confirms TRANSIENT is not
+// raised by the reconnect path.
+//
+// TC-3 Timer cancellation on reuse
+// Ping rapidly N times in a tight loop; the transport is
+// continuously reacquired so the idle timer is cancelled and
+// rescheduled each cycle. After the loop, sleep just under the
+// timeout and verify cache_size == 1 (connection still alive).
+// Then sleep past the timeout and verify cache_size == 0.
+//
+// TC-4 Disabled timeout (opt-out)
+// A second ORB is initialised with -ORBTransportIdleTimeout 0.
+// After sleeping well past the default 60 s timeout (we use a
+// short test timeout of 1 s so the second ORB uses 0 = disabled),
+// cache_size still reflects the connection is open.
+// NOTE: This scenario requires a separate server run with
+// -ORBTransportIdleTimeout 0 in its svc.conf; run_test.pl
+// handles this. Within this binary TC-4 is a command-line flag.
+//
+// Usage:
+// client -k -t [-n ] [-d]
+//
+// -t The idle timeout configured on the *server* (default: 3).
+// The client sleeps for (timeout + 2) seconds to give the
+// reactor sufficient time to fire the timer.
+// -n Number of rapid-fire pings in TC-3 (default: 10).
+// -d Run TC-4 (disabled-timeout) scenario instead of TC-1..3.
+
+#include "testC.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_sys_time.h"
+#include "tao/ORB_Core.h"
+#include "tao/Transport_Cache_Manager_T.h"
+#include "tao/Thread_Lane_Resources.h"
+
+// ---------------------------------------------------------------------------
+// Helpers
+// ---------------------------------------------------------------------------
+
+/// Sleep for @a seconds, spinning on reactor events so that the server's
+/// reactor thread (which fires the idle timer) is not blocked.
+/// We cannot use ACE_OS::sleep() alone because in a single-process test
+/// harness the reactor runs in the same thread. For a two-process test
+/// the sleep is fine; for safety we drain reactor events anyway.
+void
+sleep_with_reactor (CORBA::ORB_ptr orb, int seconds)
+{
+ ACE_Time_Value deadline =
+ ACE_OS::gettimeofday () + ACE_Time_Value (seconds);
+
+ while (ACE_OS::gettimeofday () < deadline)
+ {
+ ACE_Time_Value tv (0, 50000); // 50 ms slices
+ orb->perform_work (tv);
+ }
+}
+
+/// Verify an expected value and print PASS/FAIL. Returns false on failure.
+bool
+check (const char *label, size_t got, size_t expected)
+{
+ if (got == expected)
+ {
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" [PASS] %C : cache_size = %B (expected %B)\n"),
+ label, got, expected));
+ return true;
+ }
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" [FAIL] %C : cache_size = %B (expected %B)\n"),
+ label, got, expected));
+ return false;
+}
+
+/// Retrieve the current size of the cache in the client
+size_t
+cache_size(CORBA::ORB_ptr orb)
+{
+ TAO_ORB_Core *core = orb->orb_core ();
+ return core->lane_resources ().transport_cache ().current_size ();
+}
+
+// ---------------------------------------------------------------------------
+// Argument parsing
+// ---------------------------------------------------------------------------
+
+static const char *ior = nullptr;
+static const char *ior2 = nullptr;
+static int timeout_sec = 3; // must match server svc.conf value
+static int loop_count = 10;
+static bool disabled_tc = false;
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("k:l:t:n:d"));
+ int c;
+ while ((c = get_opts ()) != -1)
+ switch (c)
+ {
+ case 'k': ior = get_opts.opt_arg (); break;
+ case 'l': ior2 = get_opts.opt_arg (); break;
+ case 't': timeout_sec = ACE_OS::atoi (get_opts.opt_arg ()); break;
+ case 'n': loop_count = ACE_OS::atoi (get_opts.opt_arg ()); break;
+ case 'd': disabled_tc = true; break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Usage: client -k [-l ] [-t ] [-n ] [-d]\n")),
+ -1);
+ }
+ if (ior == nullptr)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("client: -k is required\n")), -1);
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// TC-1 : Basic idle close
+// ---------------------------------------------------------------------------
+// Steps:
+// 1. Ping once -> transport created, server cache_size must be 1.
+// 2. Sleep (timeout + 2s) -> idle timer fires on the server.
+// 3. cache_size must be 0 -> transport closed by timer.
+// ---------------------------------------------------------------------------
+static bool
+tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
+{
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-1: Basic idle close ===\n")));
+ bool ok = true;
+
+ // --- Step 1: establish a transport ---
+ ok &= echo->ping (0, 1, echo2, 0);
+
+ ok &= check ("TC-1 after ping (expect 1)", cache_size(orb), 1);
+
+ // --- Step 2: idle sleep ---
+ int const sleep_sec = timeout_sec + 2;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" sleeping %d s for idle timer to fire...\n"),
+ sleep_sec));
+ sleep_with_reactor (orb, sleep_sec);
+
+ // --- Step 3: cache must be empty now ---
+ ok &= check ("TC-1 after idle timeout (expect 0)", cache_size(orb), 0);
+
+ return ok;
+}
+
+// ---------------------------------------------------------------------------
+// TC-2 : Reconnect after idle close
+// ---------------------------------------------------------------------------
+// Steps:
+// 1. Ping (reconnects transparently after TC-1 closed the transport).
+// 2. cache_size must be 1 again.
+// ---------------------------------------------------------------------------
+static bool
+tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
+{
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-2: Reconnect after idle close ===\n")));
+ bool ok = true;
+
+ // A new ping must succeed without TRANSIENT even though TC-1 caused the
+ // server to close the connection. TAO's reconnect logic handles this.
+ ok &= echo->ping (0, 1, echo2, 0);
+
+ ok &= check ("TC-2 after reconnect ping (expect 1)", cache_size(orb), 1);
+
+ return ok;
+}
+
+// ---------------------------------------------------------------------------
+// TC-3 : Timer cancellation on continuous reuse
+// ---------------------------------------------------------------------------
+// Steps:
+// 1. Send N pings in rapid succession. Each one reacquires the transport
+// (BUSY), cancels the idle timer, then releases back to idle and
+// reschedules the timer. No close should occur mid-loop.
+// 2. Sleep (timeout - 1)s — still within the window, cache must be 1.
+// 3. Sleep another 4s — now past the timeout, cache must be 0.
+// ---------------------------------------------------------------------------
+static bool
+tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("\n=== TC-3: Timer cancellation on reuse (%d pings) ===\n"),
+ loop_count));
+ bool ok = true;
+
+ // Rapid-fire loop — transport reused each time
+ for (int i = 0; i < loop_count; ++i)
+ {
+ ok &= echo->ping (0, 1, echo2, 0);
+ }
+
+ // Immediately after the loop the transport returned to idle and the
+ // timer was (re)started. Cache must show 1 entry.
+ ok &= check ("TC-3 immediately after loop (expect 1)", cache_size(orb), 1);
+
+ // Sleep to just before the expected timeout
+ int const pre_sleep = (timeout_sec > 1) ? timeout_sec - 1 : 1;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" sleeping %d s (pre-timeout)...\n"), pre_sleep));
+ sleep_with_reactor (orb, pre_sleep);
+
+ ok &= check ("TC-3 before timeout (expect 1)", cache_size(orb), 1);
+
+ // Sleep past the remainder of the timeout
+ int constexpr post_sleep = 4;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" sleeping %d s (post-timeout)...\n"), post_sleep));
+ sleep_with_reactor (orb, post_sleep);
+
+ ok &= check ("TC-3 after timeout (expect 0)", cache_size(orb), 0);
+
+ return ok;
+}
+
+// ---------------------------------------------------------------------------
+// TC-4 : Disabled timeout (opt-out)
+// ---------------------------------------------------------------------------
+// The server is started with -ORBTransportIdleTimeout 0 for this scenario.
+// After sleeping well past the default timeout, the transport must still
+// be present (i.e. not closed).
+// ---------------------------------------------------------------------------
+static bool
+tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
+{
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-4: Disabled timeout ===\n")));
+ bool ok = true;
+
+ ok &= echo->ping (0, 1, echo2, 0);
+
+ ok &= check ("TC-4 after ping (expect 1)", cache_size(orb), 1);
+
+ // With timeout disabled the connection must never be closed.
+ // We use a short wall-clock sleep equal to (timeout_sec + 2) — when
+ // run_test.pl invokes TC-4 the server timeout is 0, so the timer never
+ // fires regardless.
+ const int sleep_sec = timeout_sec + 2;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" sleeping %d s (timeout should NOT fire)...\n"),
+ sleep_sec));
+ sleep_with_reactor (orb, sleep_sec);
+
+ ok &= check ("TC-4 after sleep with timeout=0 (expect 1)", cache_size(orb), 1);
+
+ return ok;
+}
+
+// ---------------------------------------------------------------------------
+// main
+// ---------------------------------------------------------------------------
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ try
+ {
+ CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);
+
+ if (parse_args (argc, argv) != 0)
+ return 1;
+
+ CORBA::Object_var obj = orb->string_to_object (ior);
+ CORBA::Object_var obj2;
+ if (ior2)
+ {
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Client received echo2\n")));
+ obj2 = orb->string_to_object (ior2);
+ }
+ Test::Echo_var echo = Test::Echo::_narrow (obj.in ());
+ Test::Echo_var echo2 = Test::Echo::_narrow (obj2.in ());;
+
+ if (CORBA::is_nil (echo.in ()))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Narrow to Test::Echo failed\n")), 1);
+
+ bool all_pass = true;
+
+ if (disabled_tc)
+ {
+ // TC-4 only — server was started without idle timeout
+ all_pass &= tc4_disabled_timeout (orb.in (), echo.in (), echo2.in ());
+ }
+ else
+ {
+ // TC-1, TC-2, TC-3 in sequence
+ all_pass &= tc1_basic_idle_close (orb.in (), echo.in (), echo2.in ());
+ all_pass &= tc2_reconnect (orb.in (), echo.in (), echo2.in ());
+ all_pass &= tc3_timer_cancel_on_reuse (orb.in (), echo.in (), echo2.in ());
+ }
+
+ // Shut down the server
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Shutting down echo\n")));
+ echo->shutdown ();
+ if (!CORBA::is_nil (echo2.in ()))
+ {
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Shutting down echo2\n")));
+ echo2->shutdown ();
+ }
+
+ orb->destroy ();
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("\n=== Overall result: %C ===\n"),
+ all_pass ? "PASS" : "FAIL"));
+ return all_pass ? 0 : 1;
+ }
+ catch (const CORBA::Exception &ex)
+ {
+ ex._tao_print_exception (ACE_TEXT ("client exception"));
+ return 1;
+ }
+}
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
index 7b9ecd8ce0299..fcf420729d2ed 100755
--- a/TAO/tests/Transport_Idle_Timeout/run_test.pl
+++ b/TAO/tests/Transport_Idle_Timeout/run_test.pl
@@ -16,7 +16,8 @@
# Helpers
# ---------------------------------------------------------------------------
-my $ior_file = "test.ior";
+my $ior_file1 = "test1.ior";
+my $ior_file2 = "test2.ior";
my $timeout_sec = 3; # must match svc.conf value
my $status = 0;
my $debug_level = '0';
@@ -38,11 +39,11 @@ sub run_scenario {
my $server = PerlACE::TestTarget::create_target (1) || die "Cannot create server target";
my $client = PerlACE::TestTarget::create_target (2) || die "Cannot create client target";
- my $server_ior = $server->LocalFile ($ior_file);
- my $client_ior = $client->LocalFile ($ior_file);
+ my $server_ior = $server->LocalFile ($ior_file1);
+ my $client_ior = $client->LocalFile ($ior_file1);
- $server->DeleteFile ($ior_file);
- $client->DeleteFile ($ior_file);
+ $server->DeleteFile ($ior_file1);
+ $client->DeleteFile ($ior_file1);
my $SV = $server->CreateProcess (
"server",
@@ -62,7 +63,7 @@ sub run_scenario {
}
# Wait for IOR file to appear (up to 30 s)
- if ($server->WaitForFileTimed ($ior_file,
+ if ($server->WaitForFileTimed ($ior_file1,
$server->ProcessStartWaitInterval ()) == -1) {
print STDERR "ERROR: IOR file '$server_ior' not created\n";
$SV->Kill (); $SV->TimedWait (1);
@@ -70,13 +71,13 @@ sub run_scenario {
}
# Transfer IOR file to client (no-op on single-host runs)
- if ($server->GetFile ($ior_file) == -1) {
- print STDERR "ERROR: server GetFile '$ior_file' failed\n";
+ if ($server->GetFile ($ior_file1) == -1) {
+ print STDERR "ERROR: server GetFile '$ior_file1' failed\n";
$SV->Kill (); $SV->TimedWait (1);
return 1;
}
- if ($client->PutFile ($ior_file) == -1) {
- print STDERR "ERROR: client PutFile '$ior_file' failed\n";
+ if ($client->PutFile ($ior_file1) == -1) {
+ print STDERR "ERROR: client PutFile '$ior_file1' failed\n";
$SV->Kill (); $SV->TimedWait (1);
return 1;
}
@@ -99,8 +100,125 @@ sub run_scenario {
$status = 1;
}
- $server->DeleteFile ($ior_file);
- $client->DeleteFile ($ior_file);
+ $server->DeleteFile ($ior_file1);
+ $client->DeleteFile ($ior_file1);
+
+ return $status;
+}
+
+sub run_multiple_scenario {
+ my ($label, $svc_conf, $extra_client_args) = @_;
+
+ print "\n### $label ###\n";
+
+ my $server1 = PerlACE::TestTarget::create_target (1) || die "Cannot create server1 target";
+ my $server2 = PerlACE::TestTarget::create_target (2) || die "Cannot create server2 target";
+ my $client = PerlACE::TestTarget::create_target (3) || die "Cannot create client target";
+
+ my $server1_ior = $server1->LocalFile ($ior_file1);
+ my $server2_ior = $server2->LocalFile ($ior_file2);
+ my $client1_ior = $client->LocalFile ($ior_file1);
+ my $client2_ior = $client->LocalFile ($ior_file2);
+
+ $server1->DeleteFile ($ior_file1);
+ $server2->DeleteFile ($ior_file2);
+ $client->DeleteFile ($ior_file1);
+ $client->DeleteFile ($ior_file2);
+
+ my $SV1 = $server1->CreateProcess (
+ "server",
+ "-ORBdebuglevel $debug_level -ORBSvcConf $svc_conf -o $server1_ior"
+ );
+ my $SV2 = $server2->CreateProcess (
+ "server",
+ "-ORBdebuglevel $debug_level -ORBSvcConf $svc_conf -o $server2_ior"
+ );
+
+ my $CL = $client->CreateProcess (
+ "client_multiple",
+ "-ORBdebuglevel $cdebug_level -ORBSvcConf $svc_conf -k file://$client1_ior -l file://$client2_ior -t $timeout_sec $extra_client_args"
+ );
+
+ # Start server 1
+ my $server1_status = $SV1->Spawn ();
+ if ($server1_status != 0) {
+ print STDERR "ERROR: server1 Spawn returned $server1_status\n";
+ return 1;
+ }
+
+ # Start server 2
+ my $server2_status = $SV2->Spawn ();
+ if ($server2_status != 0) {
+ print STDERR "ERROR: server2 Spawn returned $server2_status\n";
+ return 1;
+ }
+
+ # Wait for IOR file 1 to appear (up to 30 s)
+ if ($server1->WaitForFileTimed ($ior_file1,
+ $server1->ProcessStartWaitInterval ()) == -1) {
+ print STDERR "ERROR: IOR file '$server1_ior' not created\n";
+ $SV1->Kill (); $SV1->TimedWait (1);
+ return 1;
+ }
+
+ # Wait for IOR file 2 to appear (up to 30 s)
+ if ($server2->WaitForFileTimed ($ior_file2,
+ $server2->ProcessStartWaitInterval ()) == -1) {
+ print STDERR "ERROR: IOR file '$server2_ior' not created\n";
+ $SV2->Kill (); $SV2->TimedWait (1);
+ return 1;
+ }
+
+ # Transfer IOR file to client (no-op on single-host runs)
+ if ($server1->GetFile ($ior_file1) == -1) {
+ print STDERR "ERROR: server1 GetFile '$ior_file1' failed\n";
+ $SV1->Kill (); $SV1->TimedWait (1);
+ return 1;
+ }
+ if ($client->PutFile ($ior_file1) == -1) {
+ print STDERR "ERROR: client PutFile '$ior_file1' failed\n";
+ $SV1->Kill (); $SV1->TimedWait (1);
+ return 1;
+ }
+ if ($server2->GetFile ($ior_file2) == -1) {
+ print STDERR "ERROR: server2 GetFile '$ior_file2' failed\n";
+ $SV2->Kill (); $SV2->TimedWait (1);
+ return 1;
+ }
+ if ($client->PutFile ($ior_file2) == -1) {
+ print STDERR "ERROR: client PutFile '$ior_file2' failed\n";
+ $SV2->Kill (); $SV2->TimedWait (1);
+ return 1;
+ }
+
+ # Run client — allow generous wall-clock budget:
+ # TC-1+TC-2+TC-3: ~3*(timeout+2) + 3 slack = ~20 s for timeout=3
+ # TC-4: timeout+2 + 3 slack = ~8 s
+ my $client_budget = ($extra_client_args =~ /-d/) ? 15 : 60;
+ my $client_status = $CL->SpawnWaitKill ($client->ProcessStartWaitInterval ()
+ + $client_budget);
+ if ($client_status != 0) {
+ print STDERR "ERROR: client returned $client_status\n";
+ $status = 1;
+ }
+
+ # Wait for server 1 to exit (it calls orb->shutdown() on receiving shutdown())
+ my $server_exit1 = $SV1->WaitKill ($server1->ProcessStopWaitInterval ());
+ if ($server_exit1 != 0) {
+ print STDERR "ERROR: server1 returned $server_exit1\n";
+ $status = 1;
+ }
+ # Wait for server 2 to exit (it calls orb->shutdown() on receiving shutdown())
+ my $server_exit2 = $SV2->WaitKill ($server2->ProcessStopWaitInterval ());
+ if ($server_exit2 != 0) {
+ print STDERR "ERROR: server2 returned $server_exit2\n";
+ $status = 1;
+ }
+
+ $server1->DeleteFile ($ior_file1);
+ $server2->DeleteFile ($ior_file2);
+ $client->DeleteFile ($ior_file1);
+ $client->DeleteFile ($ior_file2);
return $status;
}
@@ -123,6 +241,11 @@ sub run_scenario {
"-d"
);
+run_multiple_scenario (
+ "TC-1/TC-2/TC-3: idle timeout enabled (${timeout_sec}s)",
+ "svc.conf",
+ ""
+);
# ---------------------------------------------------------------------------
# Final result
# ---------------------------------------------------------------------------
diff --git a/TAO/tests/Transport_Idle_Timeout/svc.conf b/TAO/tests/Transport_Idle_Timeout/svc.conf
index 8aba047832d0c..5669ac1eef86a 100644
--- a/TAO/tests/Transport_Idle_Timeout/svc.conf
+++ b/TAO/tests/Transport_Idle_Timeout/svc.conf
@@ -1,6 +1,4 @@
# Used by server and client for TC-1, TC-2, TC-3.
# Sets a short idle timeout (2 seconds) so the test completes quickly.
-# LRU purging strategy is kept at its default size so capacity-based
-# purging never fires during the test (we want only timer-based close).
static Resource_Factory "-ORBTransportIdleTimeout 3"
diff --git a/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
index 04b60678dd487..6c1175a035bbe 100644
--- a/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
+++ b/TAO/tests/Transport_Idle_Timeout/svc_disabled.conf
@@ -2,4 +2,4 @@
# Setting -ORBTransportIdleTimeout 0 disables the feature entirely;
# transports must persist
-static Resource_Factory "-ORBConnectionPurgingStrategy lru -ORBConnectionCacheMax 200 -ORBTransportIdleTimeout 0"
+static Resource_Factory "-ORBTransportIdleTimeout 0"
From 1dfa8fe00d12982da14f3701696dd1593c93f547 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Tue, 31 Mar 2026 15:52:03 +0200
Subject: [PATCH 23/37] Test extensions
* TAO/tests/Transport_Idle_Timeout/Echo_i.cpp:
* TAO/tests/Transport_Idle_Timeout/Echo_i.h:
* TAO/tests/Transport_Idle_Timeout/client.cpp:
* TAO/tests/Transport_Idle_Timeout/client_multiple.cpp:
* TAO/tests/Transport_Idle_Timeout/run_test.pl:
* TAO/tests/Transport_Idle_Timeout/test.idl:
---
TAO/tests/Transport_Idle_Timeout/Echo_i.cpp | 18 +++++++++----
TAO/tests/Transport_Idle_Timeout/Echo_i.h | 2 +-
TAO/tests/Transport_Idle_Timeout/client.cpp | 25 +++++++++----------
.../client_multiple.cpp | 15 ++++++++---
TAO/tests/Transport_Idle_Timeout/run_test.pl | 20 +++++++--------
TAO/tests/Transport_Idle_Timeout/test.idl | 2 +-
6 files changed, 48 insertions(+), 34 deletions(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
index 0f6631997a5b5..1c8d2888d56b8 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
@@ -54,24 +54,32 @@ Echo_i::Echo_i (CORBA::ORB_ptr orb)
}
bool
-Echo_i::ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected, ::Test::Echo_ptr server, ::CORBA::Long sleep_time_server)
+Echo_i::ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected, ::Test::Echo_ptr server, ::CORBA::Long sleep_time_server, ::CORBA::Long cache_size_expected2)
{
if (TAO_debug_level > 0)
ACE_DEBUG ((LM_DEBUG,
- ACE_TEXT ("Echo_i::ping, sleep time (%d), cache size expected (%d)\n"), sleep_time, cache_size_expected));
+ ACE_TEXT ("(%P|%t) Echo_i::ping, sleep time (%d), cache size expected (%d)\n"), sleep_time, cache_size_expected));
+ bool ok = true;
sleep_with_reactor (this->orb_, sleep_time);
if (!CORBA::is_nil(server))
{
- server->ping(sleep_time, 0, Test::Echo::_nil(), 0);
+ if (TAO_debug_level > 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_i::ping, pinging second server\n")));
+ ok &= server->ping (sleep_time_server, 1, Test::Echo::_nil(), 0, 1);
if (sleep_time_server > 0)
{
sleep_with_reactor (this->orb_, sleep_time_server);
}
+ ok &= check ("ping", cache_size(this->orb_), cache_size_expected2);
}
-
- return check ("ping", cache_size(this->orb_), cache_size_expected);
+ else
+ {
+ ok &= check ("ping", cache_size(this->orb_), cache_size_expected);
+ }
+ return ok;
}
void
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.h b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
index 0c25be997ec04..197d8c61757d4 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.h
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.h
@@ -19,7 +19,7 @@ class Echo_i : public virtual POA_Test::Echo
explicit Echo_i (CORBA::ORB_ptr orb);
// Test::Echo operations
- bool ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected, ::Test::Echo_ptr server, ::CORBA::Long sleep_time_server) override;
+ bool ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected, ::Test::Echo_ptr server, ::CORBA::Long sleep_time_server, ::CORBA::Long cache_size_expected2) override;
void shutdown () override;
diff --git a/TAO/tests/Transport_Idle_Timeout/client.cpp b/TAO/tests/Transport_Idle_Timeout/client.cpp
index fecfc07e20913..68faafca6c7d5 100644
--- a/TAO/tests/Transport_Idle_Timeout/client.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/client.cpp
@@ -133,13 +133,13 @@ parse_args (int argc, ACE_TCHAR *argv[])
// 3. cache_size must be 0 -> transport closed by timer.
// ---------------------------------------------------------------------------
static bool
-tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
+tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
{
ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-1: Basic idle close ===\n")));
bool ok = true;
// --- Step 1: establish a transport ---
- ok &= echo->ping (0, 1, echo2, 0);
+ ok &= echo->ping (0, 1, Test::Echo::_nil (), 0, 0);
ok &= check ("TC-1 after ping (expect 1)", cache_size(orb), 1);
@@ -164,14 +164,14 @@ tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr ec
// 2. cache_size must be 1 again.
// ---------------------------------------------------------------------------
static bool
-tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
+tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
{
ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-2: Reconnect after idle close ===\n")));
bool ok = true;
// A new ping must succeed without TRANSIENT even though TC-1 caused the
// server to close the connection. TAO's reconnect logic handles this.
- ok &= echo->ping (0, 1, echo2, 0);
+ ok &= echo->ping (0, 1, Test::Echo::_nil (), 0, 0);
ok &= check ("TC-2 after reconnect ping (expect 1)", cache_size(orb), 1);
@@ -189,7 +189,7 @@ tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
// 3. Sleep another 4s — now past the timeout, cache must be 0.
// ---------------------------------------------------------------------------
static bool
-tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
+tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
{
ACE_DEBUG ((LM_INFO,
ACE_TEXT ("\n=== TC-3: Timer cancellation on reuse (%d pings) ===\n"),
@@ -199,7 +199,7 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_p
// Rapid-fire loop — transport reused each time
for (int i = 0; i < loop_count; ++i)
{
- ok &= echo->ping (0, 1, echo2, 0);
+ ok &= echo->ping (0, 1, Test::Echo::_nil (), 0, 0);
}
// Immediately after the loop the transport returned to idle and the
@@ -233,12 +233,12 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_p
// be present (i.e. not closed).
// ---------------------------------------------------------------------------
static bool
-tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
+tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo)
{
ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-4: Disabled timeout ===\n")));
bool ok = true;
- ok &= echo->ping (0, 1, echo2, 0);
+ ok &= echo->ping (0, 1, Test::Echo::_nil (), 0, 0);
ok &= check ("TC-4 after ping (expect 1)", cache_size(orb), 1);
@@ -273,7 +273,6 @@ ACE_TMAIN (int argc, ACE_TCHAR *argv[])
CORBA::Object_var obj = orb->string_to_object (ior);
Test::Echo_var echo = Test::Echo::_narrow (obj.in ());
- Test::Echo_var echo2;
if (CORBA::is_nil (echo.in ()))
ACE_ERROR_RETURN ((LM_ERROR,
@@ -284,14 +283,14 @@ ACE_TMAIN (int argc, ACE_TCHAR *argv[])
if (disabled_tc)
{
// TC-4 only — server was started without idle timeout
- all_pass &= tc4_disabled_timeout (orb.in (), echo.in (), echo2.in ());
+ all_pass &= tc4_disabled_timeout (orb.in (), echo.in ());
}
else
{
// TC-1, TC-2, TC-3 in sequence
- all_pass &= tc1_basic_idle_close (orb.in (), echo.in (), echo2.in ());
- all_pass &= tc2_reconnect (orb.in (), echo.in (), echo2.in ());
- all_pass &= tc3_timer_cancel_on_reuse (orb.in (), echo.in (), echo2.in ());
+ all_pass &= tc1_basic_idle_close (orb.in (), echo.in ());
+ all_pass &= tc2_reconnect (orb.in (), echo.in ());
+ all_pass &= tc3_timer_cancel_on_reuse (orb.in (), echo.in ());
}
// Shut down the server
diff --git a/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp b/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp
index 72b2ffabbd48d..b337378fd76b2 100644
--- a/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp
@@ -141,7 +141,7 @@ tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr ec
bool ok = true;
// --- Step 1: establish a transport ---
- ok &= echo->ping (0, 1, echo2, 0);
+ ok &= echo->ping (0, 2, echo2, 0, 2);
ok &= check ("TC-1 after ping (expect 1)", cache_size(orb), 1);
@@ -155,6 +155,13 @@ tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr ec
// --- Step 3: cache must be empty now ---
ok &= check ("TC-1 after idle timeout (expect 0)", cache_size(orb), 0);
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-1: Call again ping ===\n")));
+
+ // Make another call, but let wait sleep_sec after the ping to the second server,
+ // which means the call takes longer as the idle time.
+ // at that moment the cache should be 1, this means the call takes longer as the idle time,
+ ok &= echo->ping (0, 2, echo2, sleep_sec, 0);
+
return ok;
}
@@ -173,7 +180,7 @@ tc2_reconnect (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr echo2)
// A new ping must succeed without TRANSIENT even though TC-1 caused the
// server to close the connection. TAO's reconnect logic handles this.
- ok &= echo->ping (0, 1, echo2, 0);
+ ok &= echo->ping (0, 2, echo2, 0, 2);
ok &= check ("TC-2 after reconnect ping (expect 1)", cache_size(orb), 1);
@@ -201,7 +208,7 @@ tc3_timer_cancel_on_reuse (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_p
// Rapid-fire loop — transport reused each time
for (int i = 0; i < loop_count; ++i)
{
- ok &= echo->ping (0, 1, echo2, 0);
+ ok &= echo->ping (0, 2, echo2, 0, 2);
}
// Immediately after the loop the transport returned to idle and the
@@ -240,7 +247,7 @@ tc4_disabled_timeout (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr ec
ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n=== TC-4: Disabled timeout ===\n")));
bool ok = true;
- ok &= echo->ping (0, 1, echo2, 0);
+ ok &= echo->ping (0, 2, echo2, 0, 1);
ok &= check ("TC-4 after ping (expect 1)", cache_size(orb), 1);
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
index fcf420729d2ed..14122a655cf99 100755
--- a/TAO/tests/Transport_Idle_Timeout/run_test.pl
+++ b/TAO/tests/Transport_Idle_Timeout/run_test.pl
@@ -226,20 +226,20 @@ sub run_multiple_scenario {
# ---------------------------------------------------------------------------
# Scenario 1: TC-1, TC-2, TC-3 (timeout enabled)
# ---------------------------------------------------------------------------
-run_scenario (
- "TC-1/TC-2/TC-3: idle timeout enabled (${timeout_sec}s)",
- "svc.conf",
- ""
-);
+# run_scenario (
+# "TC-1/TC-2/TC-3: idle timeout enabled (${timeout_sec}s)",
+# "svc.conf",
+# ""
+# );
# ---------------------------------------------------------------------------
# Scenario 2: TC-4 (timeout disabled)
# ---------------------------------------------------------------------------
-run_scenario (
- "TC-4: idle timeout disabled",
- "svc_disabled.conf",
- "-d"
-);
+# run_scenario (
+# "TC-4: idle timeout disabled",
+# "svc_disabled.conf",
+# "-d"
+# );
run_multiple_scenario (
"TC-1/TC-2/TC-3: idle timeout enabled (${timeout_sec}s)",
diff --git a/TAO/tests/Transport_Idle_Timeout/test.idl b/TAO/tests/Transport_Idle_Timeout/test.idl
index 29fa44fde4d7b..4ca53c2a7ba55 100644
--- a/TAO/tests/Transport_Idle_Timeout/test.idl
+++ b/TAO/tests/Transport_Idle_Timeout/test.idl
@@ -11,7 +11,7 @@ module Test
/// Sleeping means running the reactor to make sure idle connections are purged
/// Pass in the cache size we expect just before returning the call on the server
/// side
- boolean ping (in long sleep_time, in long cache_size_expected, in Echo server, in long sleep_time_server);
+ boolean ping (in long sleep_time, in long cache_size_expected, in Echo server, in long sleep_time_server, in long cache_size_expected2);
/// Orderly shutdown.
oneway void shutdown ();
From e0c745a3335baa0e8800987d9eff92c07f73175a Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Tue, 31 Mar 2026 16:53:25 +0200
Subject: [PATCH 24/37] Layout/nullptr changes
* TAO/tao/Transport_Cache_Manager_T.cpp:
---
TAO/tao/Transport_Cache_Manager_T.cpp | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/TAO/tao/Transport_Cache_Manager_T.cpp b/TAO/tao/Transport_Cache_Manager_T.cpp
index 6d92c293ca7bd..8d4ff973abb06 100644
--- a/TAO/tao/Transport_Cache_Manager_T.cpp
+++ b/TAO/tao/Transport_Cache_Manager_T.cpp
@@ -511,8 +511,7 @@ namespace TAO
template
bool
- Transport_Cache_Manager_T::
- is_entry_connecting_i (const HASH_MAP_ENTRY &entry)
+ Transport_Cache_Manager_T::is_entry_connecting_i (const HASH_MAP_ENTRY &entry)
{
Cache_Entries_State entry_state = entry.int_id_.recycle_state ();
bool result = (entry_state == ENTRY_CONNECTING);
@@ -540,8 +539,7 @@ namespace TAO
#if !defined (ACE_LACKS_QSORT)
template
int
- Transport_Cache_Manager_T::
- cpscmp(const void* a, const void* b)
+ Transport_Cache_Manager_T::cpscmp(const void* a, const void* b)
{
const HASH_MAP_ENTRY** left = (const HASH_MAP_ENTRY**) const_cast (a);
const HASH_MAP_ENTRY** right = (const HASH_MAP_ENTRY**) const_cast (b);
@@ -568,7 +566,7 @@ namespace TAO
{
ACE_MT (ACE_GUARD_RETURN (ACE_Lock, ace_mon, *this->cache_lock_, 0));
- DESCRIPTOR_SET sorted_set = 0;
+ DESCRIPTOR_SET sorted_set = nullptr;
int const sorted_size = this->fill_set_i (sorted_set);
// Only call close_entries () if sorted_set != 0. It takes
@@ -597,8 +595,7 @@ namespace TAO
{
if (this->is_entry_purgable_i (*sorted_set[i]))
{
- transport_type* transport =
- sorted_set[i]->int_id_.transport ();
+ transport_type* transport = sorted_set[i]->int_id_.transport ();
sorted_set[i]->int_id_.recycle_state (ENTRY_BUSY);
transport->add_reference ();
@@ -631,13 +628,13 @@ namespace TAO
}
delete [] sorted_set;
- sorted_set = 0;
+ sorted_set = nullptr;
// END FORMER close_entries
}
}
// Now, without the lock held, lets go through and close all the transports.
- if (! transports_to_be_closed.is_empty ())
+ if (!transports_to_be_closed.is_empty ())
{
typename transport_set_type::iterator it (transports_to_be_closed);
while (! it.done ())
From ef7fd5156c649f8de87ba70a8418ef9d2c547319 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Wed, 1 Apr 2026 13:09:44 +0200
Subject: [PATCH 25/37] Work in progress
* TAO/tao/Transport.cpp:
* TAO/tao/Transport_Cache_Manager_T.cpp:
* TAO/tao/Transport_Cache_Manager_T.h:
---
TAO/tao/Transport.cpp | 60 ++++++++++++++++++---------
TAO/tao/Transport_Cache_Manager_T.cpp | 14 +++++++
TAO/tao/Transport_Cache_Manager_T.h | 5 +++
3 files changed, 59 insertions(+), 20 deletions(-)
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index 58531a6623701..0fabb78c01db3 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -572,6 +572,14 @@ TAO_Transport::make_idle ()
int
TAO_Transport::update_transport ()
{
+ if (TAO_debug_level > 3)
+ {
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::update_transport\n"),
+ this->id ()));
+ }
+
+ // @todo jwi timer update????
return this->transport_cache_manager ().update_entry (this->cache_map_entry_);
}
@@ -994,16 +1002,16 @@ TAO_Transport::handle_idle_timeout (const ACE_Time_Value & /* current_time */, c
// prevent a race with find_idle_transport_i().
{
ACE_GUARD_RETURN (ACE_Lock, mon, *this->handler_lock_, 0);
- if (!this->transport_cache_manager ().is_idle (this->cache_map_entry_))
- {
+ if (!this->transport_cache_manager ().is_entry_purgable (this->cache_map_entry_))
+ {
if (TAO_debug_level > 0)
- TAOLIB_DEBUG ((LM_DEBUG,
- ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_idle_timeout, ")
- ACE_TEXT ("idle_timeout, transport is not idle, don't close it\n"),
- this->id ()));
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_idle_timeout, ")
+ ACE_TEXT ("idle_timeout, transport is not purgable, don't close it\n"),
+ this->id ()));
- return 0; // Raced — transport is busy now; leave it open
- }
+ return 0; // Raced — transport is busy now; leave it open
+ }
}
// Purge from cache then close the underlying socket.
@@ -2860,8 +2868,7 @@ TAO_Transport::post_open (size_t id)
ACE_TEXT (", cache_map_entry_ is [%@]\n"), this->id_, this->cache_map_entry_));
}
- this->transport_cache_manager ().mark_connected (this->cache_map_entry_,
- true);
+ this->transport_cache_manager ().mark_connected (this->cache_map_entry_, true);
// update transport cache to make this entry available
this->transport_cache_manager ().set_entry_state (this->cache_map_entry_, TAO::ENTRY_IDLE_AND_PURGABLE);
@@ -2934,17 +2941,30 @@ TAO_Transport::schedule_idle_timer ()
int const timeout_sec = this->orb_core_->resource_factory ()->transport_idle_timeout ();
if (timeout_sec > 0)
{
- ACE_Reactor *reactor = this->orb_core_->reactor ();
- const ACE_Time_Value tv (static_cast (timeout_sec));
- this->idle_timer_id_= reactor->schedule_timer (std::addressof(this->transport_idle_timer_), nullptr, tv);
+ if (this->transport_cache_manager ().is_entry_purgable (this->cache_map_entry_))
+ {
+ ACE_Reactor *reactor = this->orb_core_->reactor ();
+ const ACE_Time_Value tv (static_cast (timeout_sec));
+ this->idle_timer_id_= reactor->schedule_timer (std::addressof(this->transport_idle_timer_), nullptr, tv);
- if (TAO_debug_level > 6)
+ if (TAO_debug_level > 6)
+ {
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::schedule_idle_timer, ")
+ ACE_TEXT ("schedule idle timer with id [%d] ")
+ ACE_TEXT ("in the reactor.\n"),
+ this->id (), this->idle_timer_id_));
+ }
+ }
+ else
{
- TAOLIB_ERROR ((LM_ERROR,
- ACE_TEXT ("TAO (%P|%t) - Transport[%d]::schedule_idle_timer , ")
- ACE_TEXT ("schedule idle timer with id [%d] ")
- ACE_TEXT ("in the reactor.\n"),
- this->id (), this->idle_timer_id_));
+ if (TAO_debug_level > 8)
+ {
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::schedule_idle_timer, ")
+ ACE_TEXT ("not scheduled idle timer because transport is not purgable\n"),
+ this->id ()));
+ }
}
}
}
@@ -2959,7 +2979,7 @@ TAO_Transport::cancel_idle_timer ()
{
if (TAO_debug_level > 6)
{
- TAOLIB_ERROR ((LM_ERROR,
+ TAOLIB_DEBUG ((LM_DEBUG,
ACE_TEXT ("TAO (%P|%t) - Transport[%d]::cancel_idle_timer, ")
ACE_TEXT ("cancel idle timer with id [%d] ")
ACE_TEXT ("from the reactor.\n"),
diff --git a/TAO/tao/Transport_Cache_Manager_T.cpp b/TAO/tao/Transport_Cache_Manager_T.cpp
index 8d4ff973abb06..31c8d2d5d46b1 100644
--- a/TAO/tao/Transport_Cache_Manager_T.cpp
+++ b/TAO/tao/Transport_Cache_Manager_T.cpp
@@ -379,6 +379,20 @@ namespace TAO
return 0;
}
+ template
+ bool
+ Transport_Cache_Manager_T::is_entry_purgable (HASH_MAP_ENTRY *entry)
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Lock,
+ guard,
+ *this->cache_lock_, false));
+
+ if (entry == nullptr)
+ return false;
+
+ return this->is_entry_purgable_i (*entry);
+ }
+
template
int
Transport_Cache_Manager_T::update_entry (HASH_MAP_ENTRY *&entry)
diff --git a/TAO/tao/Transport_Cache_Manager_T.h b/TAO/tao/Transport_Cache_Manager_T.h
index 6d80ecb7e2037..616968a34535b 100644
--- a/TAO/tao/Transport_Cache_Manager_T.h
+++ b/TAO/tao/Transport_Cache_Manager_T.h
@@ -169,6 +169,11 @@ namespace TAO
/// Return the underlying cache map
HASH_MAP &map ();
+ /**
+ * Tries to find if the @c int_id_ in @a entry is purgable
+ */
+ bool is_entry_purgable (HASH_MAP_ENTRY* entry);
+
private:
/// Lookup entry in the cache. Grabs the lock and calls the
/// implementation function find_i.
From 101a7ef97c418c3cde0224cc1794a97544123d02 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Wed, 1 Apr 2026 13:12:39 +0200
Subject: [PATCH 26/37] Always schedule the timer
* TAO/tao/Transport.cpp:
---
TAO/tao/Transport.cpp | 39 ++++++++++++++-------------------------
1 file changed, 14 insertions(+), 25 deletions(-)
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index 0fabb78c01db3..b3331a6b127a6 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -998,7 +998,7 @@ TAO_Transport::handle_idle_timeout (const ACE_Time_Value & /* current_time */, c
// Timer has expired, so setting the idle timer id back to -1
this->idle_timer_id_ = -1;
- // Confirm transport is still idle under the handler lock to
+ // Confirm transport is purgable under the handler lock to
// prevent a race with find_idle_transport_i().
{
ACE_GUARD_RETURN (ACE_Lock, mon, *this->handler_lock_, 0);
@@ -1007,10 +1007,12 @@ TAO_Transport::handle_idle_timeout (const ACE_Time_Value & /* current_time */, c
if (TAO_debug_level > 0)
TAOLIB_DEBUG ((LM_DEBUG,
ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_idle_timeout, ")
- ACE_TEXT ("idle_timeout, transport is not purgable, don't close it\n"),
+ ACE_TEXT ("idle_timeout, transport is not purgable, don't close it, reschedule it\n"),
this->id ()));
- return 0; // Raced — transport is busy now; leave it open
+ this->schedule_idle_timer ();
+
+ return 0;
}
}
@@ -2941,30 +2943,17 @@ TAO_Transport::schedule_idle_timer ()
int const timeout_sec = this->orb_core_->resource_factory ()->transport_idle_timeout ();
if (timeout_sec > 0)
{
- if (this->transport_cache_manager ().is_entry_purgable (this->cache_map_entry_))
- {
- ACE_Reactor *reactor = this->orb_core_->reactor ();
- const ACE_Time_Value tv (static_cast (timeout_sec));
- this->idle_timer_id_= reactor->schedule_timer (std::addressof(this->transport_idle_timer_), nullptr, tv);
+ ACE_Reactor *reactor = this->orb_core_->reactor ();
+ const ACE_Time_Value tv (static_cast (timeout_sec));
+ this->idle_timer_id_= reactor->schedule_timer (std::addressof(this->transport_idle_timer_), nullptr, tv);
- if (TAO_debug_level > 6)
- {
- TAOLIB_DEBUG ((LM_DEBUG,
- ACE_TEXT ("TAO (%P|%t) - Transport[%d]::schedule_idle_timer, ")
- ACE_TEXT ("schedule idle timer with id [%d] ")
- ACE_TEXT ("in the reactor.\n"),
- this->id (), this->idle_timer_id_));
- }
- }
- else
+ if (TAO_debug_level > 6)
{
- if (TAO_debug_level > 8)
- {
- TAOLIB_DEBUG ((LM_DEBUG,
- ACE_TEXT ("TAO (%P|%t) - Transport[%d]::schedule_idle_timer, ")
- ACE_TEXT ("not scheduled idle timer because transport is not purgable\n"),
- this->id ()));
- }
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::schedule_idle_timer, ")
+ ACE_TEXT ("schedule idle timer with id [%d] ")
+ ACE_TEXT ("in the reactor.\n"),
+ this->id (), this->idle_timer_id_));
}
}
}
From 71166a816c7b12ca92df60b9d94248b7b0d7f4fd Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Wed, 1 Apr 2026 13:21:04 +0200
Subject: [PATCH 27/37] Test fixes
* TAO/tests/Transport_Idle_Timeout/Echo_i.cpp:
* TAO/tests/Transport_Idle_Timeout/client_multiple.cpp:
* TAO/tests/Transport_Idle_Timeout/run_test.pl:
---
TAO/tests/Transport_Idle_Timeout/Echo_i.cpp | 2 +-
.../client_multiple.cpp | 4 +++-
TAO/tests/Transport_Idle_Timeout/run_test.pl | 22 +++++++++----------
3 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
index 1c8d2888d56b8..075db6a42b542 100644
--- a/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/Echo_i.cpp
@@ -73,7 +73,7 @@ Echo_i::ping (::CORBA::Long sleep_time, ::CORBA::Long cache_size_expected, ::Tes
{
sleep_with_reactor (this->orb_, sleep_time_server);
}
- ok &= check ("ping", cache_size(this->orb_), cache_size_expected2);
+ ok &= check ("ping_second", cache_size(this->orb_), cache_size_expected2);
}
else
{
diff --git a/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp b/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp
index b337378fd76b2..a3bf41fcd8a01 100644
--- a/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp
+++ b/TAO/tests/Transport_Idle_Timeout/client_multiple.cpp
@@ -160,7 +160,9 @@ tc1_basic_idle_close (CORBA::ORB_ptr orb, Test::Echo_ptr echo, Test::Echo_ptr ec
// Make another call, but let wait sleep_sec after the ping to the second server,
// which means the call takes longer as the idle time.
// at that moment the cache should be 1, this means the call takes longer as the idle time,
- ok &= echo->ping (0, 2, echo2, sleep_sec, 0);
+ ok &= echo->ping (0, 2, echo2, sleep_sec, 1);
+
+ ok &= check ("TC-1 after ping longer as timeout (expect 1)", cache_size(orb), 1);
return ok;
}
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
index 14122a655cf99..982bda36a28fa 100755
--- a/TAO/tests/Transport_Idle_Timeout/run_test.pl
+++ b/TAO/tests/Transport_Idle_Timeout/run_test.pl
@@ -226,23 +226,23 @@ sub run_multiple_scenario {
# ---------------------------------------------------------------------------
# Scenario 1: TC-1, TC-2, TC-3 (timeout enabled)
# ---------------------------------------------------------------------------
-# run_scenario (
-# "TC-1/TC-2/TC-3: idle timeout enabled (${timeout_sec}s)",
-# "svc.conf",
-# ""
-# );
+run_scenario (
+ "TC-1/TC-2/TC-3: idle timeout enabled (${timeout_sec}s)",
+ "svc.conf",
+ ""
+);
# ---------------------------------------------------------------------------
# Scenario 2: TC-4 (timeout disabled)
# ---------------------------------------------------------------------------
-# run_scenario (
-# "TC-4: idle timeout disabled",
-# "svc_disabled.conf",
-# "-d"
-# );
+run_scenario (
+ "TC-4: idle timeout disabled",
+ "svc_disabled.conf",
+ "-d"
+);
run_multiple_scenario (
- "TC-1/TC-2/TC-3: idle timeout enabled (${timeout_sec}s)",
+ "TC-1/TC-2/TC-3: multiple idle timeout enabled (${timeout_sec}s)",
"svc.conf",
""
);
From db2dd465cdb91bbdae683b482eddbdca260a598f Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Wed, 1 Apr 2026 15:53:04 +0200
Subject: [PATCH 28/37] Rework for thread safety
* TAO/tao/Transport.cpp:
* TAO/tao/Transport_Cache_Manager_T.cpp:
* TAO/tao/Transport_Cache_Manager_T.h:
* TAO/tao/Transport_Cache_Manager_T.inl:
* TAO/tao/Transport_Connector.cpp:
---
TAO/tao/Transport.cpp | 42 ++++++++++++++-------------
TAO/tao/Transport_Cache_Manager_T.cpp | 18 ++----------
TAO/tao/Transport_Cache_Manager_T.h | 8 ++---
TAO/tao/Transport_Cache_Manager_T.inl | 36 +++++++++++++++++++++++
TAO/tao/Transport_Connector.cpp | 1 -
5 files changed, 64 insertions(+), 41 deletions(-)
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index b3331a6b127a6..56d180f2c46f0 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -187,6 +187,8 @@ TAO_Transport::~TAO_Transport ()
this->id_));
}
+ this->cancel_idle_timer ();
+
delete this->messaging_object_;
delete this->ws_;
@@ -998,28 +1000,28 @@ TAO_Transport::handle_idle_timeout (const ACE_Time_Value & /* current_time */, c
// Timer has expired, so setting the idle timer id back to -1
this->idle_timer_id_ = -1;
- // Confirm transport is purgable under the handler lock to
- // prevent a race with find_idle_transport_i().
- {
- ACE_GUARD_RETURN (ACE_Lock, mon, *this->handler_lock_, 0);
- if (!this->transport_cache_manager ().is_entry_purgable (this->cache_map_entry_))
- {
- if (TAO_debug_level > 0)
- TAOLIB_DEBUG ((LM_DEBUG,
- ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_idle_timeout, ")
- ACE_TEXT ("idle_timeout, transport is not purgable, don't close it, reschedule it\n"),
- this->id ()));
-
- this->schedule_idle_timer ();
+ if (this->transport_cache_manager ().purge_entry_when_purgable (this->cache_map_entry_) == -1)
+ {
+ if (TAO_debug_level > 6)
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_idle_timeout, ")
+ ACE_TEXT ("idle_timeout, transport is not purgable, don't close it, reschedule it\n"),
+ this->id ()));
- return 0;
- }
- }
+ this->schedule_idle_timer ();
+ }
+ else
+ {
+ if (TAO_debug_level > 6)
+ TAOLIB_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_idle_timeout, ")
+ ACE_TEXT ("idle_timeout, transport purged due to idle timeout\n"),
+ this->id ()));
- // Purge from cache then close the underlying socket.
- // close_connection() is safe to call from the reactor thread.
- (void) this->purge_entry ();
- (void) this->close_connection ();
+ // Close the underlying socket.
+ // close_connection() is safe to call from the reactor thread.
+ (void) this->close_connection ();
+ }
return 0;
}
diff --git a/TAO/tao/Transport_Cache_Manager_T.cpp b/TAO/tao/Transport_Cache_Manager_T.cpp
index 31c8d2d5d46b1..571b344634018 100644
--- a/TAO/tao/Transport_Cache_Manager_T.cpp
+++ b/TAO/tao/Transport_Cache_Manager_T.cpp
@@ -379,20 +379,6 @@ namespace TAO
return 0;
}
- template
- bool
- Transport_Cache_Manager_T::is_entry_purgable (HASH_MAP_ENTRY *entry)
- {
- ACE_MT (ACE_GUARD_RETURN (ACE_Lock,
- guard,
- *this->cache_lock_, false));
-
- if (entry == nullptr)
- return false;
-
- return this->is_entry_purgable_i (*entry);
- }
-
template
int
Transport_Cache_Manager_T::update_entry (HASH_MAP_ENTRY *&entry)
@@ -454,7 +440,9 @@ namespace TAO
// Do not mark the entry as closed if we don't have a
// blockable handler added
if (retval)
- (*iter).int_id_.recycle_state (ENTRY_CLOSED);
+ {
+ (*iter).int_id_.recycle_state (ENTRY_CLOSED);
+ }
}
return true;
diff --git a/TAO/tao/Transport_Cache_Manager_T.h b/TAO/tao/Transport_Cache_Manager_T.h
index 616968a34535b..d252e765575ce 100644
--- a/TAO/tao/Transport_Cache_Manager_T.h
+++ b/TAO/tao/Transport_Cache_Manager_T.h
@@ -127,6 +127,9 @@ namespace TAO
/// Purge the entry from the Cache Map
int purge_entry (HASH_MAP_ENTRY *& entry);
+ /// Purge the entry from the Cache Map only when the entry is purgable
+ int purge_entry_when_purgable (HASH_MAP_ENTRY *& entry);
+
/// Mark the entry as connected.
void mark_connected (HASH_MAP_ENTRY *& entry, bool state);
@@ -169,11 +172,6 @@ namespace TAO
/// Return the underlying cache map
HASH_MAP &map ();
- /**
- * Tries to find if the @c int_id_ in @a entry is purgable
- */
- bool is_entry_purgable (HASH_MAP_ENTRY* entry);
-
private:
/// Lookup entry in the cache. Grabs the lock and calls the
/// implementation function find_i.
diff --git a/TAO/tao/Transport_Cache_Manager_T.inl b/TAO/tao/Transport_Cache_Manager_T.inl
index 894d19fc3da00..1f2f56d7f0b5f 100644
--- a/TAO/tao/Transport_Cache_Manager_T.inl
+++ b/TAO/tao/Transport_Cache_Manager_T.inl
@@ -60,6 +60,42 @@ namespace TAO
return retval;
}
+ template
+ ACE_INLINE int
+ Transport_Cache_Manager_T::purge_entry_when_purgable (HASH_MAP_ENTRY *&entry)
+ {
+ int retval = 0;
+
+ if (entry != 0)
+ {
+ HASH_MAP_ENTRY* cached_entry = 0;
+ ACE_MT (ACE_GUARD_RETURN (ACE_Lock, guard, *this->cache_lock_, -1));
+ if (entry != 0) // in case someone beat us to it (entry is reference to transport member)
+ {
+ // Only purge the entry when it is purgable
+ if (this->is_entry_purgable_i (*entry))
+ {
+ // Store the entry in a temporary and zero out the reference.
+ // If there is only one reference count for the transport, we will end up causing
+ // it's destruction. And the transport can not be holding a cache map entry if
+ // that happens.
+ cached_entry = entry;
+ entry = 0;
+
+ // now it's save to really purge the entry
+ retval = this->purge_entry_i (cached_entry);
+ }
+ else
+ {
+ // Entry is not purgable at this moment
+ retval = -1;
+ }
+ }
+ }
+
+ return retval;
+ }
+
template
ACE_INLINE void
Transport_Cache_Manager_T::mark_connected (HASH_MAP_ENTRY *&entry, bool state)
diff --git a/TAO/tao/Transport_Connector.cpp b/TAO/tao/Transport_Connector.cpp
index f4b9aaeccf11d..56cd323040045 100644
--- a/TAO/tao/Transport_Connector.cpp
+++ b/TAO/tao/Transport_Connector.cpp
@@ -328,7 +328,6 @@ TAO_Connector::parallel_connect (TAO::Profile_Transport_Resolver *r,
// connection establishment. Maybe a custom wait strategy is needed
// at this point to register several potential transports so that
// when one succeeds the rest are cancelled or closed.
-
unsigned int endpoint_count = 0;
for (TAO_Endpoint *ep = root_ep->next_filtered (this->orb_core(),nullptr);
ep != nullptr;
From 630ec1e4b761af6527d6a25e0d7dd0bfec0477d2 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 3 Apr 2026 09:22:26 +0200
Subject: [PATCH 29/37] Removed empty line
* TAO/tao/Cache_Entries_T.inl:
---
TAO/tao/Cache_Entries_T.inl | 1 -
1 file changed, 1 deletion(-)
diff --git a/TAO/tao/Cache_Entries_T.inl b/TAO/tao/Cache_Entries_T.inl
index 1472f36a051f4..46831d312b256 100644
--- a/TAO/tao/Cache_Entries_T.inl
+++ b/TAO/tao/Cache_Entries_T.inl
@@ -112,7 +112,6 @@ namespace TAO
is_delete_ (false),
index_ (0)
{
-
}
template ACE_INLINE
From b9fbb69fd9fceb78ce042d2b955e59a4ff644ab5 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 3 Apr 2026 09:42:42 +0200
Subject: [PATCH 30/37] Update TAO/tests/Transport_Idle_Timeout/run_test.pl
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---
TAO/tests/Transport_Idle_Timeout/run_test.pl | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
index 982bda36a28fa..becfb2f4db06e 100755
--- a/TAO/tests/Transport_Idle_Timeout/run_test.pl
+++ b/TAO/tests/Transport_Idle_Timeout/run_test.pl
@@ -226,7 +226,7 @@ sub run_multiple_scenario {
# ---------------------------------------------------------------------------
# Scenario 1: TC-1, TC-2, TC-3 (timeout enabled)
# ---------------------------------------------------------------------------
-run_scenario (
+$status = 1 if run_scenario (
"TC-1/TC-2/TC-3: idle timeout enabled (${timeout_sec}s)",
"svc.conf",
""
@@ -235,13 +235,13 @@ sub run_multiple_scenario {
# ---------------------------------------------------------------------------
# Scenario 2: TC-4 (timeout disabled)
# ---------------------------------------------------------------------------
-run_scenario (
+$status = 1 if run_scenario (
"TC-4: idle timeout disabled",
"svc_disabled.conf",
"-d"
);
-run_multiple_scenario (
+$status = 1 if run_multiple_scenario (
"TC-1/TC-2/TC-3: multiple idle timeout enabled (${timeout_sec}s)",
"svc.conf",
""
From def90e136e82f37a73ec2f0ac0e5792dd0e7f345 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 3 Apr 2026 09:43:02 +0200
Subject: [PATCH 31/37] Update TAO/tests/Transport_Idle_Timeout/svc.conf
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---
TAO/tests/Transport_Idle_Timeout/svc.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/svc.conf b/TAO/tests/Transport_Idle_Timeout/svc.conf
index 5669ac1eef86a..7bfea6122334e 100644
--- a/TAO/tests/Transport_Idle_Timeout/svc.conf
+++ b/TAO/tests/Transport_Idle_Timeout/svc.conf
@@ -1,4 +1,4 @@
# Used by server and client for TC-1, TC-2, TC-3.
-# Sets a short idle timeout (2 seconds) so the test completes quickly.
+# Sets a short idle timeout (3 seconds) so the test completes quickly.
static Resource_Factory "-ORBTransportIdleTimeout 3"
From b94d846f918dde5cd0e9939c0b9471e74c2179bd Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 3 Apr 2026 09:45:01 +0200
Subject: [PATCH 32/37] fixe
* TAO/tao/tao.mpc:
---
TAO/tao/tao.mpc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TAO/tao/tao.mpc b/TAO/tao/tao.mpc
index 5ce2243e0380a..c845d714decac 100644
--- a/TAO/tao/tao.mpc
+++ b/TAO/tao/tao.mpc
@@ -634,7 +634,7 @@ project(TAO) : acelib, install, tao_output, taodefaults, pidl, extra_core, taoid
Transport_Cache_Manager_T.h
Transport_Connector.h
Transport_Descriptor_Interface.h
- Transport_Idle_Timer.cpp
+ Transport_Idle_Timer.h
Transport.h
Transport_Mux_Strategy.h
Transport_Queueing_Strategies.h
From cc41da5719029238313554a650815af77e19e9d0 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 3 Apr 2026 09:55:04 +0200
Subject: [PATCH 33/37] Return value changes
* TAO/tests/Transport_Idle_Timeout/run_test.pl:
---
TAO/tests/Transport_Idle_Timeout/run_test.pl | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
index becfb2f4db06e..d9bed2a502368 100755
--- a/TAO/tests/Transport_Idle_Timeout/run_test.pl
+++ b/TAO/tests/Transport_Idle_Timeout/run_test.pl
@@ -90,20 +90,20 @@ sub run_scenario {
+ $client_budget);
if ($client_status != 0) {
print STDERR "ERROR: client returned $client_status\n";
- $status = 1;
+ return 1;
}
# Wait for server to exit (it calls orb->shutdown() on receiving shutdown())
my $server_exit = $SV->WaitKill ($server->ProcessStopWaitInterval ());
if ($server_exit != 0) {
print STDERR "ERROR: server returned $server_exit\n";
- $status = 1;
+ return 1;
}
$server->DeleteFile ($ior_file1);
$client->DeleteFile ($ior_file1);
- return $status;
+ return 1;
}
sub run_multiple_scenario {
@@ -199,20 +199,20 @@ sub run_multiple_scenario {
+ $client_budget);
if ($client_status != 0) {
print STDERR "ERROR: client returned $client_status\n";
- $status = 1;
+ return 1;
}
# Wait for server 1 to exit (it calls orb->shutdown() on receiving shutdown())
my $server_exit1 = $SV1->WaitKill ($server1->ProcessStopWaitInterval ());
if ($server_exit1 != 0) {
print STDERR "ERROR: server1 returned $server_exit1\n";
- $status = 1;
+ return 1;
}
# Wait for server 2 to exit (it calls orb->shutdown() on receiving shutdown())
my $server_exit2 = $SV2->WaitKill ($server2->ProcessStopWaitInterval ());
if ($server_exit2 != 0) {
print STDERR "ERROR: server2 returned $server_exit2\n";
- $status = 1;
+ return 1;
}
$server1->DeleteFile ($ior_file1);
@@ -220,7 +220,7 @@ sub run_multiple_scenario {
$client->DeleteFile ($ior_file1);
$client->DeleteFile ($ior_file2);
- return $status;
+ return 1;
}
# ---------------------------------------------------------------------------
From 7c944d4cb6ff3b132c971337826e35c5f9b8dda4 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 3 Apr 2026 10:14:43 +0200
Subject: [PATCH 34/37] Revert change
* TAO/tests/Transport_Idle_Timeout/run_test.pl:
---
TAO/tests/Transport_Idle_Timeout/run_test.pl | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/TAO/tests/Transport_Idle_Timeout/run_test.pl b/TAO/tests/Transport_Idle_Timeout/run_test.pl
index d9bed2a502368..becfb2f4db06e 100755
--- a/TAO/tests/Transport_Idle_Timeout/run_test.pl
+++ b/TAO/tests/Transport_Idle_Timeout/run_test.pl
@@ -90,20 +90,20 @@ sub run_scenario {
+ $client_budget);
if ($client_status != 0) {
print STDERR "ERROR: client returned $client_status\n";
- return 1;
+ $status = 1;
}
# Wait for server to exit (it calls orb->shutdown() on receiving shutdown())
my $server_exit = $SV->WaitKill ($server->ProcessStopWaitInterval ());
if ($server_exit != 0) {
print STDERR "ERROR: server returned $server_exit\n";
- return 1;
+ $status = 1;
}
$server->DeleteFile ($ior_file1);
$client->DeleteFile ($ior_file1);
- return 1;
+ return $status;
}
sub run_multiple_scenario {
@@ -199,20 +199,20 @@ sub run_multiple_scenario {
+ $client_budget);
if ($client_status != 0) {
print STDERR "ERROR: client returned $client_status\n";
- return 1;
+ $status = 1;
}
# Wait for server 1 to exit (it calls orb->shutdown() on receiving shutdown())
my $server_exit1 = $SV1->WaitKill ($server1->ProcessStopWaitInterval ());
if ($server_exit1 != 0) {
print STDERR "ERROR: server1 returned $server_exit1\n";
- return 1;
+ $status = 1;
}
# Wait for server 2 to exit (it calls orb->shutdown() on receiving shutdown())
my $server_exit2 = $SV2->WaitKill ($server2->ProcessStopWaitInterval ());
if ($server_exit2 != 0) {
print STDERR "ERROR: server2 returned $server_exit2\n";
- return 1;
+ $status = 1;
}
$server1->DeleteFile ($ior_file1);
@@ -220,7 +220,7 @@ sub run_multiple_scenario {
$client->DeleteFile ($ior_file1);
$client->DeleteFile ($ior_file2);
- return 1;
+ return $status;
}
# ---------------------------------------------------------------------------
From 9ca5ffb1d05b9768dd4b581de42a07d4d54e079b Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 3 Apr 2026 11:48:28 +0200
Subject: [PATCH 35/37] Removed todo
* TAO/tao/Transport.cpp:
---
TAO/tao/Transport.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index 56d180f2c46f0..024769b6eed13 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -581,7 +581,6 @@ TAO_Transport::update_transport ()
this->id ()));
}
- // @todo jwi timer update????
return this->transport_cache_manager ().update_entry (this->cache_map_entry_);
}
From 812c76ec7875a0f64aa3999e8d2df41ab89a09e5 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 3 Apr 2026 11:50:25 +0200
Subject: [PATCH 36/37] Removed not used is_idle
* TAO/tao/Transport_Cache_Manager_T.h:
* TAO/tao/Transport_Cache_Manager_T.inl:
---
TAO/tao/Transport_Cache_Manager_T.h | 3 ---
TAO/tao/Transport_Cache_Manager_T.inl | 12 ------------
2 files changed, 15 deletions(-)
diff --git a/TAO/tao/Transport_Cache_Manager_T.h b/TAO/tao/Transport_Cache_Manager_T.h
index d252e765575ce..fd4e6a8047e14 100644
--- a/TAO/tao/Transport_Cache_Manager_T.h
+++ b/TAO/tao/Transport_Cache_Manager_T.h
@@ -136,9 +136,6 @@ namespace TAO
/// Make the entry idle and ready for use.
int make_idle (HASH_MAP_ENTRY *&entry);
- /// Check if the entry is idle
- bool is_idle (HASH_MAP_ENTRY *&entry) const;
-
/// Modify the state setting on the provided entry.
void set_entry_state (HASH_MAP_ENTRY *&entry,
TAO::Cache_Entries_State state);
diff --git a/TAO/tao/Transport_Cache_Manager_T.inl b/TAO/tao/Transport_Cache_Manager_T.inl
index 1f2f56d7f0b5f..3845092e11fe4 100644
--- a/TAO/tao/Transport_Cache_Manager_T.inl
+++ b/TAO/tao/Transport_Cache_Manager_T.inl
@@ -123,18 +123,6 @@ namespace TAO
return this->make_idle_i (entry);
}
- template
- ACE_INLINE bool
- Transport_Cache_Manager_T::is_idle (HASH_MAP_ENTRY *&entry) const
- {
- ACE_MT (ACE_GUARD_RETURN (ACE_Lock, guard, *this->cache_lock_, false));
- if (entry == nullptr) // in case someone beat us to it (entry is reference to transport member)
- return false;
-
- // @todo check if the state is idle and purgable, if so, then make the state so that it can't be used to make this atomic
- return entry->item ().recycle_state () == ENTRY_IDLE_AND_PURGABLE;
- }
-
template
ACE_INLINE typename Transport_Cache_Manager_T::Find_Result
Transport_Cache_Manager_T::find (transport_descriptor_type *prop,
From d6d34dc8eb28e8adef669d158b5be45216a6bd72 Mon Sep 17 00:00:00 2001
From: Johnny Willemsen
Date: Fri, 3 Apr 2026 12:01:04 +0200
Subject: [PATCH 37/37] Fixed typo
* TAO/tao/Transport.cpp:
---
TAO/tao/Transport.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp
index 024769b6eed13..2251b51177be9 100644
--- a/TAO/tao/Transport.cpp
+++ b/TAO/tao/Transport.cpp
@@ -338,7 +338,7 @@ TAO_Transport::close_connection ()
this->id ()));
}
- // Cancel any pending time
+ // Cancel any pending timer
this->cancel_idle_timer ();
this->connection_handler_i ()->close_connection ();