On Mon, 15 Jul 2024 22:08:12 GMT, Andy Goryachev <[email protected]> wrote:
>> This PR solves two related bugs that are caused by events being delivered
>> while the FX runtime is in the process of shutting down. These bugs are
>> related enough that I think they need to be addressed at the same time.
>> While debugging and developing the test, I saw one or the other or both in
>> various test runs. The system test included with this program verifies that
>> there is no crash and no exception, so will catch either failure mode.
>>
>> This can happen when there is a full-screen window showing during shutdown
>> on macOS, since full screen enter / exit uses a nested event loop that
>> affects the order of operation. This could theoretically happen in other
>> cases, thus the fix does not involve checking whether we are in full-screen
>> or whether there is a nested event loop.
>>
>> The fix does the following:
>>
>> 1. `GlassWindow+Overrides.m`: Check that the JVM is still running before
>> calling the Java notification method in `windowDidResignKey` and
>> `windowShouldClose`. This matches what is already done for other similar
>> methods in this class. This is the fix for JDK-8335630.
>> 2. `Window.java` and `View.java`: Check whether the Application instance is
>> null in the event notification callbacks, and skip handling the event if it
>> is. This is the fix for JDK-8299738.
>>
>> Note that the fix for 2 is in platform-independent code. This should be
>> fine, since we would want to skip the event handling callback on any other
>> platform if it were done during shutdown, in order to avoid the ISE.
>>
>> I have included a system test that passes on all platforms. On macOS, the
>> test will fail without the fix and pass with the fix.
>>
>> Details of the fix are below:
>>
>> `Platform::exit` is called by the application to shutdown the JavaFX
>> toolkit. The implementation of `Platform::exit` calls `Toolkit::exit` on the
>> JavaFX Application thread, which in turn calls glass
>> `Application::terminate` to shut it down. `Application::terminate` will
>> close all the native windows, and call `finishTerminating` to terminate the
>> native event loop and detach the thread from the JVM. This is asynchronous,
>> at least on macOS, and will schedule the termination by posting a native
>> event to the event loop.
>>
>> on macOS 13, and sometimes on macOS 14, a Window or View event handler can
>> be called between `Toolkit::exit`/`Application::terminate` (which sets the
>> Toolkit's cached thread to null and the glass Application instance to null)
>> and the JVM shutdown. This will make a JNI upcall to the appropriate
>> Window...
>
> modules/javafx.graphics/src/main/java/com/sun/glass/ui/View.java line 533:
>
>> 531: private boolean shouldHandleEvent() {
>> 532: // Don't send any more events if the application has shutdown
>> 533: if (Application.GetApplication() == null) {
>
> Should we declare `Application.application` field as volatile?
>
> I see interleaved multi-threaded access pattern:
>
>
> thread=JavaFX-Launcher
> CREATE thread=JavaFX-Launcher
> thread=JavaFX-Launcher
> thread=Thread-2
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX-Launcher
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX-Launcher
> thread=JavaFX Application Thread
> thread=PulseTimer-CVDisplayLink thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=QuantumRenderer-0
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=PulseTimer-CVDisplayLink thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX-Launcher
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=JavaFX Application Thread
> thread=Java...
Other threads may still not see the current value of the
`Application.application` field. Is it safe for other threads to use the
`Application` instance after the field has been set to `null`?
-------------
PR Review Comment: https://git.openjdk.org/jfx/pull/1506#discussion_r1678465264