public final void postponeCommand(final SuspendContextCommandImpl command) {
   if (!isResumed()) {
     // Important! when postponing increment the holds counter, so that the action is not released
     // too early.
     // This will ensure that the counter becomes zero only when the command is actually executed
     // or canceled
     command.hold();
     myPostponedCommands.add(command);
   } else {
     command.notifyCancelled();
   }
 }
  @Override
  public final void action() throws Exception {
    if (LOG.isDebugEnabled()) {
      LOG.debug("trying " + this);
    }

    final SuspendContextImpl suspendContext = getSuspendContext();
    if (suspendContext == null) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("skip processing - context is null " + this);
      }
      notifyCancelled();
      return;
    }

    if (suspendContext.myInProgress) {
      suspendContext.postponeCommand(this);
    } else {
      try {
        if (!suspendContext.isResumed()) {
          suspendContext.myInProgress = true;
          contextAction(suspendContext);
        } else {
          notifyCancelled();
        }
      } finally {
        suspendContext.myInProgress = false;
        if (suspendContext.isResumed()) {
          for (SuspendContextCommandImpl postponed = suspendContext.pollPostponedCommand();
              postponed != null;
              postponed = suspendContext.pollPostponedCommand()) {
            postponed.notifyCancelled();
          }
        } else {
          SuspendContextCommandImpl postponed = suspendContext.pollPostponedCommand();
          if (postponed != null) {
            final Stack<SuspendContextCommandImpl> stack = new Stack<>();
            while (postponed != null) {
              stack.push(postponed);
              postponed = suspendContext.pollPostponedCommand();
            }
            final DebuggerManagerThreadImpl managerThread =
                suspendContext.getDebugProcess().getManagerThread();
            while (!stack.isEmpty()) {
              managerThread.pushBack(stack.pop());
            }
          }
        }
      }
    }
  }
  protected void resume() {
    assertNotResumed();
    DebuggerManagerThreadImpl.assertIsManagerThread();
    try {
      if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
        for (ObjectReference objectReference : myKeptReferences) {
          DebuggerUtilsEx.enableCollection(objectReference);
        }
        myKeptReferences.clear();
      }

      for (SuspendContextCommandImpl cmd = pollPostponedCommand();
          cmd != null;
          cmd = pollPostponedCommand()) {
        cmd.notifyCancelled();
      }

      resumeImpl();
    } finally {
      myIsResumed = true;
    }
  }
  public boolean processLocatableEvent(
      final SuspendContextCommandImpl action, final LocatableEvent event)
      throws EventProcessingException {
    final SuspendContextImpl context = action.getSuspendContext();
    if (!isValid()) {
      context.getDebugProcess().getRequestsManager().deleteRequest(this);
      return false;
    }

    final String[] title = {DebuggerBundle.message("title.error.evaluating.breakpoint.condition")};

    try {
      final StackFrameProxyImpl frameProxy = context.getThread().frame(0);
      if (frameProxy == null) {
        // might be if the thread has been collected
        return false;
      }

      final EvaluationContextImpl evaluationContext =
          new EvaluationContextImpl(
              action.getSuspendContext(), frameProxy, getThisObject(context, event));

      if (!evaluateCondition(evaluationContext, event)) {
        return false;
      }

      title[0] = DebuggerBundle.message("title.error.evaluating.breakpoint.action");
      runAction(evaluationContext, event);
    } catch (final EvaluateException ex) {
      if (ApplicationManager.getApplication().isUnitTestMode()) {
        System.out.println(ex.getMessage());
        return false;
      }

      throw new EventProcessingException(title[0], ex.getMessage(), ex);
    }

    return true;
  }
  protected static boolean scheduleCommand(
      EvaluationContextImpl evaluationContext,
      @NotNull final XCompositeNode node,
      final SuspendContextCommandImpl command) {
    evaluationContext
        .getManagerThread()
        .schedule(
            new SuspendContextCommandImpl(command.getSuspendContext()) {
              @Override
              public void contextAction() throws Exception {
                command.contextAction();
              }

              @Override
              protected void commandCancelled() {
                node.setErrorMessage(DebuggerBundle.message("error.context.has.changed"));
              }
            });
    return true;
  }