Index: Leader_Follower.i =================================================================== RCS file: /src/apps/VxPSP/Current/source/ACE_wrappers/TAO/tao/Leader_Follower.i,v retrieving revision 1.1.1.4 retrieving revision 1.4 diff -u -w -r1.1.1.4 -r1.4 --- Leader_Follower.i 24 Sep 2004 18:00:55 -0000 1.1.1.4 +++ Leader_Follower.i 27 Jan 2009 16:17:13 -0000 1.4 @@ -61,4 +61,6 @@ ACE_INLINE int TAO_Leader_Follower::set_event_loop_thread (ACE_Time_Value *max_wait_time) { + // No need to grab the lock here - this method is called from the + // LF_Strategy object which has already grabbed the lock. TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources (); // Make sure that there is no other client thread run the show. If @@ -94,6 +96,9 @@ ACE_INLINE void TAO_Leader_Follower::reset_event_loop_thread_i (TAO_ORB_Core_TSS_Resources *tss) { + // No need to grab the lock here - this method is called from the + // LF_Strategy object which has already grabbed the lock. + // Always decrement . If // reaches 0 and we are not a client leader, we are done with our // duties of running the event loop. Therefore, decrement the @@ -133,0 +138,0 @@ this->elect_new_leader (); } + else if (tss->client_leader_thread_ > 0) + { + ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->lock ()); + this->reset_client_leader_thread (); + // We need some way to signal to reset_client_leader_thread that + // the leadership has already been given up - we do this by + // negating the client_leader_thread_ count. + tss->client_leader_thread_ = -tss->client_leader_thread_; + this->elect_new_leader (); + } } ACE_INLINE int @@ -144,6 +159,8 @@ ACE_INLINE void TAO_Leader_Follower::set_client_leader_thread (void) { + // No need to grab the lock here - this method is called from inside + // wait_for_event where the lock is already held. TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources (); ++this->leaders_; ++this->client_thread_is_leader_; @@ -153,8 +170,25 @@ ACE_INLINE void TAO_Leader_Follower::reset_client_leader_thread (void) { + // No need to grab the lock here - this method is called from inside + // wait_for_event where the lock is already held. TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources (); + // We may have already been called via set_upcall_thread before we + // get called via ~TAO_LF_Client_Leader_Thread_Helper, so we need to + // check that client_leader_thread_ is not already zero. + if (tss->client_leader_thread_ > 0) + { --tss->client_leader_thread_; --this->leaders_; --this->client_thread_is_leader_; } + else if (tss->client_leader_thread_ < 0) + { + // If the client_leader_thread_ count was negative that means + // that leadership was given up via a call to set_upcall_thread + // in this wait_for_event context - reset the value back to its + // postive value which is what is required for the next + // wait_for_event context up the stack. + tss->client_leader_thread_ = -tss->client_leader_thread_; + } +} ACE_INLINE int TAO_Leader_Follower::is_client_leader_thread (void) const Index: Leader_Follower.cpp =================================================================== RCS file: /src/apps/VxPSP/Current/source/ACE_wrappers/TAO/tao/Leader_Follower.cpp,v retrieving revision 1.3 retrieving revision 1.6 diff -u -w -r1.3 -r1.6 --- Leader_Follower.cpp 26 Apr 2007 20:56:46 -0000 1.3 +++ Leader_Follower.cpp 27 Jan 2009 16:12:42 -0000 1.6 @@ -161,5 +161,6 @@ if (tss->event_loop_thread_ || tss->client_leader_thread_) { + // Will this ever be true? And will it ever work? ++this->leaders_; } @@ -199,2 +200,2 @@ if (TAO_debug_level) t_id = transport->id (); - { + { // Scope #1: All threads inside here are client threads // Calls this->set_client_thread () on construction and // this->reset_client_thread () on destruction. TAO_LF_Client_Thread_Helper client_thread_helper (*this); ACE_UNUSED_ARG (client_thread_helper); + // The loop here is for when we get elected (client) leader and + // then later relinquish the leader position and our event has + // still not completed (and we haven't run out of time). + + // All the conditions below are basically the various ways the + // leader loop below can end, other than the event being complete + + while (event->keep_waiting () + && !(result == 0 && + max_wait_time != 0 && + *max_wait_time == ACE_Time_Value::zero) + && result != -1) + { // Scope #2: threads here alternate between being leader/followers // Check if there is a leader. Note that it cannot be us since we // gave up our leadership when we became a client. if (this->leader_available ()) - { + { // Scope #3: threads here are followers // = Wait as a follower. // Grab a follower: @@ -228,0 +242,0 @@ while (event->keep_waiting () && this->leader_available ()) - { + { // Scope #4: this loop handles spurious wake-ups // Add ourselves to the list, do it everytime we wake up // from the CV loop. Because: // @@ -324,4 +338,4 @@ return -1; } } - } + } // End Scope #4: loop to handle spurious wakeups countdown.update (); @@ -354,4 +368,4 @@ // We only get here if we woke up but the reply is not // complete yet, time to assume the leader role.... // i.e. ACE_ASSERT (event->successful () == 0); - } + } // End Scope #3: we are no longer a follower // = Leader Code. @@ -367,5 +381,6 @@ // construction and this->reset_client_leader_thread () // on destruction. Note that this may increase the refcount of // the leader. + { // Scope #5: We are now the client-leader TAO_LF_Client_Leader_Thread_Helper client_leader_thread_helper (*this); ACE_UNUSED_ARG (client_leader_thread_helper); - { + { // Scope #6: release the lock via a reverse lock ACE_GUARD_RETURN (ACE_Reverse_Lock, rev_mon, this->reverse_lock (), -1); // Become owner of the reactor. - ACE_Reactor *reactor = this->reactor_; + ACE_Reactor *reactor = this->reactor (); reactor->owner (ACE_Thread::self ()); // Run the reactor event loop. @@ -403,2 +418,2 @@ if (result == -1) break; + // Has an event loop thread become available to take over? + // Yes, we are checking this without the lock, however, if + // we get a false reading we'll just circle around and + // become leader again... + if (this->event_loop_threads_waiting_) + break; + + // Did we give up leadership? + if (!this->is_client_leader_thread ()) + break; // Otherwise, keep going... } @@ -411,10 +436,12 @@ "TAO (%P|%t) - Leader_Follower[%d]::wait_for_event," " (leader) exit reactor event loop\n", t_id)); - } - } + } // End Scope #6: we should now hold the lock again // // End artificial scope for auto_ptr like helpers calling: - // this->reset_client_thread () and (maybe) // this->reset_client_leader_thread (). // + } // End Scope #5: we are no longer a client-leader + // We only get here if we were the client leader and either our + // event completed or an event loop thread has become available to + // become leader. // Wake up the next leader, we cannot do that in handle_input, // because the woken up thread would try to get into handle_events, @@ -433,2 +460,2 @@ t_id), -1); + // Yield to any event loop threads that may be waiting to take + // leadership - otherwise we will just loop around and take + // leadership again (because we hold the lock). + if (this->event_loop_threads_waiting_) + { + ACE_GUARD_RETURN (ACE_Reverse_Lock, rev_mon, + this->reverse_lock (), -1); + ACE_OS::thr_yield (); + } + + } // End Scope #2: we loop here if our event is incomplete + + // + // End artificial scope for auto_ptr like helpers calling: + // this->reset_client_thread () + // + + // We should only get here when our event is complete or timed-out + } // End Scope #1: we are no longer a client thread + if (result == -1) ACE_ERROR_RETURN ((LM_ERROR, "TAO (%P|%t) - Leader_Follower[%d]::wait_for_event,"