PY-76036 PY-75988 PY-75990 PY-76065: Fix various threading issues after the new platform threading policy

All "implicit" locks are removed from the platform, so we need to call read/write action explicitly (which is a right thing to do in any case).

GitOrigin-RevId: 290788bc78e39ca42f7d0f14ae4ccd16dd315ce7
This commit is contained in:
Ilya.Kazakevich
2024-09-20 23:02:57 +02:00
committed by intellij-monorepo-bot
parent 888e3be3de
commit 0438f8093b
7 changed files with 53 additions and 19 deletions

View File

@@ -46,8 +46,10 @@ import java.util.Map;
* Needs not to be instantiated and only holds static methods. * Needs not to be instantiated and only holds static methods.
* *
* @see PythonSdkUtil for Pyhton SDK utilities with no run-time dependencies * @see PythonSdkUtil for Pyhton SDK utilities with no run-time dependencies
*
* @deprecated please use Kotlin coroutines to run processes in background
*/ */
//TODO: rename to PySdkExecuteUtil or PySdkRuntimeUtil @Deprecated
public final class PySdkUtil { public final class PySdkUtil {
private static final Logger LOG = Logger.getInstance(PySdkUtil.class); private static final Logger LOG = Logger.getInstance(PySdkUtil.class);

View File

@@ -334,6 +334,7 @@ public abstract class PythonSdkFlavor<D extends PyFlavorData> {
} }
@Nullable @Nullable
@RequiresBackgroundThread(generateAssertion = false) //because of process output
public String getVersionString(@Nullable String sdkHome) { public String getVersionString(@Nullable String sdkHome) {
if (sdkHome == null) { if (sdkHome == null) {
return null; return null;
@@ -394,6 +395,7 @@ public abstract class PythonSdkFlavor<D extends PyFlavorData> {
} }
@NotNull @NotNull
@RequiresBackgroundThread(generateAssertion = false) //because of process output
public LanguageLevel getLanguageLevel(@NotNull String sdkHome) { public LanguageLevel getLanguageLevel(@NotNull String sdkHome) {
return getLanguageLevelFromVersionString(getVersionString(sdkHome)); return getLanguageLevelFromVersionString(getVersionString(sdkHome));
} }

View File

@@ -5,9 +5,9 @@ import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.EDT import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.asContextElement import com.intellij.openapi.application.asContextElement
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service import com.intellij.openapi.components.service
import com.intellij.util.concurrency.ThreadingAssertions
import com.intellij.util.concurrency.annotations.RequiresBlockingContext import com.intellij.util.concurrency.annotations.RequiresBlockingContext
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -25,6 +25,11 @@ private class MyService(val coroutineScope: CoroutineScope)
@RequiresBlockingContext @RequiresBlockingContext
internal fun <T : Any> Flow<T>.oneShotConsumer(consumer: Consumer<T>) { internal fun <T : Any> Flow<T>.oneShotConsumer(consumer: Consumer<T>) {
ApplicationManager.getApplication().service<MyService>().coroutineScope.launch(Dispatchers.EDT + ModalityState.defaultModalityState().asContextElement()) { ApplicationManager.getApplication().service<MyService>().coroutineScope.launch(Dispatchers.EDT + ModalityState.defaultModalityState().asContextElement()) {
consumer.accept(this@oneShotConsumer.first()) // Platform doesn't guarantee write intent lock on EDT
//todo fix all clients and remove global lock from here
val t = this@oneShotConsumer.first()
writeIntentReadAction {
consumer.accept(t)
}
} }
} }

View File

@@ -17,11 +17,7 @@ package com.jetbrains.python.sdk
import com.intellij.execution.ExecutionException import com.intellij.execution.ExecutionException
import com.intellij.execution.target.* import com.intellij.execution.target.*
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.*
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.application.WriteAction
import com.intellij.openapi.application.invokeAndWaitIfNeeded
import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.diagnostic.getOrLogException import com.intellij.openapi.diagnostic.getOrLogException
import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
@@ -43,7 +39,10 @@ import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.ide.progress.ModalTaskOwner
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.intellij.util.PathUtil import com.intellij.util.PathUtil
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.intellij.webcore.packaging.PackagesNotificationPanel import com.intellij.webcore.packaging.PackagesNotificationPanel
import com.jetbrains.extensions.failure import com.jetbrains.extensions.failure
import com.jetbrains.python.PyBundle import com.jetbrains.python.PyBundle
@@ -59,12 +58,16 @@ import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor
import com.jetbrains.python.sdk.flavors.conda.CondaEnvSdkFlavor import com.jetbrains.python.sdk.flavors.conda.CondaEnvSdkFlavor
import com.jetbrains.python.target.PyTargetAwareAdditionalData import com.jetbrains.python.target.PyTargetAwareAdditionalData
import com.jetbrains.python.ui.PyUiUtil import com.jetbrains.python.ui.PyUiUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.ApiStatus
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
import javax.swing.SwingUtilities
import kotlin.Result
import kotlin.io.path.div import kotlin.io.path.div
import kotlin.io.path.pathString import kotlin.io.path.pathString
@@ -187,13 +190,22 @@ fun createSdkByGenerateTask(
throw e throw e
} }
val suggestedName = suggestedSdkName ?: suggestAssociatedSdkName(homeFile.path, associatedProjectPath) val sdkName = suggestedSdkName ?: if (SwingUtilities.isEventDispatchThread()) {
runWithModalProgressBlocking(ModalTaskOwner.guess(), "...") {
withContext(Dispatchers.IO) {
suggestAssociatedSdkName(homeFile.path, associatedProjectPath)
}
}
}
else {
suggestAssociatedSdkName(homeFile.path, associatedProjectPath)
}
return SdkConfigurationUtil.setupSdk( return SdkConfigurationUtil.setupSdk(
existingSdks.toTypedArray(), existingSdks.toTypedArray(),
homeFile, homeFile,
PythonSdkType.getInstance(), PythonSdkType.getInstance(),
null, null,
suggestedName) sdkName)
} }
fun showSdkExecutionException(sdk: Sdk?, e: ExecutionException, @NlsContexts.DialogTitle title: String) { fun showSdkExecutionException(sdk: Sdk?, e: ExecutionException, @NlsContexts.DialogTitle title: String) {
@@ -378,6 +390,7 @@ fun getInnerVirtualEnvRoot(sdk: Sdk): VirtualFile? {
} }
} }
@RequiresBackgroundThread
internal fun suggestAssociatedSdkName(sdkHome: String, associatedPath: String?): String? { internal fun suggestAssociatedSdkName(sdkHome: String, associatedPath: String?): String? {
// please don't forget to update com.jetbrains.python.inspections.PyInterpreterInspection.Visitor#getSuitableSdkFix // please don't forget to update com.jetbrains.python.inspections.PyInterpreterInspection.Visitor#getSuitableSdkFix
// after changing this method // after changing this method

View File

@@ -33,6 +33,7 @@ import com.intellij.remote.ext.LanguageCaseCollector;
import com.intellij.util.Consumer; import com.intellij.util.Consumer;
import com.intellij.util.ExceptionUtil; import com.intellij.util.ExceptionUtil;
import com.intellij.util.PlatformUtils; import com.intellij.util.PlatformUtils;
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames; import com.jetbrains.python.PyNames;
@@ -244,7 +245,7 @@ public final class PythonSdkType extends SdkType {
return name; return name;
} }
} }
@RequiresBackgroundThread(generateAssertion = false) //because of process output
public static @Nullable String suggestBaseSdkName(@NotNull String sdkHome) { public static @Nullable String suggestBaseSdkName(@NotNull String sdkHome) {
final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdkHome); final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdkHome);
if (flavor == null) return null; if (flavor == null) return null;

