Skip to content

Commit 1e729ed

Browse files
committed
CSSTUDIO-2472 Bugfix: Fix freezes of Display Runtime occurring when rapidly changing between embedded displays.
1 parent abd2826 commit 1e729ed

File tree

4 files changed

+65
-77
lines changed

4 files changed

+65
-77
lines changed

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/EmbeddedDisplayRepresentation.java

Lines changed: 65 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.util.concurrent.atomic.AtomicReference;
1616
import java.util.logging.Level;
1717

18+
import javafx.application.Platform;
1819
import org.csstudio.display.builder.model.DirtyFlag;
1920
import org.csstudio.display.builder.model.DisplayModel;
2021
import org.csstudio.display.builder.model.UntypedWidgetPropertyListener;
@@ -256,7 +257,7 @@ private void fileChanged(final WidgetProperty<?> property, final Object old_valu
256257

257258
/** Update to the next pending display
258259
*
259-
* <p>Synchronized to serialize the background threads.
260+
* <p>Executed on the JavaFX Application Thread to serialize the background threads.
260261
*
261262
* <p>Example: Displays A, B, C are requested in quick succession.
262263
*
@@ -270,65 +271,56 @@ private void fileChanged(final WidgetProperty<?> property, final Object old_valu
270271
* As thread C finally continues, it finds pending_display_and_group empty.
271272
* --> Showing A, then C, skipping B.
272273
*/
273-
private synchronized void updatePendingDisplay(final JobMonitor monitor)
274-
{
275-
try
276-
{
277-
final DisplayAndGroup handle = pending_display_and_group.getAndSet(null);
278-
if (handle == null)
279-
{
280-
// System.out.println("Nothing to handle");
281-
return;
282-
}
283-
if (inner == null)
284-
{
285-
// System.out.println("Aborted: " + handle);
286-
return;
287-
}
274+
private void updatePendingDisplay(final JobMonitor monitor) {
275+
Platform.runLater(() -> {
276+
try {
277+
final DisplayAndGroup handle = pending_display_and_group.getAndSet(null);
278+
if (handle == null) {
279+
// System.out.println("Nothing to handle");
280+
return;
281+
}
282+
if (inner == null) {
283+
// System.out.println("Aborted: " + handle);
284+
return;
285+
}
288286

289-
monitor.beginTask("Load " + handle);
290-
try
291-
{ // Load new model (potentially slow)
292-
final DisplayModel new_model = loadDisplayModel(model_widget, handle);
287+
monitor.beginTask("Load " + handle);
288+
try { // Load new model (potentially slow)
289+
final DisplayModel new_model = loadDisplayModel(model_widget, handle);
293290

294-
// Stop (old) runtime
295-
// EmbeddedWidgetRuntime tracks this property to start/stop the embedded model's runtime
296-
model_widget.runtimePropEmbeddedModel().setValue(null);
291+
// Stop (old) runtime
292+
// EmbeddedWidgetRuntime tracks this property to start/stop the embedded model's runtime
293+
model_widget.runtimePropEmbeddedModel().setValue(null);
297294

298-
// Atomically update the 'active' model
299-
final DisplayModel old_model = active_content_model.getAndSet(new_model);
300-
new_model.propBackgroundColor().addUntypedPropertyListener(backgroundChangedListener);
295+
// Atomically update the 'active' model
296+
final DisplayModel old_model = active_content_model.getAndSet(new_model);
297+
new_model.propBackgroundColor().addUntypedPropertyListener(backgroundChangedListener);
301298

302-
if (old_model != null)
303-
{ // Dispose old model
299+
if (old_model != null) { // Dispose old model
300+
final Future<Object> completion = toolkit.submit(() ->
301+
{
302+
toolkit.disposeRepresentation(old_model);
303+
return null;
304+
});
305+
checkCompletion(model_widget, completion, "timeout disposing old representation");
306+
}
307+
// Represent new model on UI thread
308+
toolkit.onRepresentationStarted();
304309
final Future<Object> completion = toolkit.submit(() ->
305310
{
306-
toolkit.disposeRepresentation(old_model);
311+
representContent(new_model);
307312
return null;
308313
});
309-
checkCompletion(model_widget, completion, "timeout disposing old representation");
314+
checkCompletion(model_widget, completion, "timeout representing new content");
315+
// Allow EmbeddedWidgetRuntime to start the new runtime
316+
model_widget.runtimePropEmbeddedModel().setValue(new_model);
317+
} catch (Exception ex) {
318+
logger.log(Level.WARNING, "Failed to handle embedded display " + handle, ex);
310319
}
311-
// Represent new model on UI thread
312-
toolkit.onRepresentationStarted();
313-
final Future<Object> completion = toolkit.submit(() ->
314-
{
315-
representContent(new_model);
316-
return null;
317-
});
318-
checkCompletion(model_widget, completion, "timeout representing new content");
319-
320-
// Allow EmbeddedWidgetRuntime to start the new runtime
321-
model_widget.runtimePropEmbeddedModel().setValue(new_model);
320+
} finally {
321+
toolkit.onRepresentationFinished();
322322
}
323-
catch (Exception ex)
324-
{
325-
logger.log(Level.WARNING, "Failed to handle embedded display " + handle, ex);
326-
}
327-
}
328-
finally
329-
{
330-
toolkit.onRepresentationFinished();
331-
}
323+
});
332324
}
333325

334326
/** @param content_model Model to represent */
@@ -471,26 +463,28 @@ else if (inner.getHeight() != 0.0 && inner.getWidth() != 0.0)
471463
}
472464

473465
@Override
474-
public void dispose()
475-
{
476-
// When the file name is changed, updatePendingDisplay()
477-
// will atomically update the active_content_model,
478-
// represent the new model, and then set runtimePropEmbeddedModel.
479-
//
480-
// Fetching the embedded model from active_content_model
481-
// could dispose a representation that hasn't been represented, yet.
482-
// Fetching the embedded model from runtimePropEmbeddedModel
483-
// could fail to dispose what's just now being represented.
484-
//
485-
// --> Very unlikely to happen because runtime has been stopped,
486-
// so nothing is changing the file name right now.
487-
final DisplayModel em = active_content_model.getAndSet(null);
488-
model_widget.runtimePropEmbeddedModel().setValue(null);
489-
490-
if (inner != null && em != null)
491-
toolkit.disposeRepresentation(em);
492-
inner = null;
493-
494-
super.dispose();
466+
public void dispose() {
467+
Platform.runLater(() -> {
468+
// When the file name is changed, updatePendingDisplay()
469+
// will atomically update the active_content_model,
470+
// represent the new model, and then set runtimePropEmbeddedModel.
471+
//
472+
// Fetching the embedded model from active_content_model
473+
// could dispose a representation that hasn't been represented, yet.
474+
// Fetching the embedded model from runtimePropEmbeddedModel
475+
// could fail to dispose what's just now being represented.
476+
//
477+
// --> Very unlikely to happen because runtime has been stopped,
478+
// so nothing is changing the file name right now.
479+
480+
final DisplayModel em = active_content_model.getAndSet(null);
481+
model_widget.runtimePropEmbeddedModel().setValue(null);
482+
483+
if (inner != null && em != null)
484+
toolkit.disposeRepresentation(em);
485+
inner = null;
486+
487+
super.dispose();
488+
});
495489
}
496490
}

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/JFXBaseRepresentation.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@ public void dispose()
251251
logger.log(Level.WARNING, "Missing JFX parent for " + model_widget);
252252
else
253253
JFXRepresentation.getChildren(parent).remove(jfx_node);
254-
jfx_node = null;
255254
}
256255

257256
/** Get parent that would be used for child-widgets.

app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/plots/XYPlotRepresentation.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,5 @@ public void dispose()
736736
{
737737
super.dispose();
738738
plot.dispose();
739-
plot = null;
740739
}
741740
}

app/display/representation/src/main/java/org/csstudio/display/builder/representation/WidgetRepresentation.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,5 @@ public void initialize(final ToolkitRepresentation<TWP, TW> toolkit,
8686
void destroy()
8787
{
8888
dispose();
89-
90-
// Speedup GC
91-
model_widget = null;
92-
toolkit = null;
9389
}
9490
}

0 commit comments

Comments
 (0)