diff --git a/ijs.tree b/ijs.tree index 80252f0e9..e63612bb9 100644 --- a/ijs.tree +++ b/ijs.tree @@ -75,7 +75,7 @@ - + diff --git a/topics/appendix/glossary.md b/topics/appendix/glossary.md index 3bf072124..80098fdf0 100644 --- a/topics/appendix/glossary.md +++ b/topics/appendix/glossary.md @@ -19,7 +19,7 @@ Annotator ## B Blocking Context -: Executing in the [blocking context](execution_contexts.md#blocking-context) means executing tasks on a thread without access to a coroutine context. +: Executing in the [blocking context](execution_contexts.topic#blocking-context) means executing tasks on a thread without access to a coroutine context. → _Suspending Context_ → _Coroutine_ @@ -130,7 +130,7 @@ Stubs : A subset of a → _Program Structure Interface_ tree in a binary serialized compact format, see [](stub_indexes.md). Suspending Context -: Executing in the [suspending context](execution_contexts.md#suspending-context-coroutines) means executing tasks in Kotlin coroutines. +: Executing in the [suspending context](execution_contexts.topic#suspending-context-coroutines) means executing tasks in Kotlin coroutines. → _Blocking Context_ → _Coroutine_ diff --git a/topics/basics/architectural_overview/threading/background_processes.md b/topics/basics/architectural_overview/threading/background_processes.md index 3db864513..ae6b19b89 100644 --- a/topics/basics/architectural_overview/threading/background_processes.md +++ b/topics/basics/architectural_overview/threading/background_processes.md @@ -14,7 +14,7 @@ The IntelliJ Platform executes background processes widely and provides two main > Plugins targeting 2024.1+ should use [Kotlin coroutines](kotlin_coroutines.md), which is a more performant solution and provides the cancellation mechanism out of the box. > -> See [](execution_contexts.md) for coroutine-based APIs to use in different contexts. +> See [](execution_contexts.topic) for coroutine-based APIs to use in different contexts. > {style="warning" title="Use Kotlin Coroutines"} diff --git a/topics/basics/architectural_overview/threading/coroutines/coroutine_edt_and_locks.md b/topics/basics/architectural_overview/threading/coroutines/coroutine_edt_and_locks.md index a7f9e5253..fabeec797 100644 --- a/topics/basics/architectural_overview/threading/coroutines/coroutine_edt_and_locks.md +++ b/topics/basics/architectural_overview/threading/coroutines/coroutine_edt_and_locks.md @@ -161,7 +161,7 @@ Sometimes it is not desired, as the coroutine in question was scheduled on [`Dis Anyway, it is suspicious when a read action cannot be executed on a background thread and a part of coroutine code cannot be suspended and rescheduled on EDT. This may signal a code issue. -Note that this API cannot be used in the [blocking context](execution_contexts.md#blocking-context). +Note that this API cannot be used in the [blocking context](execution_contexts.topic#blocking-context). ### Suspending `readAndWriteAction()` @@ -176,7 +176,7 @@ Consider rewriting code to use it, if possible. Use them if a read action is required, but it is unacceptable to reschedule code execution on a different dispatcher. -These APIs are marked to use only in the [blocking context](execution_contexts.md#blocking-context), so their usage in the [suspending context](execution_contexts.md#suspending-context-coroutines) will trigger a warning. +These APIs are marked to use only in the [blocking context](execution_contexts.topic#blocking-context), so their usage in the [suspending context](execution_contexts.topic#suspending-context-coroutines) will trigger a warning. It is intentional, as coroutines should be prepared to be rescheduled and should use `readAction()`. ### Suspending `writeIntentReadAction()` and Blocking `WriteIntentReadAction.run()`/`compute()` diff --git a/topics/basics/architectural_overview/threading/execution_contexts.md b/topics/basics/architectural_overview/threading/execution_contexts.md deleted file mode 100644 index 1a747b65e..000000000 --- a/topics/basics/architectural_overview/threading/execution_contexts.md +++ /dev/null @@ -1,188 +0,0 @@ - - -# Execution Contexts - -Tracking execution progress, checking for cancellations, and switching between different execution contexts. - -The IntelliJ Platform provides APIs that allow tracking the progress of background processes and canceling their execution when they are canceled by a user, or they become obsolete due to some changes in the data model. - -Background processes can be executed in three contexts: -- [](#suspending-context-coroutines) — available since 2024.1 -- [](#blocking-context) -- [](#progress-indicator) — obsolete since 2024.1 - -Currently, the Progress Indicator context is the most widely used approach in the IntelliJ Platform. -As the platform's execution model moves towards [coroutines](launching_coroutines.md), this approach can be considered obsolete. -Starting with 2024.1, it is recommended to execute new code in the [suspending context](#suspending-context-coroutines). - -The following sections explain the contexts and provide information about process cancellation, progress tracking, and switching between different contexts. - -## Suspending Context (Coroutines) - - -Code [executed in Kotlin coroutines](launching_coroutines.md) is executed in a suspending context. -Since 2024.1, this context is recommended for executing background tasks to maximize CPU utilization. - -> Note that executing code in a suspending context is possible only with [Kotlin](using_kotlin.md). -> -{style="warning"} - -In a suspending context, methods such as `ProgressManager.checkCanceled()` or `ModalityState.defaultModalityState()` won't have any effect. -Therefore, if their behavior is required, [switch to a blocking context](#switching-between-contexts). - -> Inspection Plugin DevKit | Code | Forbidden in suspend context method usage reports calling blocking code from suspending context. - -## Blocking Context - -Executing tasks in a blocking context means executing them on a thread without access to the [coroutine context](#suspending-context-coroutines) (basically, in non-suspending functions) and not under [a progress indicator](#progress-indicator). -Such tasks can still be canceled, but they can't report progress. - -Plugins should not execute new code in the blocking context. -Always prefer executing tasks in the [suspending context](#suspending-context-coroutines) or under the [progress indicator](#progress-indicator) if a plugin cannot use Kotlin. - -> Functions which schedule execution via [`Application.executeOnPooledThread()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/application/Application.java) -> and similar methods, and which rely on [`ProgressManager.checkCanceled()`](%gh-ic%/platform/core-api/src/com/intellij/openapi/progress/ProgressManager.java) -> should be annotated with [`@RequiresBlockingContext`](%gh-ic%/platform/core-api/src/com/intellij/util/concurrency/annotations/RequiresBlockingContext.kt) -> to inform clients about the required switch to a blocking context. -> -> Inspection Plugin DevKit | Code | Calling method should be annotated with @RequiresBlockingContext reports missing annotations. - -## Progress Indicator - - -Code executed via the Progress API -([`ProgressManager`](%gh-ic%/platform/core-api/src/com/intellij/openapi/progress/ProgressManager.java), -[`ProgressIndicator`](%gh-ic%/platform/core-api/src/com/intellij/openapi/progress/ProgressIndicator.java), etc.) -is executed in a progress indicator context. -See the [](background_processes.md#progress-api) section for details. - -> Executing code under the progress indicator is obsolete since 2024.1. -> It is advised to use Kotlin coroutines in new code. -> -> Please note that obsolete status does not mean deprecation. -> Executing code using the Progress API is still allowed, but coroutines are recommended as a more performant solution. -> -{style="tip" title="Obsolete approach since 2024.1"} - -## Execution Contexts APIs - -### Cancellation Check - -The following table presents APIs to use for checking whether a task was canceled in different execution contexts. - - - - - - - - - - - - - - -
Suspending - ensureActive() from Kotlin coroutine's API - - Note that ProgressManager.checkCanceled() does not work in a suspending context. - -
Blocking - ProgressManager.checkCanceled() -