View File

@@ -3,12 +3,13 @@ package com.jetbrains.python.sdk.add.v2
import com.intellij.execution.ExecutionException import com.intellij.execution.ExecutionException
import com.intellij.openapi.application.EDT import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.writeAction
import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.module.ModuleUtil
import com.intellij.openapi.project.ProjectManager import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.VfsUtil
import com.intellij.platform.ide.progress.ModalTaskOwner import com.intellij.platform.ide.progress.ModalTaskOwner
import com.intellij.platform.ide.progress.TaskCancellation import com.intellij.platform.ide.progress.TaskCancellation
import com.intellij.platform.ide.progress.withModalProgress import com.intellij.platform.ide.progress.withModalProgress
@@ -53,13 +54,16 @@ suspend fun PythonMutableTargetAddInterpreterModel.setupVirtualenv(venvPath: Pat
catch (e: InvalidPathException) { catch (e: InvalidPathException) {
return Result.failure(e) return Result.failure(e)
} }
val venvPython = VirtualEnvReader.Instance.findPythonInPythonRoot(dir)?.toString() val venvPython = VirtualEnvReader.Instance.findPythonInPythonRoot(dir)
if (venvPython == null) { if (venvPython == null) {
return failure(message("commandLine.directoryCantBeAccessed", venvPathOnTarget)) return failure(message("commandLine.directoryCantBeAccessed", venvPathOnTarget))
} }
val homeFile = try { val homeFile = try {
StandardFileSystems.local().refreshAndFindFileByPath(venvPython) // refresh needs write action
writeAction {
VfsUtil.findFile(venvPython, true)
}
} }
catch (e: ExecutionException) { catch (e: ExecutionException) {
return Result.failure(e) return Result.failure(e)
@@ -68,10 +72,13 @@ suspend fun PythonMutableTargetAddInterpreterModel.setupVirtualenv(venvPath: Pat
return failure(message("commandLine.directoryCantBeAccessed", venvPathOnTarget)) return failure(message("commandLine.directoryCantBeAccessed", venvPathOnTarget))
} }
val suggestedName = /*suggestedSdkName ?:*/ suggestAssociatedSdkName(homeFile.path, projectPath.toString()) // "suggest name" calls external process and can't be called from EDT
val newSdk = SdkConfigurationUtil.setupSdk(existingSdks.toTypedArray(), homeFile, val newSdk = withContext(Dispatchers.IO) {
PythonSdkType.getInstance(), val suggestedName = /*suggestedSdkName ?:*/ suggestAssociatedSdkName(homeFile.path, projectPath.toString())
false, null, suggestedName)!! SdkConfigurationUtil.setupSdk(existingSdks.toTypedArray(), homeFile,
PythonSdkType.getInstance(),
false, null, suggestedName)!!
}
addSdk(newSdk) addSdk(newSdk)

View File

@@ -4,6 +4,7 @@ package com.jetbrains.python.util
import com.intellij.openapi.application.EDT import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.asContextElement import com.intellij.openapi.application.asContextElement
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.ui.Messages import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.NlsSafe import com.intellij.openapi.util.NlsSafe
@@ -56,7 +57,10 @@ object ShowingMessageErrorSync : ErrorSink {
override suspend fun emit(value: @NlsSafe String) { override suspend fun emit(value: @NlsSafe String) {
withContext(Dispatchers.EDT + ModalityState.any().asContextElement()) { withContext(Dispatchers.EDT + ModalityState.any().asContextElement()) {
thisLogger().warn(value) thisLogger().warn(value)
Messages.showErrorDialog(value, PyBundle.message("python.error")) // Platform doesn't allow dialogs without lock for now, fix later
writeIntentReadAction {
Messages.showErrorDialog(value, PyBundle.message("python.error"))
}
} }
} }
} }