Synchronize input event processing

Some renderers (OpenGL) fire events on background threads, which can
corrupt the event queue when the sketch is not looping and multiple
threads add and remove from the queue at the same time.

This PR uses blocking queue to serialize enqueuing and lock to
synchronize dequeuing.

In the ideal case, we should be able to invoke code on the animation
thread (ala invokeLater) and always dequeue events from there even when
the sketch is not looping.
This commit is contained in:
Jakub Valtar
2017-04-09 18:32:53 +02:00
parent a05a375104
commit aadf2140ca
+15 -42
View File
@@ -61,6 +61,8 @@ import java.net.*;
import java.nio.charset.StandardCharsets;
import java.text.*;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.*;
import java.util.zip.*;
@@ -2564,38 +2566,8 @@ public class PApplet implements PConstants {
//////////////////////////////////////////////////////////////
InternalEventQueue eventQueue = new InternalEventQueue();
static class InternalEventQueue {
protected Event queue[] = new Event[10];
protected int offset;
protected int count;
synchronized void add(Event e) {
if (count == queue.length) {
queue = (Event[]) expand(queue);
}
queue[count++] = e;
}
synchronized Event remove() {
if (offset == count) {
throw new RuntimeException("Nothing left on the event queue.");
}
Event outgoing = queue[offset++];
if (offset == count) {
// All done, time to reset
offset = 0;
count = 0;
}
return outgoing;
}
synchronized boolean available() {
return count != 0;
}
}
BlockingQueue<Event> eventQueue = new LinkedBlockingQueue<>();
private final Object eventQueueDequeueLock = new Object[0];
/**
@@ -2612,16 +2584,17 @@ public class PApplet implements PConstants {
protected void dequeueEvents() {
while (eventQueue.available()) {
Event e = eventQueue.remove();
switch (e.getFlavor()) {
case Event.MOUSE:
handleMouseEvent((MouseEvent) e);
break;
case Event.KEY:
handleKeyEvent((KeyEvent) e);
break;
synchronized (eventQueueDequeueLock) {
while (!eventQueue.isEmpty()) {
Event e = eventQueue.remove();
switch (e.getFlavor()) {
case Event.MOUSE:
handleMouseEvent((MouseEvent) e);
break;
case Event.KEY:
handleKeyEvent((KeyEvent) e);
break;
}
}
}
}