예제 #1
1
  public void runReadAction(@NotNull final Runnable action) {
    /**
     * if we are inside read action, do not try to acquire read lock again since it will deadlock if
     * there is a pending writeAction see {@link
     * com.intellij.util.concurrency.ReentrantWriterPreferenceReadWriteLock#allowReader()}
     */
    if (isReadAccessAllowed()) {
      action.run();
      return;
    }

    LOG.assertTrue(
        !Thread.holdsLock(PsiLock.LOCK),
        "Thread must not hold PsiLock while performing readAction");
    try {
      myActionsLock.readLock().acquire();
    } catch (InterruptedException e) {
      throw new RuntimeInterruptedException(e);
    }

    try {
      action.run();
    } finally {
      myActionsLock.readLock().release();
    }
  }
예제 #2
1
  public boolean tryRunReadAction(@NotNull Runnable action) {
    /**
     * if we are inside read action, do not try to acquire read lock again since it will deadlock if
     * there is a pending writeAction see {@link
     * com.intellij.util.concurrency.ReentrantWriterPreferenceReadWriteLock#allowReader()}
     */
    boolean mustAcquire = !isReadAccessAllowed();

    if (mustAcquire) {
      LOG.assertTrue(
          myTestModeFlag || !Thread.holdsLock(PsiLock.LOCK),
          "Thread must not hold PsiLock while performing readAction");
      try {
        if (!myActionsLock.readLock().attempt(0)) return false;
      } catch (InterruptedException e) {
        throw new RuntimeInterruptedException(e);
      }
    }

    try {
      action.run();
    } finally {
      if (mustAcquire) {
        myActionsLock.readLock().release();
      }
    }
    return true;
  }
 ReadAccessToken(boolean explicit) {
   myExplicit = explicit;
   LOG.assertTrue(
       !Thread.holdsLock(PsiLock.LOCK),
       "Thread must not hold PsiLock while performing readAction");
   try {
     myActionsLock.readLock().acquire();
     if (myExplicit) acquired();
   } catch (InterruptedException e) {
     throw new RuntimeInterruptedException(e);
   }
 }
예제 #4
0
  public void runWriteAction(@NotNull final Runnable action) {
    assertCanRunWriteAction();

    ActivityTracker.getInstance().inc();
    fireBeforeWriteActionStart(action);
    final AtomicBoolean stopped = new AtomicBoolean(false);

    if (ourDumpThreadsOnLongWriteActionWaiting > 0) {
      executeOnPooledThread(
          new Runnable() {
            @Override
            public void run() {
              while (!stopped.get()) {
                try {
                  Thread.sleep(ourDumpThreadsOnLongWriteActionWaiting);
                  if (!stopped.get()) {
                    PerformanceWatcher.getInstance().dumpThreads(true);
                  }
                } catch (InterruptedException ignored) {
                }
              }
            }
          });
    }

    LOG.assertTrue(
        myActionsLock.isWriteLockAcquired(Thread.currentThread())
            || !Thread.holdsLock(PsiLock.LOCK),
        "Thread must not hold PsiLock while performing writeAction");
    try {
      myActionsLock.writeLock().acquire();
    } catch (InterruptedException e) {
      throw new RuntimeInterruptedException(e);
    }
    stopped.set(true);

    try {
      myWriteActionsStack.push(action);

      fireWriteActionStarted(action);

      action.run();
    } finally {
      try {
        fireWriteActionFinished(action);

        myWriteActionsStack.pop();
      } finally {
        myActionsLock.writeLock().release();
      }
    }
  }
  public void startRunInjectors(@NotNull final Document hostDocument, final boolean synchronously) {
    if (myProject.isDisposed()) return;
    if (!synchronously && ApplicationManager.getApplication().isWriteAccessAllowed()) return;
    // use cached to avoid recreate PSI in alien project
    final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
    final PsiFile hostPsiFile = documentManager.getCachedPsiFile(hostDocument);
    if (hostPsiFile == null) return;

    final CopyOnWriteArrayList<DocumentWindow> injected =
        (CopyOnWriteArrayList<DocumentWindow>)
            InjectedLanguageUtil.getCachedInjectedDocuments(hostPsiFile);
    if (injected.isEmpty()) return;

    if (myProgress.isCanceled()) {
      myProgress = new DaemonProgressIndicator();
    }

    final Processor<DocumentWindow> commitProcessor =
        new Processor<DocumentWindow>() {
          @Override
          public boolean process(DocumentWindow documentWindow) {
            if (myProject.isDisposed()) return false;
            ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
            if (indicator != null && indicator.isCanceled()) return false;
            if (documentManager.isUncommited(hostDocument) || !hostPsiFile.isValid())
              return false; // will be committed later

            Segment[] ranges = documentWindow.getHostRanges();
            Segment rangeMarker = ranges.length > 0 ? ranges[0] : null;
            PsiElement element =
                rangeMarker == null
                    ? null
                    : hostPsiFile.findElementAt(rangeMarker.getStartOffset());
            if (element == null) {
              synchronized (PsiLock.LOCK) {
                injected.remove(documentWindow);
              }
              return true;
            }
            final DocumentWindow[] stillInjectedDocument = {null};
            // it is here where the reparse happens and old file contents replaced
            InjectedLanguageUtil.enumerate(
                element,
                hostPsiFile,
                true,
                new PsiLanguageInjectionHost.InjectedPsiVisitor() {
                  @Override
                  public void visit(
                      @NotNull PsiFile injectedPsi,
                      @NotNull List<PsiLanguageInjectionHost.Shred> places) {
                    stillInjectedDocument[0] =
                        (DocumentWindow) injectedPsi.getViewProvider().getDocument();
                    PsiDocumentManagerImpl.checkConsistency(injectedPsi, stillInjectedDocument[0]);
                  }
                });
            synchronized (PsiLock.LOCK) {
              if (stillInjectedDocument[0] == null) {
                injected.remove(documentWindow);
              } else if (stillInjectedDocument[0] != documentWindow) {
                injected.remove(documentWindow);
                injected.addIfAbsent(stillInjectedDocument[0]);
              }
            }

            return true;
          }
        };
    final Runnable commitInjectionsRunnable =
        new Runnable() {
          @Override
          public void run() {
            if (myProgress.isCanceled()) return;
            JobLauncher.getInstance()
                .invokeConcurrentlyUnderProgress(
                    new ArrayList<DocumentWindow>(injected),
                    myProgress,
                    !synchronously,
                    commitProcessor);
          }
        };

    if (synchronously) {
      if (Thread.holdsLock(PsiLock.LOCK)) {
        // hack for the case when docCommit was called from within PSI modification, e.g. in
        // formatter.
        // we can't spawn threads to do injections there, otherwise a deadlock is imminent
        ContainerUtil.process(new ArrayList<DocumentWindow>(injected), commitProcessor);
      } else {
        commitInjectionsRunnable.run();
      }
    } else {
      JobLauncher.getInstance()
          .submitToJobThread(
              Job.DEFAULT_PRIORITY,
              new Runnable() {
                @Override
                public void run() {
                  ApplicationManagerEx.getApplicationEx()
                      .tryRunReadAction(commitInjectionsRunnable);
                }
              });
    }
  }