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(); } }
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); } }
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); } }); } }