See Background Processes: Cancellation for details.

-
Progress Indicator - ProgressIndicator.checkCanceled(), ProgressManager.checkCanceled() -

See Background Processes: Cancellation for details.

-
- -### Progress Reporting - -The following table presents the possibilities and APIs to use for reporting progress in different execution contexts. - - - - - - - - - - - - - - -
Suspending - -

- Any report*Progress() function must be used inside withBackgroundProgress(), withModalProgress(), or runWithModalProgressBlocking() from tasks.kt. - Otherwise, if there is no reporter in the context, using report*Progress() will have no effect. - Example: -

- - withBackgroundProgress(...) { // or other - // ... - reportProgress { reporter -> // or another report*Progress - // do tasks and report progress - } - // ... - } - -
Blocking - unavailable -
Progress Indicator - ProgressIndicator's or ProgressManager's methods -

See Background Processes: Tracking Progress for details.

-
- -### Switching Between Contexts - -The following table presents the possibilities and APIs to use for switching between different execution contexts. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
To SuspendingTo BlockingTo Progress Indicator
From Suspending-blockingContext() 1unavailable 3
From BlockingrunBlockingCancellable() 2-unavailable 4
From Progress IndicatorrunBlockingCancellable() 2unavailable-
- 1 blockingContext() enables ProgressManager.checkCanceled(), forwards modality state, etc. It has an opposite behavior to runBlockingCancellable().
- 2 runBlockingCancellable() has an opposite behavior to blockingContext()
- 3 coroutineToIndicator() is an internal API to aid platform migration
- 4 blockingContextToIndicator() is an internal API to aid platform migration -
- -It is only possible to: -- switch from the blocking context or progress indicator to the suspending context -- switch from the suspending context to the blocking context - -The lack of an API for switching from suspending and blocking contexts to progress indicator is intentional. -Cancellable and trackable tasks should be run in coroutines as the progress indicator is obsolete since 2024.1. - - diff --git a/topics/basics/architectural_overview/threading/execution_contexts.topic b/topics/basics/architectural_overview/threading/execution_contexts.topic new file mode 100644 index 000000000..9482600e6 --- /dev/null +++ b/topics/basics/architectural_overview/threading/execution_contexts.topic @@ -0,0 +1,408 @@ + + + + + + Execution Contexts + Tracking execution progress, checking for cancellations, and switching between different execution contexts. + +

The IntelliJ Platform provides APIs that allow tracking the progress of background processes and canceling their + execution when they are canceled by a user, or they become obsolete due to some changes in the data model.

+ + + + +

Available execution contexts differ depending on the IntelliJ Platform version. + For the details, select the required tab below.

+ + + +

Background processes can be executed in two contexts:

+ +
  • — available since 2024.2
  • +
  • — obsolete since 2024.1
  • +
    + +

    Currently, the Progress Indicator context is the most widely used approach in the IntelliJ Platform. + As the platform's execution model moves towards coroutines, this approach + can be considered obsolete.

    + +

    Starting with 2024.2, it is recommended to execute new code in the + Job context.

    + +

    The following sections explain the contexts and provide information about process cancellation, progress + tracking, and switching between contexts.

    + + + + + + + Suspending and Blocking contexts available in 2024.1 have been unified into the Job context. + See the + Reconsider blockingContext issue for more details. + + +

    Code executed in Kotlin coroutines is executed in the Job context. + Since 2024.2, coroutines are recommended for executing background tasks to maximize CPU utilization. + Note that executing code in coroutines is possible only with Kotlin. +

    + +

    + While code executed in the Job context should use suspending functions, + sometimes it is required to call non-suspending/blocking APIs that use methods such as + ProgressManager.checkCanceled() or ModalityState.defaultModalityState(). + Since 2024.2, these methods work as expected without the need to switch to the blocking context. +

    + + The "Job" word in the name refers to the + + Job class, which is used for task cancellation in suspending and non-suspending + functions. + + + +

    Inspection + Plugin DevKit | Code | Forbidden in suspend context method usage + reports calling blocking code from suspending context. + While this is not an error, it is recommended to use suspending counterparts if they exist. +

    +
    +
    +
    + + +

    Background processes can be executed in three contexts:

    + +
  • — available since 2024.1
  • +
  • +
  • — obsolete since 2024.1
  • +
    + + +

    Starting with 2024.1, it is recommended to execute new code in the + suspending context.

    + + + + + +

    Code executed in Kotlin coroutines is executed in a suspending context. + Since 2024.1, this context is recommended for executing background tasks to maximize CPU utilization. + Note that executing code in coroutines is possible only with Kotlin. +

    +

    In a suspending context, methods such as ProgressManager.checkCanceled() or ModalityState.defaultModalityState() + won't have any effect. + Therefore, if their behavior is required, switch to a blocking + context.

    + +

    Inspection + Plugin DevKit | Code | Forbidden in suspend context method usage + reports calling blocking code from suspending context. +

    +
    +
    + + +

    Executing tasks in a blocking context means executing them on a thread without access to the coroutine context (basically, in non-suspending functions) + and not under a progress indicator. + Such tasks can still be canceled, but they can't report progress.

    +

    Plugins should not execute new code in the blocking context. + Always prefer executing tasks in the suspending context or + under the progress indicator if a plugin cannot use Kotlin.

    + + +

    Functions which schedule execution via Application.executeOnPooledThread() + and similar methods, and which rely on ProgressManager.checkCanceled() + should be annotated with @RequiresBlockingContext + to inform clients about the required switch to a blocking context.

    +

    Inspection + Plugin DevKit | Code | Calling method should be annotated with @RequiresBlockingContext + + reports missing annotations. +

    +
    +
    +
    +
    + + + + +

    Code executed via the Progress API + (ProgressManager, + ProgressIndicator, + etc.) + is executed in a progress indicator context. + See the section for details.

    + +

    Executing code under the progress indicator is obsolete since 2024.1. + It is advised to use Kotlin coroutines in new code.

    +

    Please note that obsolete status does not mean deprecation. + Executing code using the Progress API is still allowed, but coroutines are recommended as a more + performant solution.

    +
    +
    + + +

    The following table presents APIs to use for checking whether a task was canceled in different execution + contexts.

    + + + See
    Background Processes: Cancellation for + general cancellation mechanism explanation. + + + + + + + + + + + + + +
    Job Context + +
  • + checkCanceled()
  • +
  • + ProgressManager.checkCanceled()
  • +
    +
    Progress Indicator + +
  • + ProgressIndicator.checkCanceled()
  • +
  • + ProgressManager.checkCanceled()
  • +
    +
    +
    + + + + + + + + + + + +
    Suspending Context + +
  • ensureActive() + from Kotlin coroutine's API
  • +
    + + + Note that + ProgressManager.checkCanceled() + does not work in the suspending context. + To enable it, + switch to blockingContext(), + if it is not possible to change the code. + +
    Blocking Context + +
  • ProgressManager.checkCanceled()
  • +
    +
    +
    +
    + + + +

    The following table presents the possibilities and APIs to use for reporting progress in different + execution contexts.

    + + + + + + + + + + + + +
    Job Context + +
  • ProgressStep + - a step-based progress reporting (see its KDoc for details) +
  • +
  • RawProgressReporter + - a raw text, details, and fraction reporting (invoked via reportRawProgress()) +
  • +
    +

    + Any report*Progress() + function must be used inside withBackgroundProgress(), withModalProgress(), + or runWithModalProgressBlocking() from + tasks.kt + . + Otherwise, if there is no reporter in the context, using report*Progress() will + have no effect. + Example: +

    + + withBackgroundProgress(...) { // or other + // ... + reportProgress { reporter -> // or another report*Progress + // do tasks and report progress + } + // ... + } + +
    Progress Indicator + ProgressIndicator's + or ProgressManager's + methods +

    See Background Processes: Tracking + Progress for details.

    +
    +
    + + + + + + + + + + + +
    Suspending Context
    Blocking Context + unavailable +
    +
    +
    +
    + + +

    The following table presents the possibilities and APIs to use for switching between different execution + contexts.

    + + + + + + + + + + + + + + + + + + + + + +
    + To Job ContextTo Progress Indicator
    From Job Context- + coroutineToIndicator() 1
    From Progress Indicator + runBlockingCancellable()-
    + 1 + coroutineToIndicator() + is an experimental API, which was originally internal and created to aid + platform migration. + It is not recommended to switch from the Job context to the progress indicator. + Use it only if there is no other option. +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + To Suspending ContextTo Blocking ContextTo Progress Indicator
    From Suspending Context-blockingContext() 1unavailable 3
    From Blocking ContextrunBlockingCancellable() 2-unavailable 4
    From Progress IndicatorrunBlockingCancellable() 2unavailable-
    + 1 + + blockingContext() + enables ProgressManager.checkCanceled(), forwards modality state, etc. + It has an opposite behavior to runBlockingCancellable(). + Since 2024.2, it is a no-operation function, as the blocking context was unified + with the suspending context into the Job context. +
    + + 2 + + runBlockingCancellable() + has an opposite behavior to blockingContext() +
    + + 3 + + coroutineToIndicator() + is an internal API to aid platform migration +
    + + 4 + + blockingContextToIndicator() + is an internal API to aid platform migration +
    + +

    It is only possible to:

    + +
  • switch from the blocking context or progress indicator to the suspending context
  • +
  • switch from the suspending context to the blocking context
  • +
    +

    The lack of an API for switching from suspending and blocking contexts to progress indicator is + intentional. + Cancellable and trackable tasks should be run in coroutines as the progress indicator is obsolete since + 2024.1.

    +
    +
    + + +
    + + +
    + + + + diff --git a/topics/ui/controls/progress_indicators.md b/topics/ui/controls/progress_indicators.md index 8c7f8224a..6615f4ded 100644 --- a/topics/ui/controls/progress_indicators.md +++ b/topics/ui/controls/progress_indicators.md @@ -6,7 +6,7 @@ -**Implementation**: Progress tracking in [Progress API](background_processes.md#tracking-progress) and [Kotlin Coroutines](execution_contexts.md#progress-reporting) +**Implementation**: Progress tracking in [Progress API](background_processes.md#tracking-progress) and [Kotlin Coroutines](execution_contexts.topic#progress-reporting)