diff options
author | coryan <coryan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2009-05-25 21:57:28 +0000 |
---|---|---|
committer | coryan <coryan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2009-05-25 21:57:28 +0000 |
commit | ad4a1e3302a63ecd37be7d15fe96e20095ccd37c (patch) | |
tree | 60d0260aed71daac00f76b3f09747eae470d06d3 | |
parent | b3d258af06fa034e122d70733e18954da6a61246 (diff) | |
download | ATCD-ad4a1e3302a63ecd37be7d15fe96e20095ccd37c.tar.gz |
Mon May 25 19:05:22 UTC 2009 Carlos O'Ryan <coryan@atdesk.com>
-rw-r--r-- | TAO/ChangeLog | 124 | ||||
-rw-r--r-- | TAO/bin/tao_orb_tests.lst | 1 | ||||
-rw-r--r-- | TAO/tao/Block_Flushing_Strategy.cpp | 12 | ||||
-rw-r--r-- | TAO/tao/Connection_Handler.cpp | 4 | ||||
-rw-r--r-- | TAO/tao/GIOP_Message_Base.cpp | 19 | ||||
-rw-r--r-- | TAO/tao/Transport.cpp | 93 | ||||
-rw-r--r-- | TAO/tao/Transport.h | 133 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/Backend_Impl.cpp | 66 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/Backend_Impl.h | 37 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/Bug_3647_Regression.mpc | 52 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/Middle_Impl.cpp | 96 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/Middle_Impl.h | 46 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/README | 32 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/Test.idl | 48 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/backend_server.cpp | 120 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/client.cpp | 147 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/middle_server.cpp | 221 | ||||
-rwxr-xr-x | TAO/tests/Bug_3647_Regression/run_test.pl | 149 | ||||
-rw-r--r-- | TAO/tests/Bug_3647_Regression/svc.conf | 6 |
19 files changed, 1349 insertions, 57 deletions
diff --git a/TAO/ChangeLog b/TAO/ChangeLog index 168f082568d..6e84850133b 100644 --- a/TAO/ChangeLog +++ b/TAO/ChangeLog @@ -1,3 +1,127 @@ +Mon May 25 19:05:22 UTC 2009 Carlos O'Ryan <coryan@atdesk.com> + + * Fixed bug #3647. In this commit I am merging the changes form + the Bug_3647_Regression branch. The exact command used to merge + the changes was: + $ svn merge --accept postpone -r85163:HEAD \ + https://svn.dre.vanderbilt.edu/DOC/Middleware/\ + branches/Bug_3647_Regression . + + The typical conflict in the ChangeLog was manually resolved. + + * bin/tao_orb_tests.lst: + Add the new test, in alphabetical order, preserve tests added in + trunk. + + * tao/Transport.h: + * tao/Transport.cpp: + Restore the ACE_Countdown_Time object in drain_queue_helper(). + I removed it because I thought there were no side effects and it + was not needed, but after Johnny W asked, I realised it was + indeed important. + The header changes are required because the Drain_Constraints + object needs a non-const ACE_Time_Value* parameter now. + + * tests/Bug_3647_Regression/Backend_Impl.cpp: + * tests/Bug_3647_Regression/backend_server.cpp: + * tests/Bug_3647_Regression/Backend_Impl.hpp: + * tests/Bug_3647_Regression/Backend_Impl.h: + * tests/Bug_3647_Regression/Middle_Impl.cpp: + * tests/Bug_3647_Regression/Throw_Spec.h: + * tests/Bug_3647_Regression/Middle_Impl.hpp: + * tests/Bug_3647_Regression/middle_server.cpp: + * tests/Bug_3647_Regression/Middle_Impl.h: + I used a hacky macro to compile this code with both + TAO-1.5.1 (need throw specs) and TAO-1.6.9 (cannot have throw + specs) + I also changed the .hpp files to .h to be less consistent with + the .cpp files, but more consistent with the rest of ACE+TAO. + Thanks to Johnny to point out the ugliness before it reached the + main branch. + + * tao/Transport.h: + * tao/Transport.cpp: + * tao/GIOP_Message_Base.cpp: + * tao/Block_Flushing_Strategy.cpp: + * tao/Connection_Handler.cpp: + Seemingly completed the fixes for 3647. + Fundamentally, the calls to sendv() need to use a timeout + parameter when called with the blocking flushing strategy or + with the read-write waiting strategy *and* when there is a + timeout. + Unfortunately, the point(s) where we call sendv() does not have + enough context to determine if the parameter is needed. + I changed the Transport class to pass a little struct with both + the timeout value and flag to indicate if using blocking I/O + calls was desired. + The caller makes the determination and passes the parameter into + the Transport object, for example, the Block_Flushing_Strategy + certainly wants to use blocking I/O calls. + Several interface in TAO_Transport changed, and so did its + callers. + + * tests/Bug_3647_Regression/client.cpp: + * tests/Bug_3647_Regression/Middle_Impl.cpp: + * tests/Bug_3647_Regression/Backend_Impl.cpp: + * tests/Bug_3647_Regression/run_test.pl: + Fine-tune the test so it would pass all the time. The default + parameters showed the problem before the changes, but then + failed due to a timeout during shutdown. + Also expanded run_test.pl to test with SYNC_NONE vs. other + policies. It was important to me to verify that the test + continues to fail with SYNC_WITH_SERVER, so my "fine tuning" did + not hide real errors. + + * tao/Transport.h: + * tao/Transport.cpp: + First attempt at fixing bug 3647. + The ORB is blocking in ACE::sendv(), because we are passing a + timeout parameter which results in blocking for the prescribed + timeout period on select(). But on a select() call with only + one socket! + What we want to achieve is pass the timeout parameter when we + are using the blocking configurations of the ORB, such as RW + waiting strategies. + This fix, changes the way the timeout parameter to sendv() calls + is computed, by looking at the wait_strategy. + Unfortunately, this missed the blocking flushing strategies, + where we want to block too! The Oneway_Send_Timeout tests + caught this. + So more work is needed, but I want to save the work first. + + * tests/Bug_3647_Regression: + * tests/Bug_3647_Regression/Bug_3647_Regression.mpc: + * tests/Bug_3647_Regression/run_test.pl: + * tests/Bug_3647_Regression/README: + * tests/Bug_3647_Regression/svc.conf: + * tests/Bug_3647_Regression/Test.idl: + * tests/Bug_3647_Regression/Throw_Spec.h: + Add a regression test for bug #3647. The test consists of three + processeses: + + * tests/Bug_3647_Regression/Backend_Impl.hpp: + * tests/Bug_3647_Regression/Backend_Impl.cpp: + * tests/Bug_3647_Regression/backend_server.cpp: + The backend server receives oneway calls. On request, it calls + sleep for a long period of time to block its I/O on particular + sockets. + + * tests/Bug_3647_Regression/Middle_Impl.hpp: + * tests/Bug_3647_Regression/Middle_Impl.cpp: + * tests/Bug_3647_Regression/middle_server.cpp: + A middle tier server, which never calls sleep, but because of + bug 3647 it blocks trying to make calls on the backend server, + though it should not. + + * tests/Bug_3647_Regression/client.cpp: + The client coordinates the work. It setups connections between + all the servers and makes calls on the middle tier server. It + expects the middle tier server to be always available, but it + did not before the fixes. + + * bin/tao_orb_tests.lst: + Add Bug_3647_Regression to the list. + Mon May 24 14:26:43 UTC 2009 Johnny Willemsen <jwillemsen@remedy.nl> * tests/Bug_3672_Regression: diff --git a/TAO/bin/tao_orb_tests.lst b/TAO/bin/tao_orb_tests.lst index 1664f9e1868..4af13c5cce5 100644 --- a/TAO/bin/tao_orb_tests.lst +++ b/TAO/bin/tao_orb_tests.lst @@ -157,6 +157,7 @@ TAO/tests/Bug_3598a_Regression/run_test.pl: !MINIMUM !CORBA_E_COMPACT !CORBA_E_M TAO/tests/Bug_3630_Regression/run_test.pl: !FIXED_BUGS_ONLY TAO/tests/Bug_3632_Regression/run_test.pl: TAO/tests/Bug_3636_Regression/run_test.pl: !FIXED_BUGS_ONLY +TAO/tests/Bug_3647_Regression/run_test.pl: TAO/tests/Bug_3674_Regression/run_test.pl: !MINIMUM !CORBA_E_COMPACT !CORBA_E_MICRO !DISABLE_INTERCEPTORS TAO/tests/Bug_3676_Regression/run_test.pl: TAO/tests/DIOP/run_test.pl: !ST !NO_DIOP !ACE_FOR_TAO !CORBA_E_MICRO !LabVIEW_RT !WinCE !FUZZ diff --git a/TAO/tao/Block_Flushing_Strategy.cpp b/TAO/tao/Block_Flushing_Strategy.cpp index f6ef164b948..397e4717006 100644 --- a/TAO/tao/Block_Flushing_Strategy.cpp +++ b/TAO/tao/Block_Flushing_Strategy.cpp @@ -27,19 +27,23 @@ TAO_Block_Flushing_Strategy::flush_message (TAO_Transport *transport, { while (!msg->all_data_sent ()) { - if (transport->handle_output (max_wait_time) == -1) + TAO::Transport::Drain_Constraints dc( + max_wait_time, true); + if (transport->handle_output (dc) == -1) return -1; } return 0; } int -TAO_Block_Flushing_Strategy::flush_transport (TAO_Transport *transport - , ACE_Time_Value *max_wait_time) +TAO_Block_Flushing_Strategy::flush_transport (TAO_Transport *transport, + ACE_Time_Value *max_wait_time) { while (!transport->queue_is_empty ()) { - if (transport->handle_output (max_wait_time) == -1) + TAO::Transport::Drain_Constraints dc( + max_wait_time, true); + if (transport->handle_output (dc) == -1) return -1; } return 0; diff --git a/TAO/tao/Connection_Handler.cpp b/TAO/tao/Connection_Handler.cpp index 852e8557e5b..269ffd38024 100644 --- a/TAO/tao/Connection_Handler.cpp +++ b/TAO/tao/Connection_Handler.cpp @@ -206,7 +206,9 @@ TAO_Connection_Handler::handle_output_eh ( return return_value; } - return_value = this->transport ()->handle_output (0); + // The default constraints are to never block. + TAO::Transport::Drain_Constraints dc; + return_value = this->transport ()->handle_output (dc); this->pos_io_hook (return_value); diff --git a/TAO/tao/GIOP_Message_Base.cpp b/TAO/tao/GIOP_Message_Base.cpp index 249b77d1f5b..c93f6d9f35b 100644 --- a/TAO/tao/GIOP_Message_Base.cpp +++ b/TAO/tao/GIOP_Message_Base.cpp @@ -1437,25 +1437,6 @@ TAO_GIOP_Message_Base:: TAO_GIOP_MESSAGE_HEADER_LEN); } -#if 0 - // @@CJC I don't think we need this check b/c the transport's send() - // will simply return -1. However, I guess we could create something - // like TAO_Tranport::is_closed() that returns whether the connection - // is already closed. The problem with that, however, is that it's - // entirely possible that is_closed() could return TRUE, and then the - // transport could get closed down btw. the time it gets called and the - // time that the send actually occurs. - ACE_HANDLE which = transport->handle (); - if (which == ACE_INVALID_HANDLE) - { - if (TAO_debug_level > 0) - ACE_DEBUG ((LM_DEBUG, - ACE_TEXT ("TAO (%P|%t) TAO_GIOP_Message_Base::send_close_connection -") - ACE_TEXT (" connection already closed\n"))); - return; - } -#endif - ACE_Data_Block data_block (TAO_GIOP_MESSAGE_HEADER_LEN, ACE_Message_Block::MB_DATA, close_message, diff --git a/TAO/tao/Transport.cpp b/TAO/tao/Transport.cpp index 6a17d84b61c..d9e4d456e0b 100644 --- a/TAO/tao/Transport.cpp +++ b/TAO/tao/Transport.cpp @@ -401,7 +401,7 @@ TAO_Transport::sendfile (TAO_MMAP_Allocator * /* allocator */, iovec * iov, int iovcnt, size_t &bytes_transferred, - ACE_Time_Value const * timeout) + TAO::Transport::Drain_Constraints const & dc) { // Concrete pluggable transport doesn't implement sendfile(). // Fallback on TAO_Transport::send(). @@ -410,7 +410,8 @@ TAO_Transport::sendfile (TAO_MMAP_Allocator * /* allocator */, // implementation to this base class method, and leave any TCP // specific configuration out of this base class method. // -Ossama - return this->send (iov, iovcnt, bytes_transferred, timeout); + return this->send (iov, iovcnt, bytes_transferred, + this->io_timeout (dc)); } #endif /* TAO_HAS_SENDFILE==1 */ @@ -521,19 +522,23 @@ TAO_Transport::update_transport (void) * */ int -TAO_Transport::handle_output (ACE_Time_Value *max_wait_time) +TAO_Transport::handle_output (TAO::Transport::Drain_Constraints const & dc) { if (TAO_debug_level > 3) { ACE_DEBUG ((LM_DEBUG, - ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_output\n"), - this->id ())); + ACE_TEXT ("TAO (%P|%t) - Transport[%d]::handle_output" + " - block_on_io=%d, timeout=%d.%06d\n"), + this->id (), + dc.block_on_io(), + dc.timeout() ? dc.timeout()->sec() : -1, + dc.timeout() ? dc.timeout()->usec() : -1 )); } // The flushing strategy (potentially via the Reactor) wants to send // more data, first check if there is a current message that needs // more sending... - int const retval = this->drain_queue (max_wait_time); + int const retval = this->drain_queue (dc); if (TAO_debug_level > 3) { @@ -566,15 +571,18 @@ TAO_Transport::send_message_block_chain (const ACE_Message_Block *mb, { ACE_GUARD_RETURN (ACE_Lock, ace_mon, *this->handler_lock_, -1); + TAO::Transport::Drain_Constraints dc( + max_wait_time, true); + return this->send_message_block_chain_i (mb, bytes_transferred, - max_wait_time); + dc); } int TAO_Transport::send_message_block_chain_i (const ACE_Message_Block *mb, size_t &bytes_transferred, - ACE_Time_Value *max_wait_time) + TAO::Transport::Drain_Constraints const & dc) { size_t const total_length = mb->total_length (); @@ -584,7 +592,7 @@ TAO_Transport::send_message_block_chain_i (const ACE_Message_Block *mb, synch_message.push_back (this->head_, this->tail_); - int const n = this->drain_queue_i (max_wait_time); + int const n = this->drain_queue_i (dc); if (n == -1) { @@ -769,7 +777,10 @@ int TAO_Transport::send_synch_message_helper_i (TAO_Synch_Queued_Message &synch_message, ACE_Time_Value * max_wait_time) { - int const n = this->drain_queue_i (max_wait_time); + TAO::Transport::Drain_Constraints dc( + max_wait_time, this->using_blocking_io_for_synch_messages()); + + int const n = this->drain_queue_i (dc); if (n == -1) { @@ -890,10 +901,10 @@ TAO_Transport::handle_timeout (const ACE_Time_Value & /* current_time */, } int -TAO_Transport::drain_queue (ACE_Time_Value *max_wait_time) +TAO_Transport::drain_queue (TAO::Transport::Drain_Constraints const & dc) { ACE_GUARD_RETURN (ACE_Lock, ace_mon, *this->handler_lock_, -1); - int const retval = this->drain_queue_i (max_wait_time); + int const retval = this->drain_queue_i (dc); if (retval == 1) { @@ -911,10 +922,15 @@ TAO_Transport::drain_queue (ACE_Time_Value *max_wait_time) } int -TAO_Transport::drain_queue_helper (int &iovcnt, iovec iov[], ACE_Time_Value *max_wait_time) +TAO_Transport::drain_queue_helper (int &iovcnt, iovec iov[], + TAO::Transport::Drain_Constraints const & dc) { + // As a side-effect, this decrements the timeout() pointed-to value by + // the time used in this function. That might be important as there are + // potentially long running system calls invoked from here. + ACE_Countdown_Time countdown(dc.timeout()); + size_t byte_count = 0; - ACE_Countdown_Time countdown (max_wait_time); // ... send the message ... ssize_t retval = -1; @@ -924,10 +940,12 @@ TAO_Transport::drain_queue_helper (int &iovcnt, iovec iov[], ACE_Time_Value *max retval = this->sendfile (this->mmap_allocator_, iov, iovcnt, - byte_count); + byte_count, + dc); else #endif /* TAO_HAS_SENDFILE==1 */ - retval = this->send (iov, iovcnt, byte_count, max_wait_time); + retval = this->send (iov, iovcnt, byte_count, + this->io_timeout (dc)); if (TAO_debug_level == 5) { @@ -988,7 +1006,7 @@ TAO_Transport::drain_queue_helper (int &iovcnt, iovec iov[], ACE_Time_Value *max } int -TAO_Transport::drain_queue_i (ACE_Time_Value *max_wait_time) +TAO_Transport::drain_queue_i (TAO::Transport::Drain_Constraints const & dc) { // This is the vector used to send data, it must be declared outside // the loop because after the loop there may still be data to be @@ -1039,8 +1057,7 @@ TAO_Transport::drain_queue_i (ACE_Time_Value *max_wait_time) // IOV_MAX elements ... if (iovcnt == ACE_IOV_MAX) { - int const retval = this->drain_queue_helper (iovcnt, iov, - max_wait_time); + int const retval = this->drain_queue_helper (iovcnt, iov, dc); now = ACE_High_Res_Timer::gettimeofday_hr (); @@ -1067,7 +1084,7 @@ TAO_Transport::drain_queue_i (ACE_Time_Value *max_wait_time) if (iovcnt != 0) { - int const retval = this->drain_queue_helper (iovcnt, iov, max_wait_time); + int const retval = this->drain_queue_helper (iovcnt, iov, dc); if (TAO_debug_level > 4) { @@ -1345,6 +1362,9 @@ TAO_Transport::send_asynchronous_message_i (TAO_Stub *stub, bool partially_sent = false; bool timeout_encountered = false; + TAO::Transport::Drain_Constraints dc( + max_wait_time, this->using_blocking_io_for_asynch_messages()); + if (try_sending_first) { ssize_t n = 0; @@ -1367,7 +1387,7 @@ TAO_Transport::send_asynchronous_message_i (TAO_Stub *stub, // code I will re-visit this decision n = this->send_message_block_chain_i (message_block, byte_count, - max_wait_time); + dc); if (n == -1) { @@ -2755,6 +2775,37 @@ TAO_Transport::set_bidir_context_info (TAO_Operation_Details &) { } +ACE_Time_Value const * +TAO_Transport::io_timeout( + TAO::Transport::Drain_Constraints const & dc) const +{ + if (dc.block_on_io()) + { + return dc.timeout(); + } + if (this->wait_strategy()->can_process_upcalls()) + { + return 0; + } + return dc.timeout(); +} + +bool +TAO_Transport::using_blocking_io_for_synch_messages() const +{ + if (this->wait_strategy()->can_process_upcalls()) + { + return false; + } + return true; +} + +bool +TAO_Transport::using_blocking_io_for_asynch_messages() const +{ + return false; +} + /* * Hook to add concrete implementations from the derived class onto * TAO's transport. diff --git a/TAO/tao/Transport.h b/TAO/tao/Transport.h index f61d02827e5..e8d45fcd7e2 100644 --- a/TAO/tao/Transport.h +++ b/TAO/tao/Transport.h @@ -30,6 +30,7 @@ #include "tao/Message_Semantics.h" #include "ace/Time_Value.h" #include "ace/Basic_Stats.h" +#include "ace/Copy_Disabled.h" struct iovec; @@ -68,6 +69,80 @@ namespace TAO /// Transport-level statistics. Initially introduced to support /// the "Transport Current" functionality. class Stats; + + /** + * @struct Drain_Constraints + * + * @brief Encapsulate the flushing control parameters. + * + * At several points, the ORB needs to flush data from a transport to the + * underlying I/O mechanisms. How this data is flushed depends on the + * context where the request is made, the ORB configuration and the + * application level policies in effect. + * + * Some examples: + * + * # When idle, the ORB will want to send data on any socket that has + * space available. In this case, the queue must be drained on + * a best-effort basis, without any blocking. + * # If the ORB is configured to handle nested upcalls, any two-way + * request should block and push data to the underlying socket as fast + * as possible. + * # In the same use-case, but now with a timeout policy in + * effect, the ORB will need to send the data use I/O operations with + * timeouts (as implemented by ACE::sendv() + * # When the ORB is configured to support nested upcalls, any two-way, + * reliable oneway or similar should wait using the reactor or + * Leader-Follower implementation. While still respecting the timeout + * policies. + * + * Instead of sprinkling if() statements throughput the critical path + * trying to determine how the I/O operations should be performed, we + * pass the information encapsulated in this class. The caller into the + * Transport object determines the right parameters to use, and the + * Transport object simply obeys those instructions. + */ + class Drain_Constraints : private ACE_Copy_Disabled + { + public: + /// Default constructor + Drain_Constraints() + : timeout_(0) + , block_on_io_(false) + { + } + + /// Constructor + Drain_Constraints( + ACE_Time_Value * timeout, + bool block_on_io) + : timeout_(timeout) + , block_on_io_(block_on_io) + { + } + + /** + * If true, then the ORB should block on I/O operations instead of + * using non-blocking I/O. + */ + bool block_on_io() const + { + return block_on_io_; + } + + /** + * The maximum time to block on I/O operations (or nested loops) based + * on the current timeout policies. + */ + ACE_Time_Value * timeout() const + { + return timeout_; + } + + private: + ACE_Time_Value * timeout_; + bool block_on_io_; + }; } } @@ -243,7 +318,7 @@ namespace TAO * https://svn.dre.vanderbilt.edu/viewvc/Middleware/trunk/TAO/docs/pluggable_protocols/index.html?revision=HEAD * */ -class TAO_Export TAO_Transport +class TAO_Export TAO_Transport : private ACE_Copy_Disabled { public: @@ -290,7 +365,7 @@ public: TAO_Wait_Strategy *wait_strategy (void) const; /// Callback method to reactively drain the outgoing data queue - int handle_output (ACE_Time_Value *max_wait_time); + int handle_output (TAO::Transport::Drain_Constraints const & c); /// Get the bidirectional flag int bidirectional_flag (void) const; @@ -411,7 +486,7 @@ public: virtual ssize_t send (iovec *iov, int iovcnt, size_t &bytes_transferred, - const ACE_Time_Value *timeout = 0) = 0; + ACE_Time_Value const * timeout) = 0; #if TAO_HAS_SENDFILE == 1 /// Send data through zero-copy write mechanism, if available. @@ -428,7 +503,7 @@ public: iovec * iov, int iovcnt, size_t &bytes_transferred, - ACE_Time_Value const * timeout = 0); + TAO::Transport::Drain_Constraints const & dc); #endif /* TAO_HAS_SENDFILE==1 */ @@ -708,7 +783,14 @@ public: ACE_Time_Value *max_wait_time, TAO_Stub* stub); - /// Send a message block chain, + /** + * This is a very specialized interface to send a simple chain of + * messages through the Transport. The only place we use this interface + * is in GIOP_Message_Base.cpp, to send error messages (i.e., an + * indication that we received a malformed GIOP message,) and to close + * the connection. + * + */ int send_message_block_chain (const ACE_Message_Block *message_block, size_t &bytes_transferred, ACE_Time_Value *max_wait_time = 0); @@ -716,7 +798,8 @@ public: /// Send a message block chain, assuming the lock is held int send_message_block_chain_i (const ACE_Message_Block *message_block, size_t &bytes_transferred, - ACE_Time_Value *max_wait_time); + TAO::Transport::Drain_Constraints const & dc); + /// Cache management int purge_entry (void); @@ -801,10 +884,10 @@ private: * Returns 0 if there is more data to send, -1 if there was an error * and 1 if the message was completely sent. */ - int drain_queue (ACE_Time_Value *max_wait_time); + int drain_queue (TAO::Transport::Drain_Constraints const & dc); /// Implement drain_queue() assuming the lock is held - int drain_queue_i (ACE_Time_Value *max_wait_time); + int drain_queue_i (TAO::Transport::Drain_Constraints const & dc); /// Check if there are messages pending in the queue /** @@ -816,7 +899,8 @@ private: bool queue_is_empty_i (void) const; /// A helper routine used in drain_queue_i() - int drain_queue_helper (int &iovcnt, iovec iov[], ACE_Time_Value *max_wait_time); + int drain_queue_helper (int &iovcnt, iovec iov[], + TAO::Transport::Drain_Constraints const & dc); /// These classes need privileged access to: /// - schedule_output_i() @@ -928,10 +1012,35 @@ private: /// partial_message_ data member. void allocate_partial_message_block (void); - // Disallow copying and assignment. - TAO_Transport (const TAO_Transport&); - void operator= (const TAO_Transport&); + /** + * @brief Re-factor computation of I/O timeouts based on operation + * timeouts. + * Depending on the wait strategy, we need to timeout I/O operations or + * not. For example, if we are using a non-blocking strategy, we want + * to pass 0 to all I/O operations, and rely on the ACE_NONBLOCK + * settings on the underlying sockets. However, for blocking strategies + * we want to pass the operation timeouts, to respect the application + * level policies. + * + * This function was introduced as part of the fixes for bug 3647. + */ + ACE_Time_Value const *io_timeout( + TAO::Transport::Drain_Constraints const & dc) const; + /** + * Return true if blocking I/O should be used for sending synchronous + * (two-way, reliable oneways, etc.) messages. This is determined based + * on the current flushing and waiting strategies. + */ + bool using_blocking_io_for_synch_messages() const; + + /** + * Return true if blocking I/O should be used for sending asynchronous + * (AMI calls, non-blocking oneways, responses to operations, etc.) + * messages. This is determined based on the current flushing strategy. + */ + 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 diff --git a/TAO/tests/Bug_3647_Regression/Backend_Impl.cpp b/TAO/tests/Bug_3647_Regression/Backend_Impl.cpp new file mode 100644 index 00000000000..213f90b907f --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/Backend_Impl.cpp @@ -0,0 +1,66 @@ +#include "Backend_Impl.h" +#include "ace/OS.h" + +Bug_3647_Regression::Backend_Impl:: +Backend_Impl(CORBA::ORB_ptr orb, bool verbose) + : POA_Bug_3647_Regression::Backend() + , orb_(CORBA::ORB::_duplicate(orb)) + , verbose_(verbose) +{ +} + +Bug_3647_Regression::Backend_Impl:: +~Backend_Impl() +{ +} + +void Bug_3647_Regression::Backend_Impl:: +startup_test() +{ + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Backend_Impl::startup_test(%P|%t) - called\n")); + } +} + +void Bug_3647_Regression::Backend_Impl:: +ping(Bug_3647_Regression::Payload const & p) +{ + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Backend_Impl::ping(%P|%t) - called, payload length = %d\n", + p.length())); + } +} + +void Bug_3647_Regression::Backend_Impl:: +freeze(CORBA::ULong seconds) +{ + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Backend_Impl::freeze(%P|%t) - called, sleeping for %d seconds\n", + seconds)); + } + ACE_OS::sleep(seconds); + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Backend_Impl::sleep(%P|%t) - finished after %d seconds\n", + seconds)); + } + shutdown(); +} + +void Bug_3647_Regression::Backend_Impl:: +shutdown() +{ + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Backend_Impl::shutdown(%P|%t) - called\n")); + } + orb_->shutdown (false); +} diff --git a/TAO/tests/Bug_3647_Regression/Backend_Impl.h b/TAO/tests/Bug_3647_Regression/Backend_Impl.h new file mode 100644 index 00000000000..efd8569082e --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/Backend_Impl.h @@ -0,0 +1,37 @@ +#ifndef Bug_3647_Regression_Backend_Impl_h +#define Bug_3647_Regression_Backend_Impl_h + +#include "TestS.h" + +namespace Bug_3647_Regression +{ + +/** + * @class Backend + * + * Implement the Bug_3647_Regression::Backend interface + * + */ +class Backend_Impl : public POA_Bug_3647_Regression::Backend +{ +public: + Backend_Impl(CORBA::ORB_ptr orb, bool verbose); + virtual ~Backend_Impl(); + + virtual void startup_test(); + virtual void ping(Bug_3647_Regression::Payload const & the_payload); + virtual void freeze(CORBA::ULong seconds); + + virtual void shutdown(); + +private: + /// Keep a reference to the ORB so we can shutdown the application. + CORBA::ORB_var orb_; + + /// Use this flag to decide if the program should produce any output. + bool verbose_; +}; + +} // namespace Bug_3647_Regression + +#endif // Bug_3647_Regression_Backend_h diff --git a/TAO/tests/Bug_3647_Regression/Bug_3647_Regression.mpc b/TAO/tests/Bug_3647_Regression/Bug_3647_Regression.mpc new file mode 100644 index 00000000000..35be833411b --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/Bug_3647_Regression.mpc @@ -0,0 +1,52 @@ +// -*- MPC -*- +// $Id$ + +project(*idl): taoidldefaults, strategies { + IDL_Files { + Test.idl + } + custom_only = 1 +} + +project(*Backend): taoserver, utils, strategies { + after += *idl + Source_Files { + Backend_Impl.cpp + backend_server.cpp + } + Source_Files { + TestC.cpp + TestS.cpp + } + IDL_Files { + } + exename = backend_server +} + +project(*Middle): taoserver, messaging, utils, strategies { + after += *idl + Source_Files { + Middle_Impl.cpp + middle_server.cpp + } + Source_Files { + TestC.cpp + TestS.cpp + } + IDL_Files { + } + exename = middle_server +} + +project(*Client): taoclient, messaging, utils, strategies { + after += *idl + Source_Files { + client.cpp + } + Source_Files { + TestC.cpp + } + IDL_Files { + } +} + diff --git a/TAO/tests/Bug_3647_Regression/Middle_Impl.cpp b/TAO/tests/Bug_3647_Regression/Middle_Impl.cpp new file mode 100644 index 00000000000..ca62d2563af --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/Middle_Impl.cpp @@ -0,0 +1,96 @@ +#include "Middle_Impl.h" + +Bug_3647_Regression::Middle_Impl:: +Middle_Impl( + Backend_ptr backend, + CORBA::ORB_ptr orb, + bool verbose, + long timeout) + : POA_Bug_3647_Regression::Middle() + , backend_(Bug_3647_Regression::Backend::_duplicate(backend)) + , orb_(CORBA::ORB::_duplicate(orb)) + , verbose_(verbose) + , timeout_(timeout) +{ +} + +Bug_3647_Regression::Middle_Impl:: +~Middle_Impl() +{ +} + +void Bug_3647_Regression::Middle_Impl:: +startup_test() +{ + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Middle_Impl::startup_test(%P|%t) - called\n")); + } + backend_->startup_test(); + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Middle_Impl::startup_test(%P|%t) - backend " + "startup call sucessful\n")); + } + backend_->freeze(10); + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Middle_Impl::startup_test(%P|%t) - backend " + "freeze call sucessful\n")); + } +} + +void Bug_3647_Regression::Middle_Impl:: +ping() +{ + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Middle_Impl::ping(%P|%t) - called\n")); + } + try + { + Payload p; + p.length(1024); + backend_->ping(p); + } + catch(CORBA::TIMEOUT const & ex) + { + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Middle_Impl::ping(%P|%t) - timeout raised\n")); + } + } + catch(CORBA::Exception const & ex) + { + ACE_DEBUG ((LM_INFO, + "Middle_Impl::ping(%P|%t) - unexpected exception raised\n")); + throw; + } +} + +void Bug_3647_Regression::Middle_Impl:: +shutdown() +{ + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Middle_Impl::shutdown(%P|%t) - called\n")); + } + backend_->shutdown(); + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Middle_Impl::shutdown(%P|%t) - call to backend was completed\n")); + } + orb_->shutdown (false); + if (verbose_) + { + ACE_DEBUG ((LM_INFO, + "Middle_Impl::shutdown(%P|%t) - call to ORB was completed\n")); + } +} diff --git a/TAO/tests/Bug_3647_Regression/Middle_Impl.h b/TAO/tests/Bug_3647_Regression/Middle_Impl.h new file mode 100644 index 00000000000..0435f8a3b7d --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/Middle_Impl.h @@ -0,0 +1,46 @@ +#ifndef Bug_3647_Regression_Middle_Impl_h +#define Bug_3647_Regression_Middle_Impl_h + +#include "TestS.h" + +namespace Bug_3647_Regression +{ + +/** + * @class Middle + * + * Implement the Bug_3647_Regression::Middle interface + * + */ +class Middle_Impl : public POA_Bug_3647_Regression::Middle +{ +public: + Middle_Impl( + Backend_ptr backend, + CORBA::ORB_ptr orb, + bool verbose, + long timeout); + virtual ~Middle_Impl(); + + virtual void startup_test(); + virtual void ping(); + + virtual void shutdown(); + +private: + /// Keep a reference to the backend so we can call it, shutdown, etc. + Backend_var backend_; + + /// Keep a reference to the ORB so we can shutdown the application. + CORBA::ORB_var orb_; + + /// Use this flag to decide if the program should produce any output. + bool verbose_; + + /// Control the freeze time based on the timeout time + long timeout_; +}; + +} // namespace Bug_3647_Regression + +#endif // Bug_3647_Regression_Middle_hpp diff --git a/TAO/tests/Bug_3647_Regression/README b/TAO/tests/Bug_3647_Regression/README new file mode 100644 index 00000000000..13afa51b826 --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/README @@ -0,0 +1,32 @@ +/** + +@page Bug_3647_Regression Test README File + +This test demonstrates the problem described in bugzilla entry #3647. + +In this test we have three participants: + +A) A back-end server that will inconveniently block in the middle of + its work +B) A middle-tier server that is trying to communicate with the back + end server using SYNC_WITH_TRANSPORT oneway calls, with timeouts. +C) A client application that is sending twoway calls to the + middle-tier server. + +The expectaton is that when the back-end server completely blocks, the +middle-tier server will continue to operate normally. That is, the +oneway calls to the back-end server will block it, the timeouts will +expire, but the recursive loop will be available to respond to any +incoming requests from the client application. + +What we observe is that the middle-tier application blocks, but not in +the event loop as it should, but while checking if the socket is ready +for output. + +To run the test use the run_test.pl script: + +$ ./run_test.pl + +the script returns 0 if the test was successful, non-zero otherwise. + +*/ diff --git a/TAO/tests/Bug_3647_Regression/Test.idl b/TAO/tests/Bug_3647_Regression/Test.idl new file mode 100644 index 00000000000..7ae8286608d --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/Test.idl @@ -0,0 +1,48 @@ +/** + * @namespace Bug_3647_Regression + * + * Keep the types in this test to its own namespace. + * + * Keeping each test in its own namespace makes it easier to generate + * Doxygen documentation for all the tests. Also, it makes it clear as to + * what types are local vs. coming from the library vs. generated. + * + */ + +module Bug_3647_Regression +{ + typedef sequence<octet> Payload; + + interface Backend + { + /// This operation is called during the startup, to make sure all + /// servers are talking to each other and communication has been + /// established. + void startup_test(); + + /// When called this will just consume the data. The idea is to + /// generate network/traffic load. + oneway void ping(in Payload the_payload); + + /// When called this will cause the single thread in the server to + /// block for the specified number of seconds. + oneway void freeze(in unsigned long seconds); + + /// Shutdown the server + oneway void shutdown(); + }; + + interface Middle + { + /// This operation is called during the startup, to make sure all + /// servers are talking to each other and communication has been + /// established. + void startup_test(); + + /// When called this operation should return immediately. + void ping(); + + /// Shutdown the server + oneway void shutdown(); + }; +}; diff --git a/TAO/tests/Bug_3647_Regression/backend_server.cpp b/TAO/tests/Bug_3647_Regression/backend_server.cpp new file mode 100644 index 00000000000..65e03ea57c6 --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/backend_server.cpp @@ -0,0 +1,120 @@ +// $Id$ + +#include "Backend_Impl.h" + +#include "tao/Strategies/advanced_resource.h" + +#include "tao/Utils/Servant_Var.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" + +ACE_RCSID (Bug_3647_Regression, + backend_server, + "$Id$") + +const ACE_TCHAR *ior_output_file = ACE_TEXT ("backend.ior"); +bool verbose = false; + +int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("vo:")); + int c; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'o': + ior_output_file = get_opts.opt_arg (); + break; + + case 'v': + verbose = true; + break; + + case '?': + default: + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s " + "-o <iorfile>" + "\n", + argv [0]), + -1); + } + // Indicates sucessful parsing of the command line + return 0; +} + +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + try + { + CORBA::ORB_var orb = + CORBA::ORB_init (argc, argv); + + 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, + "backend_server(%P|%t) - panic: nil RootPOA\n"), + 1); + } + + PortableServer::POAManager_var poa_manager = root_poa->the_POAManager (); + + if (parse_args (argc, argv) != 0) + return 1; + + using namespace Bug_3647_Regression; + TAO::Utils::Servant_Var<Backend_Impl> impl( + new Backend_Impl(orb.in(), verbose)); + + PortableServer::ObjectId_var id = + root_poa->activate_object (impl.in()); + + CORBA::Object_var object = root_poa->id_to_reference (id.in ()); + + Bug_3647_Regression::Backend_var backend = + Bug_3647_Regression::Backend::_narrow (object.in ()); + + CORBA::String_var ior = orb->object_to_string (backend.in ()); + + // Output the IOR to the <ior_output_file> + FILE *output_file= ACE_OS::fopen (ior_output_file, "w"); + if (output_file == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + "backend_server(%P|%) - cannot open output file " + "for writing IOR: %s\n", + ior_output_file), + 1); + } + ACE_OS::fprintf (output_file, "%s", ior.in ()); + ACE_OS::fclose (output_file); + + poa_manager->activate (); + + orb->run (); + + ACE_DEBUG ((LM_DEBUG, "backend_server(%P|%t) - event loop finished\n")); + + root_poa->destroy (1, 1); + + orb->destroy (); + } + catch (const CORBA::Exception& ex) + { + ACE_DEBUG ((LM_DEBUG, + "backend_server")); + ex._tao_print_exception ("Exception caught:"); + return 1; + } + + return 0; +} diff --git a/TAO/tests/Bug_3647_Regression/client.cpp b/TAO/tests/Bug_3647_Regression/client.cpp new file mode 100644 index 00000000000..830ef6d3ab3 --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/client.cpp @@ -0,0 +1,147 @@ +// $Id$ + +#include "TestC.h" +#include "tao/Strategies/advanced_resource.h" +#include "tao/Utils/PolicyList_Destroyer.h" +#include "tao/Messaging/Messaging.h" +#include "tao/AnyTypeCode/Any.h" +#include "ace/Get_Opt.h" + +ACE_RCSID(Bug_3647_Regression, + client, + "$Id$") + +const ACE_TCHAR *ior = ACE_TEXT ("file://middle.ior"); +bool verbose = true; +long timeout = 2; + +void +usage(ACE_TCHAR const *cmd, + ACE_TCHAR const *msg) +{ + ACE_ERROR ((LM_ERROR, + "usage: %s " + "-v " + "-k <ior> " + "-t timeout " + "\n" + " %s\n", + cmd, msg)); +} + +int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("vk:t:")); + int c; + ACE_TCHAR const *stimeout = 0; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'v': + verbose = true; + break; + + case 'k': + ior = get_opts.opt_arg (); + break; + + case 't': + stimeout = get_opts.opt_arg(); + break; + + case '?': + default: + usage(argv[0], "unknown argument"); + return -1; + } + + if (stimeout != 0) + { + ACE_TCHAR *end; + long tmp = ACE_OS::strtol(stimeout, &end, 10); + if (end == 0 || *end != '\0') + { + usage(argv[0], "Invalid timeout value"); + return -1; + } + timeout = tmp; + } + + // Indicates sucessful parsing of the command line + 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 tmp = orb->string_to_object(ior); + + // one second in TimeT units + TimeBase::TimeT const second = 10 * TimeBase::TimeT(1000000); + + CORBA::Any timeout_as_any; + timeout_as_any <<= TimeBase::TimeT(timeout * second); + + TAO::Utils::PolicyList_Destroyer plist(1); + plist.length(1); + plist[0] = + orb->create_policy(Messaging::RELATIVE_RT_TIMEOUT_POLICY_TYPE, + timeout_as_any); + + tmp = tmp->_set_policy_overrides(plist, CORBA::SET_OVERRIDE); + + Bug_3647_Regression::Middle_var middle = + Bug_3647_Regression::Middle::_narrow(tmp.in ()); + + if (CORBA::is_nil (middle.in ())) + { + ACE_ERROR_RETURN ((LM_DEBUG, + "client(%P|%t) - nil " + "Bug_3647_Regression::Middle reference <%s>\n", + ior), + 1); + } + + // Startup the tests ... + middle->startup_test(); + + ACE_DEBUG ((LM_DEBUG, "client(%P|%t) - test started up\n")); + + int const iterations = 10000; + int const interval = iterations / 20; + ACE_DEBUG ((LM_DEBUG, "client(%P|%t) - running pings")); + for (int i = 0; i != iterations; ++i) + { + middle->ping(); + if (i % interval == 0 and i > 0) + { + ACE_DEBUG((LM_DEBUG, ".")); + } + } + ACE_DEBUG ((LM_DEBUG, "done\n")); + + middle->shutdown (); + ACE_DEBUG ((LM_DEBUG, + "client(%P|%t) - server shutdown request sent\n")); + + orb->destroy (); + } + catch (const CORBA::Exception& ex) + { + ACE_DEBUG ((LM_DEBUG, + "client")); + ex._tao_print_exception ("Exception caught:"); + return 1; + } + + return 0; +} diff --git a/TAO/tests/Bug_3647_Regression/middle_server.cpp b/TAO/tests/Bug_3647_Regression/middle_server.cpp new file mode 100644 index 00000000000..a60585ab7eb --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/middle_server.cpp @@ -0,0 +1,221 @@ +// $Id$ + +#include "Middle_Impl.h" + +#include "tao/Utils/PolicyList_Destroyer.h" +#include "tao/Utils/Servant_Var.h" +#include "tao/Utils/RIR_Narrow.h" +#include "tao/Strategies/advanced_resource.h" +#include "tao/Messaging/Messaging.h" +#include "tao/AnyTypeCode/Any.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" + +ACE_RCSID (Bug_3647_Regression, + middle_server, + "$Id$") + +bool verbose = false; +const ACE_TCHAR *ior_output_file = ACE_TEXT ("middle.ior"); +const ACE_TCHAR *ior = ACE_TEXT ("file://backend.ior"); +Messaging::SyncScope scope = Messaging::SYNC_NONE; +long timeout = 2; + +void +usage(ACE_TCHAR const *cmd, + ACE_TCHAR const *msg) +{ + ACE_ERROR ((LM_ERROR, + "Usage: %s " + "-v " + "-k <ior> " + "-o <iorfile> " + "-s <NONE|TRANSPORT|SERVER|TARGET|DELAYED> " + "-t timeout " + "\n" + " %s\n", + cmd, msg)); +} + +int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("vo:k:s:t:")); + int c; + ACE_TCHAR const *sname = "NONE"; + ACE_TCHAR const *stimeout = 0; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'v': + verbose = true; + break; + + case 'o': + ior_output_file = get_opts.opt_arg (); + break; + + case 'k': + ior = get_opts.opt_arg (); + break; + + case 's': + sname = get_opts.opt_arg (); + break; + + case 't': + stimeout = get_opts.opt_arg(); + break; + + case '?': + default: + usage(argv[0], "unknown argument"); + return -1; + } + + if (ACE_OS::strcmp(sname, "NONE") == 0) { + scope = Messaging::SYNC_NONE; + } else if (ACE_OS::strcmp(sname, "TRANSPORT") == 0) { + scope = Messaging::SYNC_WITH_TRANSPORT; + } else if (ACE_OS::strcmp(sname, "SERVER") == 0) { + scope = Messaging::SYNC_WITH_SERVER; + } else if (ACE_OS::strcmp(sname, "TARGET") == 0) { + scope = Messaging::SYNC_WITH_TARGET; + } else if (ACE_OS::strcmp(sname, "DELAYED") == 0) { + scope = TAO::SYNC_DELAYED_BUFFERING; + } else { + usage(argv[0], "Invalid scope value"); + return -1; + } + + if (stimeout != 0) + { + ACE_TCHAR *end; + long tmp = ACE_OS::strtol(stimeout, &end, 10); + if (end == 0 || *end != '\0') + { + usage(argv[0], "Invalid timeout value"); + return -1; + } + timeout = tmp; + } + + // Indicates sucessful parsing of the command line + return 0; +} + +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + try + { + CORBA::ORB_var orb = + CORBA::ORB_init (argc, argv); + + 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, + "backend_server(%P|%t) - panic: nil RootPOA\n"), + 1); + } + + PortableServer::POAManager_var poa_manager = + root_poa->the_POAManager (); + + if (parse_args (argc, argv) != 0) + return 1; + + CORBA::Object_var tmp = orb->string_to_object(ior); + + // one second in TimeT units + TimeBase::TimeT const second = 10 * TimeBase::TimeT(1000000); + + CORBA::Any timeout_as_any; + timeout_as_any <<= TimeBase::TimeT(timeout * second); + + CORBA::Any scope_as_any; + scope_as_any <<= scope; + + TAO::Utils::PolicyList_Destroyer plist(1); + plist.length(2); + plist[0] = + orb->create_policy(Messaging::RELATIVE_RT_TIMEOUT_POLICY_TYPE, + timeout_as_any); + plist[1] = + orb->create_policy(Messaging::SYNC_SCOPE_POLICY_TYPE, + scope_as_any); + + CORBA::PolicyCurrent_var policy_current = + TAO::Utils::RIR_Narrow<CORBA::PolicyCurrent>::narrow( + orb.in (), + "PolicyCurrent"); + + policy_current->set_policy_overrides( + plist, CORBA::ADD_OVERRIDE); + + Bug_3647_Regression::Backend_var backend = + Bug_3647_Regression::Backend::_narrow(tmp.in ()); + + if (CORBA::is_nil (backend.in ())) + { + ACE_ERROR_RETURN ((LM_DEBUG, + "middle_server(%P|%t) - nil backend reference <%s>\n", + ior), + 1); + } + + using namespace Bug_3647_Regression; + TAO::Utils::Servant_Var<Middle_Impl> impl( + new Middle_Impl(backend.in(), orb.in(), verbose, + timeout)); + + PortableServer::ObjectId_var id = + root_poa->activate_object (impl.in()); + + CORBA::Object_var object = root_poa->id_to_reference (id.in ()); + + + Bug_3647_Regression::Middle_var middle = + Bug_3647_Regression::Middle::_narrow (object.in ()); + + CORBA::String_var ior = orb->object_to_string (middle.in ()); + + // Output the IOR to the <ior_output_file> + FILE *output_file= ACE_OS::fopen (ior_output_file, "w"); + if (output_file == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "middle_server(%P|%t) - Cannot open output file " + "for writing IOR: %s\n", + ior_output_file), + 1); + ACE_OS::fprintf (output_file, "%s", ior.in ()); + ACE_OS::fclose (output_file); + + poa_manager->activate (); + + orb->run (); + + ACE_DEBUG ((LM_DEBUG, + "middle_server(%P|%t) - event loop finished\n")); + + root_poa->destroy (1, 1); + + orb->destroy (); + } + catch (const CORBA::Exception& ex) + { + ACE_DEBUG ((LM_DEBUG, + "middle_server")); + ex._tao_print_exception ("Exception caught:"); + return 1; + } + + return 0; +} diff --git a/TAO/tests/Bug_3647_Regression/run_test.pl b/TAO/tests/Bug_3647_Regression/run_test.pl new file mode 100755 index 00000000000..acac010b251 --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/run_test.pl @@ -0,0 +1,149 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; +use strict; + +my $verbose = ''; +my $mode = 'DELAYED'; + +foreach my $i (@ARGV) { + if ($i eq '-verbose') { + $verbose = ' -v'; + } elsif ($i eq '-none') { + $mode = 'NONE'; + } elsif ($i eq '-delayed') { + $mode = 'DELAYED'; + } elsif ($i eq '-transport') { + # In this mode, the test is *expected* to fail. We only run it + # like this to verify that the test is a good test (i.e. it + # detects failures.) Same comment applies for SERVER and TARGET + # modes. + $mode = 'TRANSPORT'; + } elsif ($i eq '-server') { + $mode = 'SERVER'; + } elsif ($i eq '-target') { + $mode = 'TARGET'; + } +} + +my $backend = PerlACE::TestTarget::create_target(1) + or die "Create target 1 failed\n"; +my $middle = PerlACE::TestTarget::create_target(2) + or die "Create target 2 failed\n"; +my $client = PerlACE::TestTarget::create_target(3) + or die "Create target 3 failed\n"; + +my $backend_ior = "backend.ior"; +my $middle_ior = "middle.ior"; + +my $backend_iorfile = $backend->LocalFile ($backend_ior); +my $middle_in_iorfile = $middle->LocalFile ($backend_ior); +my $middle_out_iorfile = $middle->LocalFile ($middle_ior); +my $client_in_iorfile = $client->LocalFile ($middle_ior); + +$backend->DeleteFile($backend_ior); +$middle->DeleteFile($backend_ior); +$middle->DeleteFile($middle_ior); +$client->DeleteFile($middle_ior); + +my $BE = + $backend->CreateProcess ("backend_server", + " -o $backend_iorfile" + . $verbose); +my $MD = + $middle->CreateProcess (#"/usr/bin/strace"," -o md.strace.txt ./middle_server". + "middle_server", + " -s $mode -t 5 " + ." -o $middle_out_iorfile" + . $verbose + . " -k file://$middle_in_iorfile"); +my $CL = $client->CreateProcess ("client", + " -k file://$client_in_iorfile" + ." -t 1 " + .$verbose); +my $be_status = $BE->Spawn (); +if ($be_status != 0) { + print STDERR "ERROR: server returned $be_status\n"; + exit 1; +} + +if ($backend->WaitForFileTimed ($backend_ior, + $backend->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$backend_iorfile>\n"; + $BE->Kill (); $BE->TimedWait (1); + exit 1; +} + +if ($backend->GetFile ($backend_ior) == -1) { + print STDERR "ERROR: cannot retrieve file <$backend_iorfile>\n"; + $BE->Kill (); $BE->TimedWait (1); + exit 1; +} + +if ($middle->PutFile ($backend_ior) == -1) { + print STDERR "ERROR: cannot set file <$middle_in_iorfile>\n"; + $BE->Kill (); $BE->TimedWait (1); + exit 1; +} + +my $md_status = $MD->Spawn (); +if ($md_status != 0) { + print STDERR "ERROR: server returned $md_status\n"; + $BE->Kill (); $BE->TimedWait (1); + exit 1; +} + +if ($middle->WaitForFileTimed ($middle_ior, + $middle->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$middle_in_iorfile>\n"; + $MD->Kill (); $MD->TimedWait (1); + $BE->Kill (); $BE->TimedWait (1); + exit 1; +} + +if ($middle->GetFile ($middle_ior) == -1) { + print STDERR "ERROR: cannot retrieve file <$middle_out_iorfile>\n"; + $MD->Kill (); $MD->TimedWait (1); + $BE->Kill (); $BE->TimedWait (1); + exit 1; +} + +if ($client->PutFile ($middle_ior) == -1) { + print STDERR "ERROR: cannot set file <$client_in_iorfile>\n"; + $MD->Kill (); $MD->TimedWait (1); + $BE->Kill (); $BE->TimedWait (1); + exit 1; +} + +my $status = 0; +my $client_status = + $CL->SpawnWaitKill ($client->ProcessStartWaitInterval()); +if ($client_status != 0) { + print STDERR "ERROR: client returned $client_status\n"; + $status = 1; +} + +$md_status = $MD->WaitKill ($middle->ProcessStopWaitInterval()); +if ($md_status != 0) { + print STDERR "ERROR: middle returned $md_status\n"; + $status = 1; +} + +$be_status = $BE->WaitKill ($backend->ProcessStopWaitInterval()); +if ($be_status != 0) { + print STDERR "ERROR: backend returned $be_status\n"; + $status = 1; +} + +$backend->DeleteFile($backend_ior); +$middle->DeleteFile($backend_ior); +$middle->DeleteFile($middle_ior); +$client->DeleteFile($middle_ior); + +exit $status; diff --git a/TAO/tests/Bug_3647_Regression/svc.conf b/TAO/tests/Bug_3647_Regression/svc.conf new file mode 100644 index 00000000000..b3efd649ff2 --- /dev/null +++ b/TAO/tests/Bug_3647_Regression/svc.conf @@ -0,0 +1,6 @@ +# +# $Id$ +# +static Advanced_Resource_Factory "-ORBReactorType select_st -ORBInputCDRAllocator null -ORBConnectionCacheLock null" +static Server_Strategy_Factory "-ORBPOALock null" +static Client_Strategy_Factory "-ORBProfileLock null" |