private void dispatch(StartCallback startCB, Queue<OutgoingMessage> sentCBs, MessageInfo info) { int dispatchedCount = 0; // // Notify the factory that the connection establishment and // validation has completed. // if(startCB != null) { startCB.connectionStartCompleted(this); ++dispatchedCount; } // // Notify AMI calls that the message was sent. // if(sentCBs != null) { foreach(OutgoingMessage m in sentCBs) { if(m.invokeSent) { m.outAsync.invokeSent(); } if(m.receivedReply) { IceInternal.OutgoingAsync outAsync = (IceInternal.OutgoingAsync)m.outAsync; if(outAsync.response()) { outAsync.invokeResponse(); } } } ++dispatchedCount; } // // Asynchronous replies must be handled outside the thread // synchronization, so that nested calls are possible. // if(info.outAsync != null) { info.outAsync.invokeResponse(); ++dispatchedCount; } if(info.heartbeatCallback != null) { try { info.heartbeatCallback(this); } catch(System.Exception ex) { _logger.error("connection callback exception:\n" + ex + '\n' + _desc); } ++dispatchedCount; } // // Method invocation (or multiple invocations for batch messages) // must be done outside the thread synchronization, so that nested // calls are possible. // if(info.invokeNum > 0) { invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager, info.adapter); // // Don't increase dispatchedCount, the dispatch count is // decreased when the incoming reply is sent. // } // // Decrease dispatch count. // if(dispatchedCount > 0) { lock(this) { _dispatchCount -= dispatchedCount; if(_dispatchCount == 0) { // // Only initiate shutdown if not already done. It // might have already been done if the sent callback // or AMI callback was dispatched when the connection // was already in the closing state. // if(_state == StateClosing) { try { initiateShutdown(); } catch(Ice.LocalException ex) { setState(StateClosed, ex); } } else if(_state == StateFinished) { reap(); } System.Threading.Monitor.PulseAll(this); } } } }