code: protected Object internalSearchAndInvokeWithBlocking(AbstractServiceContext context, String mName, String mDescriptor, Object[] arguments) throws Exception {
          // FIXME: reuse providers already looked-up!
          
          long timeout= context.getTimeout();
          long searchStart= System.currentTimeMillis();
          Synchroniser sync= new Synchroniser();
          final String serviceName= context.serviceClass.getName();
          
          synchronized (sync) {
              // wait at most one third of the timeout for search responses
              _requestProtocol.broadcastRequest(SEARCH, serviceName, SEARCH_GROUP, timeout / 3, sync);
              sync.wait(timeout);
          }
          
          if(sync.source == null || sync.content == null || !serviceName.equals(sync.content)) {
              throw new RuntimeException("service unavailable: '" + serviceName + "'");
          }
          
          String providerAddress= sync.source;
          sync.source= null;
          sync.content= null;
          timeout-= (System.currentTimeMillis() - searchStart);
          
          if(timeout <= 0) {
              throw new RuntimeException("no time to invoke service: '" + serviceName + "'");
          }
          
          synchronized (sync) {
              ServiceInvocation invocation= new ServiceInvocation(serviceName, mName, mDescriptor, arguments);
              _requestProtocol.request(INVOKE, invocation, providerAddress, timeout, sync);
              sync.wait(timeout);
          }
          
          if(sync.content == null) {
              throw new RuntimeException("service invocation timed out: " + serviceName + "'");
          }
          
          return ((ServiceInvocation) sync.content).result;
      }
docs: Note: The caller must lock the specified ServiceContext!