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 @@

1.1. Resource_Factory

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 ();