mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
prevent AWT auto shutdown, don't create app in EDT
GitOrigin-RevId: 861d20e85bdee38f4ef371984ae360c5ff8310d8
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6486e5b086
commit
b15e34043d
@@ -3,6 +3,7 @@
|
||||
@file:ApiStatus.Internal
|
||||
package com.intellij.idea
|
||||
|
||||
import com.intellij.BundleBase
|
||||
import com.intellij.diagnostic.*
|
||||
import com.intellij.diagnostic.StartUpMeasurer.Activities
|
||||
import com.intellij.icons.AllIcons
|
||||
@@ -35,9 +36,9 @@ import com.intellij.util.io.createDirectories
|
||||
import com.intellij.util.io.storage.HeavyProcessLatch
|
||||
import com.intellij.util.lang.ZipFilePool
|
||||
import com.intellij.util.ui.AsyncProcessIcon
|
||||
import com.intellij.util.ui.EDT
|
||||
import net.miginfocom.layout.PlatformDefaults
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.awt.EventQueue
|
||||
import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Files
|
||||
@@ -52,61 +53,61 @@ private val SAFE_JAVA_ENV_PARAMETERS = arrayOf(JetBrainsProtocolHandler.REQUIRED
|
||||
private val LOG = Logger.getInstance("#com.intellij.idea.ApplicationLoader")
|
||||
|
||||
fun initApplication(rawArgs: List<String>, prepareUiFuture: CompletionStage<*>) {
|
||||
val args = processProgramArguments(rawArgs)
|
||||
|
||||
val initAppActivity = StartupUtil.startupStart.endAndStart(Activities.INIT_APP)
|
||||
val loadAndInitPluginFutureActivity = initAppActivity.startChild("plugin descriptor init waiting")
|
||||
val loadAndInitPluginFuture = PluginManagerCore.initPlugins(StartupUtil::class.java.classLoader)
|
||||
loadAndInitPluginFuture.thenRun(loadAndInitPluginFutureActivity::end)
|
||||
|
||||
// use main thread, avoid thread switching
|
||||
(prepareUiFuture as CompletableFuture<*>).join()
|
||||
prepareUiFuture.thenComposeAsync({
|
||||
val isInternal = java.lang.Boolean.getBoolean(ApplicationManagerEx.IS_INTERNAL_PROPERTY)
|
||||
val app = ApplicationImpl(isInternal, false, Main.isHeadless(), Main.isCommandLine(), EDT.getEventDispatchThread()
|
||||
?: throw IllegalStateException("Init UI first"))
|
||||
(UIManager.getLookAndFeel() as? DarculaLaf)?.appCreated(app)
|
||||
|
||||
val args = processProgramArguments(rawArgs)
|
||||
EventQueue.invokeLater {
|
||||
runActivity("create app") {
|
||||
val isInternal = java.lang.Boolean.getBoolean(ApplicationManagerEx.IS_INTERNAL_PROPERTY)
|
||||
ApplicationImpl(isInternal, false, Main.isHeadless(), Main.isCommandLine()) { app ->
|
||||
(UIManager.getLookAndFeel() as? DarculaLaf)?.appCreated(app)
|
||||
if (isInternal) {
|
||||
BundleBase.assertOnMissedKeys(true)
|
||||
}
|
||||
|
||||
loadAndInitPluginFuture
|
||||
.thenAcceptAsync({ plugins ->
|
||||
runActivity("app component registration") {
|
||||
app.registerComponents(plugins, app, null)
|
||||
}
|
||||
loadAndInitPluginFuture
|
||||
.thenAccept { plugins ->
|
||||
runActivity("app component registration") {
|
||||
app.registerComponents(plugins, app, null)
|
||||
}
|
||||
|
||||
if (args.isEmpty()) {
|
||||
startApp(app, IdeStarter(), initAppActivity, plugins, args)
|
||||
}
|
||||
else {
|
||||
// `ApplicationStarter` is an extension, so to find a starter extensions must be registered first
|
||||
findCustomAppStarterAndStart(plugins, args, app, initAppActivity)
|
||||
}
|
||||
if (args.isEmpty()) {
|
||||
startApp(app, IdeStarter(), initAppActivity, plugins, args)
|
||||
}
|
||||
else {
|
||||
// `ApplicationStarter` is an extension, so to find a starter extensions must be registered first
|
||||
findCustomAppStarterAndStart(plugins, args, app, initAppActivity)
|
||||
}
|
||||
|
||||
if (!Main.isHeadless()) {
|
||||
ForkJoinPool.commonPool().execute {
|
||||
runActivity("icons preloading") {
|
||||
if (isInternal) {
|
||||
IconLoader.setStrictGlobally(true)
|
||||
}
|
||||
if (!Main.isHeadless()) {
|
||||
ForkJoinPool.commonPool().execute {
|
||||
runActivity("icons preloading") {
|
||||
if (isInternal) {
|
||||
IconLoader.setStrictGlobally(true)
|
||||
}
|
||||
|
||||
AsyncProcessIcon("")
|
||||
AnimatedIcon.Blinking(AllIcons.Ide.FatalError)
|
||||
AnimatedIcon.FS()
|
||||
}
|
||||
AsyncProcessIcon("")
|
||||
AnimatedIcon.Blinking(AllIcons.Ide.FatalError)
|
||||
AnimatedIcon.FS()
|
||||
}
|
||||
|
||||
runActivity("migLayout") {
|
||||
// IDEA-170295
|
||||
PlatformDefaults.setLogicalPixelBase(PlatformDefaults.BASE_FONT_SIZE)
|
||||
}
|
||||
}
|
||||
runActivity("migLayout") {
|
||||
// IDEA-170295
|
||||
PlatformDefaults.setLogicalPixelBase(PlatformDefaults.BASE_FONT_SIZE)
|
||||
}
|
||||
}, { if (EventQueue.isDispatchThread()) ForkJoinPool.commonPool().execute(it) else it.run() })
|
||||
.exceptionally {
|
||||
StartupAbortedException.processException(it)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}, Executor { if (EDT.isCurrentThreadEdt()) ForkJoinPool.commonPool().execute(it) else it.run() } )
|
||||
.exceptionally {
|
||||
StartupAbortedException.processException(it)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startApp(app: ApplicationImpl,
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.intellij.openapi.application.ApplicationInfo;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.application.ConfigImportHelper;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.application.impl.AWTExceptionHandler;
|
||||
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.ShutDownTracker;
|
||||
@@ -40,6 +41,7 @@ import com.intellij.ui.IconManager;
|
||||
import com.intellij.ui.mac.MacOSApplicationProvider;
|
||||
import com.intellij.ui.scale.JBUIScale;
|
||||
import com.intellij.util.EnvironmentUtil;
|
||||
import com.intellij.util.concurrency.AppScheduledExecutorService;
|
||||
import com.intellij.util.lang.ZipFilePool;
|
||||
import com.intellij.util.ui.StartupUiUtil;
|
||||
import com.intellij.util.ui.accessibility.ScreenReader;
|
||||
@@ -477,9 +479,20 @@ public final class StartupUtil {
|
||||
catch (UnsupportedLookAndFeelException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
activity.end();
|
||||
|
||||
StartUpMeasurer.setCurrentState(LoadingState.LAF_INITIALIZED);
|
||||
|
||||
activity = activity.endAndStart("awt thread busy notification");
|
||||
// instantiate AppDelayQueue which starts "Periodic task thread" which we'll mark busy to prevent this EDT to die
|
||||
// that thread was chosen because we know for sure it's running
|
||||
Thread thread = AppScheduledExecutorService.getPeriodicTasksThread();
|
||||
// needed for EDT not to exit suddenly
|
||||
AWTAutoShutdown.getInstance().notifyThreadBusy(thread);
|
||||
ShutDownTracker.getInstance().registerShutdownTask(() -> {
|
||||
// allow for EDT to exit
|
||||
AWTAutoShutdown.getInstance().notifyThreadFree(thread);
|
||||
});
|
||||
activity.end();
|
||||
}, it -> EventQueue.invokeLater(it)/* don't use here method reference (EventQueue class must be loaded on demand) */);
|
||||
|
||||
if (isUsingSeparateWriteThread()) {
|
||||
@@ -954,6 +967,10 @@ public final class StartupUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// do not crash AWT on exceptions
|
||||
AWTExceptionHandler.register();
|
||||
|
||||
activity.end();
|
||||
}
|
||||
|
||||
|
||||
+43
-10
@@ -111,21 +111,12 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
|
||||
}
|
||||
|
||||
public ApplicationImpl(boolean isInternal, boolean isUnitTestMode, boolean isHeadless, boolean isCommandLine) {
|
||||
this(isInternal, isUnitTestMode, isHeadless, isCommandLine, null);
|
||||
}
|
||||
|
||||
public ApplicationImpl(boolean isInternal, boolean isUnitTestMode, boolean isHeadless, boolean isCommandLine, Consumer<ApplicationImpl> initTask) {
|
||||
super(null);
|
||||
|
||||
registerServiceInstance(TransactionGuard.class, myTransactionGuard, ComponentManagerImpl.getFakeCorePluginDescriptor());
|
||||
registerServiceInstance(ApplicationInfo.class, ApplicationInfoImpl.getShadowInstance(), ComponentManagerImpl.getFakeCorePluginDescriptor());
|
||||
registerServiceInstance(Application.class, this, ComponentManagerImpl.getFakeCorePluginDescriptor());
|
||||
|
||||
if (initTask != null) {
|
||||
// myLock is a final field, we cannot do init in EDT and set it later
|
||||
initTask.accept(this);
|
||||
}
|
||||
|
||||
if (isUnitTestMode || isInternal) {
|
||||
BundleBase.assertOnMissedKeys(true);
|
||||
}
|
||||
@@ -147,6 +138,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
|
||||
|
||||
if (!isUnitTestMode && !isHeadless) {
|
||||
Disposable uiRootDisposable = Disposer.newDisposable();
|
||||
//noinspection deprecation
|
||||
Disposer.register(this, uiRootDisposable, "ui");
|
||||
}
|
||||
|
||||
@@ -155,7 +147,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
|
||||
EdtInvocationManager.invokeAndWaitIfNeeded(() -> {
|
||||
// instantiate AppDelayQueue which starts "Periodic task thread" which we'll mark busy to prevent this EDT to die
|
||||
// that thread was chosen because we know for sure it's running
|
||||
Thread thread = ((AppScheduledExecutorService)AppExecutorUtil.getAppScheduledExecutorService()).getPeriodicTasksThread();
|
||||
Thread thread = AppScheduledExecutorService.getPeriodicTasksThread();
|
||||
AWTAutoShutdown.getInstance().notifyThreadBusy(thread); // needed for EDT not to exit suddenly
|
||||
Disposer.register(this, () -> {
|
||||
AWTAutoShutdown.getInstance().notifyThreadFree(thread); // allow for EDT to exit - needed for Upsource
|
||||
@@ -172,6 +164,47 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
|
||||
NoSwingUnderWriteAction.watchForEvents(this);
|
||||
}
|
||||
|
||||
// this constructor must be called only by ApplicationLoader
|
||||
public ApplicationImpl(boolean isInternal,
|
||||
boolean isUnitTestMode,
|
||||
boolean isHeadless,
|
||||
boolean isCommandLine,
|
||||
@NotNull Thread edtThread) {
|
||||
super(null);
|
||||
|
||||
registerServiceInstance(TransactionGuard.class, myTransactionGuard, ComponentManagerImpl.getFakeCorePluginDescriptor());
|
||||
registerServiceInstance(ApplicationInfo.class, ApplicationInfoImpl.getShadowInstance(), ComponentManagerImpl.getFakeCorePluginDescriptor());
|
||||
registerServiceInstance(Application.class, this, ComponentManagerImpl.getFakeCorePluginDescriptor());
|
||||
|
||||
Disposer.setDebugMode(isInternal || isUnitTestMode || Disposer.isDebugDisposerOn());
|
||||
|
||||
myIsInternal = isInternal;
|
||||
myTestModeFlag = isUnitTestMode;
|
||||
myHeadlessMode = isHeadless;
|
||||
myCommandLineMode = isCommandLine;
|
||||
|
||||
mySaveAllowed = !(isUnitTestMode || isHeadless);
|
||||
|
||||
if (!isUnitTestMode && !isHeadless) {
|
||||
Disposable uiRootDisposable = Disposer.newDisposable();
|
||||
//noinspection deprecation
|
||||
Disposer.register(this, uiRootDisposable, "ui");
|
||||
}
|
||||
|
||||
Activity activity = StartUpMeasurer.startActivity("AppDelayQueue instantiation", ActivityCategory.DEFAULT);
|
||||
myLock = new ReadMostlyRWLock(edtThread);
|
||||
// Acquire IW lock on EDT indefinitely in legacy mode
|
||||
if (!USE_SEPARATE_WRITE_THREAD || isUnitTestMode) {
|
||||
EventQueue.invokeLater(() -> acquireWriteIntentLock(getClass()));
|
||||
}
|
||||
activity.end();
|
||||
|
||||
NoSwingUnderWriteAction.watchForEvents(this);
|
||||
|
||||
// reset back to null only when all components already disposed
|
||||
ApplicationManager.setApplication(this, myLastDisposable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a {@code runnable} in an "impatient" mode.
|
||||
* In this mode any attempt to call {@link #runReadAction(Runnable)}
|
||||
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.application.impl;
|
||||
|
||||
import com.intellij.ide.IdeEventQueue;
|
||||
@@ -15,20 +15,20 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
final class NoSwingUnderWriteAction {
|
||||
private static final Logger LOG = Logger.getInstance(NoSwingUnderWriteAction.class);
|
||||
|
||||
static void watchForEvents(Application application) {
|
||||
static void watchForEvents(@NotNull Application app) {
|
||||
AtomicBoolean reported = new AtomicBoolean();
|
||||
IdeEventQueue.getInstance().addPostprocessor(e -> {
|
||||
if (application.isWriteAccessAllowed() && reported.compareAndSet(false, true)) {
|
||||
if (app.isWriteAccessAllowed() && reported.compareAndSet(false, true)) {
|
||||
LOG.error("AWT events are not allowed inside write action: " + e);
|
||||
}
|
||||
return true;
|
||||
}, application);
|
||||
}, app);
|
||||
|
||||
application.addApplicationListener(new ApplicationListener() {
|
||||
app.addApplicationListener(new ApplicationListener() {
|
||||
@Override
|
||||
public void afterWriteActionFinished(@NotNull Object action) {
|
||||
reported.set(false);
|
||||
}
|
||||
}, application);
|
||||
}, app);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.util.concurrency;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -27,16 +27,15 @@ public final class AppScheduledExecutorService extends SchedulingWrapper {
|
||||
private final LowMemoryWatcherManager myLowMemoryWatcherManager;
|
||||
private final MyThreadFactory myCountingThreadFactory;
|
||||
|
||||
private static class Holder {
|
||||
private static final class Holder {
|
||||
private static final AppScheduledExecutorService INSTANCE = new AppScheduledExecutorService("Global instance", 1, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static ScheduledExecutorService getInstance() {
|
||||
static @NotNull ScheduledExecutorService getInstance() {
|
||||
return Holder.INSTANCE;
|
||||
}
|
||||
|
||||
private static class MyThreadFactory extends CountingThreadFactory {
|
||||
private static final class MyThreadFactory extends CountingThreadFactory {
|
||||
private BiConsumer<? super Thread, ? super Runnable> newThreadListener;
|
||||
private final ThreadFactory myThreadFactory = Executors.privilegedThreadFactory();
|
||||
|
||||
@@ -195,9 +194,8 @@ public final class AppScheduledExecutorService extends SchedulingWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Thread getPeriodicTasksThread() {
|
||||
return delayQueue.getThread();
|
||||
public static @NotNull Thread getPeriodicTasksThread() {
|
||||
return Holder.INSTANCE.delayQueue.getThread();
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.util.ui;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@@ -33,6 +34,11 @@ public final class EDT {
|
||||
return thread == myEventDispatchThread;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static @Nullable Thread getEventDispatchThread() {
|
||||
return myEventDispatchThread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current thread is EDT.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user