docs: private void queueInvocationCommon(AbstractInvocation invocation, ConversationImpl conversation)
     {
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.entry(this, tc, "queueInvocationCommon", new Object[] {invocation, conversation});
        if (dispatcherEnabled)
        {
           // Start F201521
  
           try                                                                              // D202636
           {                                                                                // D202636
              // First job is to ask the ConversationReceiveListener for the object which may contain
              // a dispatch queue. If they return null here, we assume that we should use the dispatch
              // queue held in the Conversation.
              // Note this method may throw a RuntimeException indicating that there was a problem
              // executing this method. If this occurs, we don't want to dispatch this segment as
              // the conversation will be closed.
              Dispatchable dispatchable = invocation.getThreadContext();
  
              // If this was null, then use the Conversation as the Dispatchable object
              if (dispatchable == null) dispatchable = conversation;
  
              // Save this in the invocation
              invocation.setDispatchable(dispatchable);
  
              // Update the count in the Conversation of how many requests are outstanding on
              // this Conversation. This is needed when we are processing errorOccurred
              // notifications as we want to ensure that errorOccurred callbacks come after
              // all the data has been processed for that Conversation.
              synchronized (conversation.getTotalOutstandingRequestCountLock())
              {
                 conversation.incrementTotalOutstandingCount();
              }
  
              ReceiveListenerDispatchQueue dispatchQueue = null;
              Object dispatchableLock = dispatchable.getDispatchLockObject();
  
              // Take a lock on the dispatchable to determin its dispatch queue.  This is
              // required to exclude other threads whilst we check if there is an associated
              // dispatch queue and if there is - increment its reference count.  We can drop
              // out of the synchronize block once the reference count is increased as other
              // threads will not disassociate a dispatch queue with a non-zero reference count.
              synchronized(dispatchableLock)
              {
                 dispatchQueue = (ReceiveListenerDispatchQueue) dispatchable.getDispatchQueue();
                 if (dispatchQueue != null)
                    dispatchable.incrementDispatchQueueRefCount();
              }
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "queueInvocationCommon", "dispatchQueue="+dispatchQueue);
              // End F201521
  
              if (dispatchQueue == null)
              {
                 // The dispatchable was not already associated with a dispatch queue, so try
                 // finding a suitable queue in the list of empty queues.  We synchronize on the
                 // empty queues list to prevent corruption of the data structure by concurrent
                 // access.  We also want to prevent anyone else from adding or removing queues
                 // from the list until we have either removed a queue of our own or chosen a
                 // queue to dispatch into.
                 synchronized(emptyDispatchQueues)
                 {
                    if (!emptyDispatchQueues.isEmpty())
                       dispatchQueue = emptyDispatchQueues.remove(emptyDispatchQueues.size()-1);  // D217401
                    else
                    {
                       // There was no empty queues so choose a queue by taking the modulus of
                       // the monotomically incrementing counter associated with the conversation.
                       // We must do this inside a block synchronized on the empty dispatch queue
                       // to prevent a race condition where someone could be adding the queue we
                       // decide upon into the empty queues list.
                       int queueNumber = conversation.getInstanceCounterValue();
                       dispatchQueue = dispatchQueues[queueNumber % maxConcurrentDispatches];
                    }
                 }
                 if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "dispatchQueue="+dispatchQueue);
  
                 // Now we have decided upon a dispatch queue - associate it with the
                 // dispatchable and ensure it has a non-zero reference count.  This is
                 // done inside a synchronize block to ensure the change is kept consistent
                 // across threads accessing the dispatchable.
                 synchronized(dispatchableLock)                                                // F201521
                 {
                    dispatchable.setDispatchQueue(dispatchQueue);                              // F201521
                    dispatchable.incrementDispatchQueueRefCount();                             // F201521
                 }
              }
  
              //Reset invocation prior to enqueue to prevent its reference count getting messed up. 
              invocation.resetReferenceCounts();
              
              // Finally enqueue the work to our chosen dispatch queue
              dispatchQueue.enqueue(invocation);
           }
           catch (RuntimeException e)
           {
              // No FFDC code needed
              // Note the connection has already been blown away by this point - so no further action
              // needs to be taken.
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Looks like getThreadContext failed:", e);
           }
           // Start D213108
           // It's important that we carry on here and do not barf back up to the TCP channel
           // as we do not want to knacker any threads that will service user requests
           catch (Throwable t)
           {
              FFDCFilter.processException(t, "com.ibm.ws.sib.jfapchannel.impl.rldispatcher.ReceiveListenerDispatcher",
                                          JFapChannelConstants.RLDISPATCHER_QUEUEINVOCCOMMON_01, this);
  
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "RL Dispatcher threw an exception: ", t);
           }
           // End D213108
           // End D202636
        }
        else // dispatcherEnabled == false
        {
           // If we are not using the new dispatching code then just invoke
           // the appropriate method on this thread.
           invocation.invoke();
           invocation.repool();
           invocation.resetReferenceCounts();                                               // D213108
        }
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.exit(this, tc, "queueInvocationCommon");
     }