Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

klighd.lsp: Added main thread queue for SWT and AWT calls. #66

Merged
merged 3 commits into from
Aug 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import de.cau.cs.kieler.klighd.krendering.KRendering
import de.cau.cs.kieler.klighd.krendering.KText
import de.cau.cs.kieler.klighd.lsp.interactive.layered.ConstraintActionHandler
import de.cau.cs.kieler.klighd.lsp.interactive.rectpack.RectPackActionHandler
import de.cau.cs.kieler.klighd.lsp.launch.AbstractLanguageServer
import de.cau.cs.kieler.klighd.lsp.model.CheckImagesAction
import de.cau.cs.kieler.klighd.lsp.model.CheckedImagesAction
import de.cau.cs.kieler.klighd.lsp.model.ComputedTextBoundsAction
Expand Down Expand Up @@ -295,9 +296,11 @@ class KGraphDiagramServer extends LanguageAwareDiagramServer {
* FIXME Remove this if UpdateModelAction has a cause.
*/
def void doSubmitModel(SModelRoot newRoot, boolean update, Action cause) {
var ILayoutEngine layoutEngine = getLayoutEngine();
val ILayoutEngine layoutEngine = getLayoutEngine();
if (needsServerLayout(newRoot, cause)) {
layoutEngine.layout(newRoot, cause);
AbstractLanguageServer.addToMainThreadQueue([
layoutEngine.layout(newRoot, cause)
])
}
synchronized (modelLock) {
if (newRoot.getRevision() == revision) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import de.cau.cs.kieler.klighd.SynthesisOption
import de.cau.cs.kieler.klighd.ViewContext
import de.cau.cs.kieler.klighd.ide.model.MessageModel
import de.cau.cs.kieler.klighd.kgraph.KNode
import de.cau.cs.kieler.klighd.lsp.launch.AbstractLanguageServer
import de.cau.cs.kieler.klighd.lsp.model.SKGraph
import de.cau.cs.kieler.klighd.util.KlighdSynthesisProperties
import java.util.HashSet
Expand Down Expand Up @@ -213,8 +214,11 @@ class KGraphDiagramUpdater extends DiagramUpdater {
} else {
viewContext.copyProperties(properties)
}
val vc = viewContext
// Update the model and with that call the diagram synthesis.
viewContext.update(model)
AbstractLanguageServer.addToMainThreadQueue([
vc.update(model)
])

synchronized (diagramState) {
diagramState.putURIString(server.clientId, uri)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import de.cau.cs.kieler.klighd.IAction.ActionContext
import de.cau.cs.kieler.klighd.KlighdDataManager
import de.cau.cs.kieler.klighd.SynthesisOption
import de.cau.cs.kieler.klighd.ViewContext
import de.cau.cs.kieler.klighd.lsp.launch.AbstractLanguageServer
import de.cau.cs.kieler.klighd.lsp.model.GetOptionsParam
import de.cau.cs.kieler.klighd.lsp.model.GetOptionsResult
import de.cau.cs.kieler.klighd.lsp.model.LayoutOptionUIData
Expand Down Expand Up @@ -256,7 +257,9 @@ class KGraphLanguageServerExtension extends SyncDiagramLanguageServer
}
// Update the diagram.
if (diagramUpdater instanceof KGraphDiagramUpdater) {
(diagramUpdater as KGraphDiagramUpdater).updateDiagrams2(#[_uriExtensions.toUri(decodedUri)])
AbstractLanguageServer.addToMainThreadQueue([
(diagramUpdater as KGraphDiagramUpdater).updateDiagrams2(#[_uriExtensions.toUri(decodedUri)])
])
return null
}
throw new IllegalStateException("The diagramUpdater is not setup correctly.")
Expand Down Expand Up @@ -295,7 +298,9 @@ class KGraphLanguageServerExtension extends SyncDiagramLanguageServer
// Update the layout of the diagram.
val diagramServer = this.diagramServerManager.findDiagramServersByUri(decodedUri).head
if (diagramUpdater instanceof KGraphDiagramUpdater && diagramServer instanceof KGraphDiagramServer) {
(diagramUpdater as KGraphDiagramUpdater).updateLayout(diagramServer as KGraphDiagramServer)
AbstractLanguageServer.addToMainThreadQueue([
(diagramUpdater as KGraphDiagramUpdater).updateLayout(diagramServer as KGraphDiagramServer)
])
} else {
throw new IllegalStateException("The diagram server or diagram updater are not set up correctly.")
}
Expand All @@ -319,7 +324,9 @@ class KGraphLanguageServerExtension extends SyncDiagramLanguageServer
val diagramServer = this.diagramServerManager.findDiagramServersByUri(decodedUri)
.filter(KGraphDiagramServer).head
if (diagramServer !== null) {
diagramUpdater.updateDiagram(diagramServer)
AbstractLanguageServer.addToMainThreadQueue([
diagramUpdater.updateDiagram(diagramServer)
])
} else {
throw new IllegalStateException("The diagram server is not set up correctly.")
}
Expand All @@ -333,7 +340,9 @@ class KGraphLanguageServerExtension extends SyncDiagramLanguageServer
val diagramServer = this.diagramServerManager.findDiagramServersByUri(decodedUri)
.filter(KGraphDiagramServer).head
if (diagramServer !== null) {
(diagramUpdater as KGraphDiagramUpdater).updateLayout(diagramServer)
AbstractLanguageServer.addToMainThreadQueue([
(diagramUpdater as KGraphDiagramUpdater).updateLayout(diagramServer)
])
} else {
throw new IllegalStateException("The diagram server is not set up correctly.")
}
Expand Down Expand Up @@ -450,7 +459,9 @@ class KGraphLanguageServerExtension extends SyncDiagramLanguageServer
// use the 'model' as its model.
if (diagramUpdater instanceof KGraphDiagramUpdater) {
(diagramUpdater as KGraphDiagramUpdater).prepareModel(diagramServer, model, uri)
(diagramUpdater as KGraphDiagramUpdater).updateLayout(diagramServer)
AbstractLanguageServer.addToMainThreadQueue([
(diagramUpdater as KGraphDiagramUpdater).updateLayout(diagramServer)
])
// Also, update the syntheses available for the given diagram.
if (!update) {
val availableSynthesesData = getAvailableSynthesesData(model.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import com.google.inject.Guice
import java.net.InetSocketAddress
import java.nio.channels.AsynchronousServerSocketChannel
import java.nio.channels.Channels
import java.util.concurrent.BlockingQueue
import java.util.concurrent.Executors
import java.util.concurrent.LinkedBlockingQueue
import java.util.function.Consumer
import org.apache.log4j.Logger
import org.eclipse.lsp4j.services.LanguageServer
import org.eclipse.xtext.ide.server.LanguageServerImpl
Expand Down Expand Up @@ -46,6 +49,11 @@ abstract class AbstractLanguageServer implements Runnable {
extension ILanguageRegistration languageRegistration

extension ILsCreator creator

/**
* Queue to execute SWT or AWT calls on the main Thread.
*/
private static val BlockingQueue<Consumer<Void>> mainThreadQueue = new LinkedBlockingQueue<Consumer<Void>>()

/**
* Configure this the launch of this language server with the language registration, a language server creator and
Expand All @@ -57,7 +65,44 @@ abstract class AbstractLanguageServer implements Runnable {
def configureAndRun(ILanguageRegistration languageRegistration, ILsCreator lsCreator) {
this.languageRegistration = languageRegistration
this.creator = lsCreator
run
// Start LS an new Thread to use this as UI Thread.
new Thread([
run
]).start()
while (true) {
synchronized (mainThreadQueue) {
// Wait until a new function arrives
while (mainThreadQueue.isNullOrEmpty) {
mainThreadQueue.wait
}
// Get new element of queue and only empty after it was processed to make sure that waiting clients
// are not able to continue before the function is executed.
val f = mainThreadQueue.peek
if (f !== null) {
f.accept(null)
mainThreadQueue.poll
mainThreadQueue.notify
}
}
}
}

/**
* Add a new function to be executed on the main Thread.
* This method will wait until the function is executed.
*/
public static def addToMainThreadQueue(Consumer<Object> f) {

synchronized (mainThreadQueue) {
mainThreadQueue.add([
f.accept(null)
])
// Wait to continue
while (!mainThreadQueue.isNullOrEmpty) {
mainThreadQueue.notify
mainThreadQueue.wait
}
}
}

/**
Expand Down