mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
reduce contention
This commit is contained in:
+186
-145
@@ -19,6 +19,7 @@ import com.intellij.BundleBase;
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.diagnostic.PerformanceWatcher;
|
||||
import com.intellij.diagnostic.PluginException;
|
||||
import com.intellij.diagnostic.ThreadDumper;
|
||||
import com.intellij.ide.*;
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.ide.plugins.PluginManagerCore;
|
||||
@@ -80,7 +81,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
@SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"})
|
||||
public class ApplicationImpl extends PlatformComponentManagerImpl implements ApplicationEx {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.application.impl.ApplicationImpl");
|
||||
private final ModalityState MODALITY_STATE_NONE = ModalityState.NON_MODAL;
|
||||
@@ -96,7 +96,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
private IApplicationStore myComponentStore;
|
||||
|
||||
private boolean myTestModeFlag;
|
||||
private final boolean myTestModeFlag;
|
||||
private final boolean myHeadlessMode;
|
||||
private final boolean myCommandLineMode;
|
||||
|
||||
@@ -107,12 +107,12 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
private volatile Runnable myExceptionalThreadWithReadAccessRunnable;
|
||||
|
||||
private int myInEditorPaintCounter = 0;
|
||||
private long myStartTime = 0;
|
||||
private int myInEditorPaintCounter; // EDT only
|
||||
private final long myStartTime;
|
||||
@Nullable
|
||||
private final Splash mySplash;
|
||||
private boolean myDoNotSave;
|
||||
private volatile boolean myDisposeInProgress = false;
|
||||
private volatile boolean myDisposeInProgress;
|
||||
|
||||
private final Disposable myLastDisposable = Disposer.newDisposable(); // will be disposed last
|
||||
|
||||
@@ -171,7 +171,30 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
private Boolean myActive;
|
||||
|
||||
private static final ThreadLocal<Integer> ourEdtSafe = new ThreadLocal<Integer>();
|
||||
private static final int IS_EDT_FLAG = 1<<30; // we don't mess with sign bit since we want to do arithmetic
|
||||
private static final int IS_READ_LOCK_ACQUIRED_FLAG = 1<<29;
|
||||
private static final int IS_EXCEPTIONAL_THREAD_FLAG = 1<<28;
|
||||
private static class Status {
|
||||
// higher three bits are for IS_* flags
|
||||
// lower bits are for edtSafe counter
|
||||
private int flags;
|
||||
}
|
||||
|
||||
private static final ThreadLocal<Status> status = new ThreadLocal<Status>(){
|
||||
@Override
|
||||
protected Status initialValue() {
|
||||
Status status = new Status();
|
||||
status.flags = BitUtil.set(status.flags, IS_EDT_FLAG, EventQueue.isDispatchThread());
|
||||
return status;
|
||||
}
|
||||
};
|
||||
private static Status getStatus() {
|
||||
return status.get();
|
||||
}
|
||||
private static void setReadLockAcquired(Status status, boolean acquired) {
|
||||
status.flags = BitUtil.set(status.flags, IS_READ_LOCK_ACQUIRED_FLAG, acquired);
|
||||
}
|
||||
|
||||
@NonNls private static final ModalityState ANY = new ModalityState() {
|
||||
@Override
|
||||
public boolean dominates(@NotNull ModalityState anotherState) {
|
||||
@@ -201,7 +224,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeComponent(Object component, boolean service) {
|
||||
public void initializeComponent(@NotNull Object component, boolean service) {
|
||||
getStateStore().initComponent(component, service);
|
||||
}
|
||||
|
||||
@@ -233,7 +256,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
myHeadlessMode = isHeadless;
|
||||
myCommandLineMode = isCommandLine;
|
||||
|
||||
myDoNotSave = myTestModeFlag || myHeadlessMode;
|
||||
myDoNotSave = isUnitTestMode || isHeadless;
|
||||
|
||||
loadApplicationComponents();
|
||||
|
||||
@@ -353,7 +376,11 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
@Override
|
||||
public boolean holdsReadLock() {
|
||||
return myLock.getReadHoldCount() != 0;
|
||||
return holdsReadLock(getStatus());
|
||||
}
|
||||
|
||||
private static boolean holdsReadLock(Status status) {
|
||||
return BitUtil.isSet(status.flags, IS_READ_LOCK_ACQUIRED_FLAG);
|
||||
}
|
||||
|
||||
private void loadApplicationComponents() {
|
||||
@@ -367,7 +394,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized Object createComponent(Class componentInterface) {
|
||||
protected synchronized Object createComponent(@NotNull Class componentInterface) {
|
||||
Object component = super.createComponent(componentInterface);
|
||||
if (mySplash != null) {
|
||||
mySplash.showProgress("", 0.65f + getPercentageOfComponentsLoaded() * 0.35f);
|
||||
@@ -375,6 +402,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
return component;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected MutablePicoContainer createPicoContainer() {
|
||||
return Extensions.getRootArea().getPicoContainer();
|
||||
@@ -395,10 +423,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
return myTestModeFlag;
|
||||
}
|
||||
|
||||
public void setUnitTestMode(boolean testModeFlag) {
|
||||
myTestModeFlag = testModeFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHeadlessEnvironment() {
|
||||
return myHeadlessMode;
|
||||
@@ -415,6 +439,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
return ourThreadExecutorsService.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isReadAccessAllowed()) {
|
||||
assert false : describe(Thread.currentThread());
|
||||
}
|
||||
try {
|
||||
action.run();
|
||||
}
|
||||
@@ -427,6 +454,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
finally {
|
||||
//ReflectionUtil.resetThreadLocals();
|
||||
Thread.interrupted(); // reset interrupted status
|
||||
if (isReadAccessAllowed()) {
|
||||
assert false : describe(Thread.currentThread());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -438,6 +468,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
return ourThreadExecutorsService.submit(new Callable<T>() {
|
||||
@Override
|
||||
public T call() {
|
||||
if (isReadAccessAllowed()) {
|
||||
assert false : describe(Thread.currentThread());
|
||||
}
|
||||
try {
|
||||
return action.call();
|
||||
}
|
||||
@@ -450,17 +483,22 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
finally {
|
||||
//ReflectionUtil.resetThreadLocals();
|
||||
Thread.interrupted(); // reset interrupted status
|
||||
if (isReadAccessAllowed()) {
|
||||
assert false : describe(Thread.currentThread());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Thread ourDispatchThread = null;
|
||||
|
||||
@Override
|
||||
public boolean isDispatchThread() {
|
||||
return EventQueue.isDispatchThread();
|
||||
return isDispatchThread(getStatus());
|
||||
}
|
||||
|
||||
private static boolean isDispatchThread(Status status) {
|
||||
return BitUtil.isSet(status.flags, IS_EDT_FLAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -535,7 +573,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> T getComponentFromContainer(final Class<T> interfaceClass) {
|
||||
protected <T> T getComponentFromContainer(@NotNull final Class<T> interfaceClass) {
|
||||
if (myIsFiringLoadingEvent) {
|
||||
return null;
|
||||
}
|
||||
@@ -567,13 +605,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
Disposer.dispose(myLastDisposable); // dispose it last
|
||||
}
|
||||
|
||||
private final Object lock = new Object();
|
||||
private void makeChangesVisibleToEDT() {
|
||||
synchronized (lock) {
|
||||
lock.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean runProcessWithProgressSynchronously(@NotNull final Runnable process,
|
||||
@NotNull String progressTitle,
|
||||
@@ -629,7 +660,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
@Override
|
||||
public void run() {
|
||||
if (myExceptionalThreadWithReadAccessRunnable != process) {
|
||||
LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable);
|
||||
LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable);
|
||||
}
|
||||
|
||||
executeOnPooledThread(new Runnable() {
|
||||
@@ -639,9 +670,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable);
|
||||
}
|
||||
|
||||
final boolean old = setExceptionalThreadWithReadAccessFlag(true);
|
||||
LOG.assertTrue(isReadAccessAllowed());
|
||||
setExceptionalThreadWithReadAccessFlag(true);
|
||||
try {
|
||||
LOG.assertTrue(isReadAccessAllowed());
|
||||
ProgressManager.getInstance().runProcess(process, progress);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
@@ -653,8 +684,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
setExceptionalThreadWithReadAccessFlag(old);
|
||||
makeChangesVisibleToEDT();
|
||||
setExceptionalThreadWithReadAccessFlag(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -669,7 +699,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
}
|
||||
finally {
|
||||
myExceptionalThreadWithReadAccessRunnable = null;
|
||||
makeChangesVisibleToEDT();
|
||||
}
|
||||
|
||||
return !progress.isCanceled();
|
||||
@@ -677,12 +706,13 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
@Override
|
||||
public void invokeAndWait(@NotNull Runnable runnable, @NotNull ModalityState modalityState) {
|
||||
if (isDispatchThread()) {
|
||||
Status status = getStatus();
|
||||
if (isDispatchThread(status)) {
|
||||
runnable.run();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isExceptionalThreadWithReadAccess() && holdsReadLock()) {
|
||||
if (!isExceptionalThreadWithReadAccess(status) && holdsReadLock(status)) {
|
||||
LOG.error("Calling invokeAndWait from read-action leads to possible deadlock.");
|
||||
}
|
||||
|
||||
@@ -712,13 +742,11 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
@Override
|
||||
@NotNull
|
||||
public ModalityState getDefaultModalityState() {
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
if (isDispatchThread()) {
|
||||
return getCurrentModalityState();
|
||||
}
|
||||
else {
|
||||
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
return progress == null ? getNoneModalityState() : progress.getModalityState();
|
||||
}
|
||||
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
return progress == null ? getNoneModalityState() : progress.getModalityState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -769,7 +797,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
private static volatile boolean exiting = false;
|
||||
|
||||
public void exit(final boolean force, final boolean allowListenersToCancel, final boolean restart) {
|
||||
|
||||
if (exiting) return;
|
||||
|
||||
exiting = true;
|
||||
@@ -788,19 +815,19 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
getMessageBus().syncPublisher(AppLifecycleListener.TOPIC).appClosing();
|
||||
myDisposeInProgress = true;
|
||||
if (!doExit(allowListenersToCancel, restart)) {
|
||||
myDisposeInProgress = false;
|
||||
}
|
||||
doExit(allowListenersToCancel, restart);
|
||||
myDisposeInProgress = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (!isDispatchThread()) {
|
||||
invokeLater(runnable, ModalityState.NON_MODAL);
|
||||
}
|
||||
else {
|
||||
if (isDispatchThread()) {
|
||||
runnable.run();
|
||||
}
|
||||
} finally {
|
||||
else {
|
||||
invokeLater(runnable, ModalityState.NON_MODAL);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
exiting = false;
|
||||
}
|
||||
}
|
||||
@@ -857,6 +884,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDoNotShowMessage() {
|
||||
return "Do not ask me again";
|
||||
@@ -896,13 +924,15 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
@Override
|
||||
public void runReadAction(@NotNull final Runnable action) {
|
||||
if (isReadAccessAllowed()) {
|
||||
Status status = getStatus();
|
||||
if (isReadAccessAllowed(status)) {
|
||||
action.run();
|
||||
}
|
||||
else {
|
||||
assertReadActionAllowed();
|
||||
assertNoPsiLock();
|
||||
try {
|
||||
myLock.readLock().lockInterruptibly();
|
||||
setReadLockAcquired(status, true);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeInterruptedException(e);
|
||||
@@ -911,70 +941,66 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
action.run();
|
||||
}
|
||||
finally {
|
||||
setReadLockAcquired(status, false);
|
||||
myLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public <T> T runReadAction(@NotNull final Computable<T> computation) {
|
||||
if (isReadAccessAllowed()) {
|
||||
Status status = getStatus();
|
||||
if (isReadAccessAllowed(status)) {
|
||||
return computation.compute();
|
||||
}
|
||||
else {
|
||||
assertReadActionAllowed();
|
||||
try {
|
||||
myLock.readLock().lockInterruptibly();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeInterruptedException(e);
|
||||
}
|
||||
try {
|
||||
return computation.compute();
|
||||
}
|
||||
finally {
|
||||
myLock.readLock().unlock();
|
||||
}
|
||||
assertNoPsiLock();
|
||||
try {
|
||||
myLock.readLock().lockInterruptibly();
|
||||
setReadLockAcquired(status, true);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeInterruptedException(e);
|
||||
}
|
||||
try {
|
||||
return computation.compute();
|
||||
}
|
||||
finally {
|
||||
setReadLockAcquired(status, false);
|
||||
myLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, E extends Throwable> T runReadAction(@NotNull ThrowableComputable<T, E> computation) throws E {
|
||||
if (isReadAccessAllowed()) {
|
||||
Status status = getStatus();
|
||||
if (isReadAccessAllowed(status)) {
|
||||
return computation.compute();
|
||||
}
|
||||
else {
|
||||
assertReadActionAllowed();
|
||||
try {
|
||||
myLock.readLock().lockInterruptibly();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeInterruptedException(e);
|
||||
}
|
||||
try {
|
||||
return computation.compute();
|
||||
}
|
||||
finally {
|
||||
myLock.readLock().unlock();
|
||||
}
|
||||
assertNoPsiLock();
|
||||
try {
|
||||
myLock.readLock().lockInterruptibly();
|
||||
setReadLockAcquired(status, true);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeInterruptedException(e);
|
||||
}
|
||||
try {
|
||||
return computation.compute();
|
||||
}
|
||||
finally {
|
||||
setReadLockAcquired(status, false);
|
||||
myLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static final ThreadLocal<Boolean> exceptionalThreadWithReadAccessFlag = new ThreadLocal<Boolean>();
|
||||
|
||||
private static boolean isExceptionalThreadWithReadAccess() {
|
||||
Boolean flag = exceptionalThreadWithReadAccessFlag.get();
|
||||
return flag == Boolean.TRUE;
|
||||
private static boolean isExceptionalThreadWithReadAccess(Status status) {
|
||||
return BitUtil.isSet(status.flags, IS_EXCEPTIONAL_THREAD_FLAG);
|
||||
}
|
||||
|
||||
public static boolean setExceptionalThreadWithReadAccessFlag(boolean flag) {
|
||||
boolean old = isExceptionalThreadWithReadAccess();
|
||||
if (flag) {
|
||||
exceptionalThreadWithReadAccessFlag.set(Boolean.TRUE);
|
||||
}
|
||||
else {
|
||||
exceptionalThreadWithReadAccessFlag.remove();
|
||||
}
|
||||
return old;
|
||||
public static void setExceptionalThreadWithReadAccessFlag(boolean flag) {
|
||||
Status status = getStatus();
|
||||
assert !isDispatchThread(status) : "exceptional thread must not be EDT";
|
||||
assert flag != isReadAccessAllowed(status) : "must not start exceptional thread from inside read action";
|
||||
status.flags = BitUtil.set(status.flags, IS_EXCEPTIONAL_THREAD_FLAG, flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1012,7 +1038,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
@Override
|
||||
public boolean hasWriteAction(@Nullable Class<?> actionClass) {
|
||||
assertCanRunWriteAction();
|
||||
assertCanRunWriteAction(getStatus());
|
||||
|
||||
for (int i = myWriteActionsStack.size() - 1; i >= 0; i--) {
|
||||
Class action = myWriteActionsStack.get(i);
|
||||
@@ -1028,7 +1054,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
LOG.error(
|
||||
"Read access is allowed from event dispatch thread or inside read-action only" +
|
||||
" (see com.intellij.openapi.application.Application.runReadAction())",
|
||||
"Current thread: " + describe(Thread.currentThread()), "Our dispatch thread:" + describe(ourDispatchThread),
|
||||
"Current thread: " + describe(Thread.currentThread()), "; dispatch thread: " + EventQueue.isDispatchThread() +"; isDispatchThread(): "+isDispatchThread(),
|
||||
"SystemEventQueueThread: " + describe(getEventQueueThread()));
|
||||
}
|
||||
}
|
||||
@@ -1039,7 +1065,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
return o + " " + System.identityHashCode(o);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Thread getEventQueueThread() {
|
||||
EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
|
||||
try {
|
||||
@@ -1047,63 +1072,63 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
method.setAccessible(true);
|
||||
return (Thread)method.invoke(eventQueue);
|
||||
}
|
||||
catch (Exception e1) {
|
||||
// ok
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadAccessAllowed() {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
return ourDispatchThread == currentThread ||
|
||||
isExceptionalThreadWithReadAccess() ||
|
||||
holdsReadLock() ||
|
||||
isDispatchThread();
|
||||
return isReadAccessAllowed(getStatus());
|
||||
}
|
||||
|
||||
private static void assertCanRunWriteAction() {
|
||||
assertIsDispatchThread("Write access is allowed from event dispatch thread only");
|
||||
private static boolean isReadAccessAllowed(Status status) {
|
||||
return (status.flags & (IS_EDT_FLAG | IS_EXCEPTIONAL_THREAD_FLAG | IS_READ_LOCK_ACQUIRED_FLAG)) != 0;
|
||||
}
|
||||
|
||||
private static void assertCanRunWriteAction(Status status) {
|
||||
assertIsDispatchThread(status, "Write access is allowed from event dispatch thread only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertIsDispatchThread() {
|
||||
if (ShutDownTracker.isShutdownHookRunning()) return;
|
||||
Integer safeCounter = ourEdtSafe.get();
|
||||
if (safeCounter != null && safeCounter > 0) return;
|
||||
assertIsDispatchThread("Access is allowed from event dispatch thread only.");
|
||||
assertIsDispatchThread(getStatus());
|
||||
}
|
||||
|
||||
private static void assertIsDispatchThread(@NotNull String message) {
|
||||
final Thread currentThread = Thread.currentThread();
|
||||
if (ourDispatchThread == currentThread) return;
|
||||
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
ourDispatchThread = currentThread;
|
||||
private static void assertIsDispatchThread(Status status) {
|
||||
if (isDispatchThread(status)) return;
|
||||
if (ShutDownTracker.isShutdownHookRunning()) return;
|
||||
int safeCounter = getSafeCounter(status);
|
||||
if (safeCounter == 0) {
|
||||
assertIsDispatchThread(status, "Access is allowed from event dispatch thread only.");
|
||||
}
|
||||
if (ourDispatchThread == currentThread) return;
|
||||
}
|
||||
|
||||
private static int getSafeCounter(Status status) {
|
||||
return status.flags & 0x1fffffff;
|
||||
}
|
||||
|
||||
private static void assertIsDispatchThread(Status status, @NotNull String message) {
|
||||
if (isDispatchThread(status)) return;
|
||||
LOG.error(message,
|
||||
"EventQueue.isDispatchThread()="+EventQueue.isDispatchThread(),
|
||||
"isDispatchThread()="+isDispatchThread(getStatus()),
|
||||
"Toolkit.getEventQueue()="+Toolkit.getDefaultToolkit().getSystemEventQueue(),
|
||||
"Current thread: " + describe(Thread.currentThread()),
|
||||
"Our dispatch thread:" + describe(ourDispatchThread),
|
||||
"SystemEventQueueThread: " + describe(getEventQueueThread()));
|
||||
"SystemEventQueueThread: " + describe(getEventQueueThread()) +"\n"+ ThreadDumper.dumpThreadsToString()+"\n-----------");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runEdtSafeAction(@NotNull Runnable runnable) {
|
||||
Integer value = ourEdtSafe.get();
|
||||
if (value == null) {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
ourEdtSafe.set(value + 1);
|
||||
Status status = getStatus();
|
||||
LOG.assertTrue(getSafeCounter(status) < 1<<26);
|
||||
status.flags++;
|
||||
|
||||
try {
|
||||
runnable.run();
|
||||
}
|
||||
finally {
|
||||
int newValue = ourEdtSafe.get() - 1;
|
||||
ourEdtSafe.set(newValue >= 1 ? newValue : null);
|
||||
status.flags--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1111,19 +1136,19 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
public void assertIsDispatchThread(@Nullable final JComponent component) {
|
||||
if (component == null) return;
|
||||
|
||||
Thread curThread = Thread.currentThread();
|
||||
if (ourDispatchThread == curThread) {
|
||||
Status status = getStatus();
|
||||
if (isDispatchThread(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Boolean.TRUE.equals(component.getClientProperty(WAS_EVER_SHOWN))) {
|
||||
assertIsDispatchThread();
|
||||
assertIsDispatchThread(status);
|
||||
}
|
||||
else {
|
||||
final JRootPane root = component.getRootPane();
|
||||
if (root != null) {
|
||||
component.putClientProperty(WAS_EVER_SHOWN, Boolean.TRUE);
|
||||
assertIsDispatchThread();
|
||||
assertIsDispatchThread(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1136,14 +1161,16 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
@Override
|
||||
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
|
||||
boolean mustAcquire = !isReadAccessAllowed();
|
||||
Status status = getStatus();
|
||||
//if we are inside read action, do not try to acquire read lock again since it will deadlock if there is a pending writeAction
|
||||
boolean mustAcquire = !isReadAccessAllowed(status);
|
||||
|
||||
if (mustAcquire) {
|
||||
LOG.assertTrue(myTestModeFlag || !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction");
|
||||
assertNoPsiLock();
|
||||
try {
|
||||
// timed version of tryLock() respects fairness unlike the no-args method
|
||||
if (!myLock.readLock().tryLock(0, TimeUnit.MILLISECONDS)) return false;
|
||||
setReadLockAcquired(status, true);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeInterruptedException(e);
|
||||
@@ -1155,6 +1182,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
}
|
||||
finally {
|
||||
if (mustAcquire) {
|
||||
setReadLockAcquired(status, false);
|
||||
myLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
@@ -1167,7 +1195,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
if (frame instanceof IdeFrame) {
|
||||
final IdeFrame ideFrame = (IdeFrame)frame;
|
||||
if (isActive() != active) {
|
||||
myActive = Boolean.valueOf(active);
|
||||
myActive = active;
|
||||
System.setProperty("idea.active", myActive.toString());
|
||||
ApplicationActivationListener publisher = getMessageBus().syncPublisher(ApplicationActivationListener.TOPIC);
|
||||
if (active) {
|
||||
@@ -1198,10 +1226,11 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
@NotNull
|
||||
@Override
|
||||
public AccessToken acquireReadActionLock() {
|
||||
Status status = getStatus();
|
||||
// if we are inside read action, do not try to acquire read lock again since it will deadlock if there is a pending writeAction
|
||||
if (isReadAccessAllowed()) return AccessToken.EMPTY_ACCESS_TOKEN;
|
||||
if (isReadAccessAllowed(status)) return AccessToken.EMPTY_ACCESS_TOKEN;
|
||||
|
||||
return new ReadAccessToken();
|
||||
return new ReadAccessToken(status);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -1215,13 +1244,16 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
public WriteAccessToken(Class _clazz) {
|
||||
clazz = _clazz;
|
||||
assertCanRunWriteAction();
|
||||
assertCanRunWriteAction(getStatus());
|
||||
|
||||
ActivityTracker.getInstance().inc();
|
||||
fireBeforeWriteActionStart(_clazz);
|
||||
final AtomicBoolean stopped = new AtomicBoolean(false);
|
||||
|
||||
LOG.assertTrue(isWriteAccessAllowed() || !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing writeAction");
|
||||
if (!isWriteAccessAllowed()) {
|
||||
assertNoPsiLock();
|
||||
}
|
||||
|
||||
try {
|
||||
if (!myLock.writeLock().tryLock()) {
|
||||
if (ourDumpThreadsOnLongWriteActionWaiting > 0) {
|
||||
@@ -1304,10 +1336,14 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
}
|
||||
|
||||
private class ReadAccessToken extends AccessToken {
|
||||
private ReadAccessToken() {
|
||||
assertReadActionAllowed();
|
||||
private final Status myStatus;
|
||||
|
||||
private ReadAccessToken(Status status) {
|
||||
myStatus = status;
|
||||
assertNoPsiLock();
|
||||
try {
|
||||
myLock.readLock().lockInterruptibly();
|
||||
setReadLockAcquired(myStatus, true);
|
||||
acquired();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
@@ -1317,13 +1353,18 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
setReadLockAcquired(myStatus, false);
|
||||
myLock.readLock().unlock();
|
||||
released();
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertReadActionAllowed() {
|
||||
LOG.assertTrue(!Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction");
|
||||
private final boolean myExtraChecks = isUnitTestMode();
|
||||
|
||||
private void assertNoPsiLock() {
|
||||
if (myExtraChecks) {
|
||||
LOG.assertTrue(!Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1334,12 +1375,12 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
|
||||
|
||||
@Override
|
||||
public boolean isWriteAccessAllowed() {
|
||||
return myLock.writeLock().isHeldByCurrentThread();
|
||||
return myLock.isWriteLockedByCurrentThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteActionInProgress() {
|
||||
return myLock.writeLock().getHoldCount() != 0;
|
||||
return myLock.getWriteHoldCount() != 0;
|
||||
}
|
||||
|
||||
public void editorPaintStart() {
|
||||
|
||||
Reference in New Issue
Block a user