On Fri, 16 May 2025 14:38:20 GMT, Michael Strauß <mstra...@openjdk.org> wrote:
> When an exception is thrown from `AnimationTimer::handle`, the JavaFX > application freezes. The reason is that the user exception will bubble up > into framework code, preventing the normal operation of JavaFX. > > The following program demonstrates the defect: > > > public class FailingAnimationTimer extends Application { > @Override > public void start(Stage stage) throws Exception { > var button = new Button("start timer"); > button.setOnAction(_ -> { > var timer = new AnimationTimer() { > @Override > public void handle(long l) { > throw new RuntimeException("foo"); > } > }; > > timer.start(); > }); > > var root = new HBox(); > root.getChildren().add(new TextField("test")); > root.getChildren().add(button); > stage.setScene(new Scene(root)); > stage.show(); > } > } > > > The solution is to not allow user exceptions to bubble up into animation > framework code. If an exception occurs, it is instead sent to the current > thread's uncaught exception handler. This is the same thing that we already > do for exceptions thrown by invalidation listeners and change listeners. > > In addition to that, a failing animation timer has the potential to spam > logs, which is why I introduced a cut-off value at 100 exceptions for each > individual timer, after which no further exceptions from this particular > timer are sent to the uncaught exception handler. After reaching the cut-off > value, the following warning is logged: > > `WARNING: Too many exceptions thrown by AnimationTimer, ignoring further > exceptions. The cut-off number can be set with the system property > com.sun.scenario.animation.failingTimerThreshold (current = 100).` modules/javafx.graphics/src/main/java/com/sun/scenario/animation/AbstractPrimaryTimer.java line 66: > 64: private final int PULSE_DURATION_TICKS = > getPulseDuration((int)TickCalculation.fromMillis(1000)); > 65: > 66: private static final String FAILING_TIMER_THRESHOLD_PROP = > "com.sun.scenario.animation.failingTimerThreshold"; maybe a comment describing what this property does would be helpful for the digital paleontologist of the future modules/javafx.graphics/src/main/java/com/sun/scenario/animation/AbstractPrimaryTimer.java line 331: > 329: } > 330: > 331: receiversLocked = false; if L327 throws an exception, `receiversLocked` will not get cleared. modules/javafx.graphics/src/main/java/com/sun/scenario/animation/AbstractPrimaryTimer.java line 347: > 345: } > 346: > 347: animationTimersLocked = false; same here ------------- PR Review Comment: https://git.openjdk.org/jfx/pull/1811#discussion_r2093467739 PR Review Comment: https://git.openjdk.org/jfx/pull/1811#discussion_r2093466067 PR Review Comment: https://git.openjdk.org/jfx/pull/1811#discussion_r2093466315