docs: @Override
      public Object preInvoke(EJSDeployedSupport s, ContainerTx tx) throws RemoteException {
          final boolean isTraceOn = TraceComponent.isAnyTracingEnabled();
          if (isTraceOn && tc.isEntryEnabled())
              Tr.entry(tc, "preInvoke : " + this);
  
          // If this is container managed concurrency control, then use
          // then get the lock specified by the lock type found in the
          // EJB method info object.
          s.ivLockAcquired = false; // d571981
          if (ivContainerManagedConcurrency) {
              // Get the lock type to use for the method being invoked.
              // and AccessTimeout value to use.
              EJBMethodInfoImpl mInfo = s.methodInfo;
              LockType lockType = mInfo.ivLockType;
  
              // Ensure we are not trying to upgrade from a READ to a WRITE lock. We
              // must throw an exception if trying to upgrade from READ to WRITE.
              if (lockType == LockType.WRITE && ivLock.isWriteLockedByCurrentThread() == false) {
                  // Requesting write lock and write lock is not currently held by the
                  // calling thread. So check whether calling thread holds any read locks.
                  if (ivLock.getReadHoldCount() > 0) {
                      throw new IllegalLoopbackException("A loopback method call is not allowed to upgrade from a READ to a WRITE lock.");
                  }
              }
  
              if (isTraceOn && tc.isDebugEnabled())
                  Tr.debug(tc, "preInvoke attempting to acquire a " + mInfo.ivLockType.name() + " lock. " + ivLock.toString());
  
              // PMI startLockTime for read and write locks  F743-9002
              long lockStartTime = 0;
              int lockStatType = 0;
  
              try {
                  long timeout = mInfo.ivAccessTimeout;
  
                  // For a persistent timeout callback that will wait a significant amount of
                  // time for the lock, perform a quick lock attempt in an effort to detect a
                  // deadlock that can occur between the singleton lock and the timer database
                  // if there is a concurrent thread calling getTimers().             RTC126471
                  if (s.isPersistentTimeoutGlobalTx &&
                      PersistentTimerSingletonDeadlockTimeout >= 0 &&
                      (timeout == -1 || timeout > PersistentTimerSingletonDeadlockTimeout)) {
                      if (lockType == LockType.READ) {
                          if (pmiBean != null) {
                              lockStatType = EJBPMICollaborator.READ_LOCK_TIME;
                              lockStartTime = pmiBean.initialTime(lockStatType);
                          }
                          s.ivLockAcquired = ivReadLock.tryLock(PersistentTimerSingletonDeadlockTimeout, TimeUnit.MILLISECONDS);
                      } else {
                          if (pmiBean != null) {
                              lockStatType = EJBPMICollaborator.WRITE_LOCK_TIME;
                              lockStartTime = pmiBean.initialTime(lockStatType);
                          }
                          s.ivLockAcquired = ivWriteLock.tryLock(PersistentTimerSingletonDeadlockTimeout, TimeUnit.MILLISECONDS);
                      }
  
                      if (s.ivLockAcquired) {
                          if (isTraceOn && tc.isDebugEnabled())
                              Tr.debug(tc, "preInvoke acquired a " + mInfo.ivLockType.name() + " lock. " + ivLock.toString());
                      } else {
                          // If the lock was not obtained and another thread is in getTimer,
                          // then a deadlock is very likely, so abort the timeout callback
                          // which will free up the database row lock.
                          if (ivInGetTimers.get() > 0) {
                              if (pmiBean != null) {
                                  pmiBean.countCancelledLocks();
                              }
                              throw new ConcurrentAccessTimeoutException("preInvoke timed out in attempt to acquire a "
                                                                         + mInfo.ivLockType.name() + " lock for method signature = " + mInfo.getMethodSignature()
                                                                         + ".  Dead lock detected with timer database.");
                          }
  
                          // Otherwise, subtract the time waited, and proceed normally
                          if (timeout != -1) {
                              timeout = Math.max(0, timeout - PersistentTimerSingletonDeadlockTimeout);
                          }
                      }
                  }
  
                  // If the lock is not acquired, then either this is not for a persistent
                  // timeout callback, or there is not a concurrent thread in getTimers(),
                  // so just attempt to obtain a lock using the configured access timeout.
                  if (!s.ivLockAcquired) {
                      if (timeout == -1) // -1 means wait forever     F743-21028.5
                      {
                          if (lockType == LockType.READ) {
                              if (pmiBean != null && lockStartTime == 0) // F743-9002
                              {
                                  lockStatType = EJBPMICollaborator.READ_LOCK_TIME;
                                  lockStartTime = pmiBean.initialTime(lockStatType);
                              }
                              ivReadLock.lock(); // d571981
                          } else {
                              if (pmiBean != null && lockStartTime == 0)// F743-9002
                              {
                                  lockStatType = EJBPMICollaborator.WRITE_LOCK_TIME;
                                  lockStartTime = pmiBean.initialTime(lockStatType);
                              }
                              ivWriteLock.lock(); // d571981
                          }
  
                          s.ivLockAcquired = true;
                          if (isTraceOn && tc.isDebugEnabled())
                              Tr.debug(tc, "preInvoke acquired a " + mInfo.ivLockType.name() + " lock. " + ivLock.toString());
                      } else {
                          if (lockType == LockType.READ) {
                              if (pmiBean != null && lockStartTime == 0) // F743-9002
                              {
                                  lockStatType = EJBPMICollaborator.READ_LOCK_TIME;
                                  lockStartTime = pmiBean.initialTime(lockStatType);
                              }
                              s.ivLockAcquired = ivReadLock.tryLock(timeout, TimeUnit.MILLISECONDS); // d571981
                          } else {
                              if (pmiBean != null && lockStartTime == 0) // F743-9002
                              {
                                  lockStatType = EJBPMICollaborator.WRITE_LOCK_TIME;
                                  lockStartTime = pmiBean.initialTime(lockStatType);
                              }
                              s.ivLockAcquired = ivWriteLock.tryLock(timeout, TimeUnit.MILLISECONDS); // d571981
                          }
  
                          if (s.ivLockAcquired) {
                              if (isTraceOn && tc.isDebugEnabled())
                                  Tr.debug(tc, "preInvoke acquired a " + mInfo.ivLockType.name() + " lock. " + ivLock.toString());
                          } else {
                              if (pmiBean != null) // F743-9002
                              {
                                  pmiBean.countCancelledLocks();
                              }
  
                              throw new ConcurrentAccessTimeoutException("preInvoke timed out in attempt to acquire a "
                                                                         + mInfo.ivLockType.name() + " lock for method signature = " + mInfo.getMethodSignature()
                                                                         + ".  Access timeout value = " + timeout + " milli-seconds");
                          }
                      }
                  }
              } catch (InterruptedException e) {
                  if (isTraceOn && tc.isDebugEnabled())
                      Tr.debug(tc, "InterruptedException prevented lock from being acquired.");
  
                  if (pmiBean != null) // F743-9002
                  {
                      pmiBean.countCancelledLocks();
                  }
  
                  throw ExceptionUtil.EJBException("InterruptedException prevented lock from being acquired.", e);
              } finally {
                  // F743-9002
                  // Calculate the time to obtain the lock and adjust the pmiCookie
                  // used for methodRT PMI counter to exclude the lock time.
                  if (pmiBean != null) {
                      // d648142.2
                      long lockDuration = pmiBean.finalTime(lockStatType, lockStartTime);
                      if (lockDuration > 0) {
                          s.pmiCookie += lockDuration; // d724734
                      }
                  }
              }
          }
  
          if (isTraceOn && tc.isEntryEnabled())
              Tr.exit(tc, "preInvoke");
  
          return ivEjbInstance;
      }