From e6788877d5d1fd3f9eead731a660f83906af9d27 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Wed, 16 Feb 2022 19:37:35 +0100 Subject: [PATCH] Handle cancelled selection keys... "properly"? This seems very needlessly complex for something which shouldn't even have to be an issue, but I can't obviously see how else to handle it, but also not really what the whole point of selectors "cancelled-sets" is. --- src/jagi/event/Driver.java | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/jagi/event/Driver.java b/src/jagi/event/Driver.java index 59f54a3..6ee920f 100644 --- a/src/jagi/event/Driver.java +++ b/src/jagi/event/Driver.java @@ -58,6 +58,7 @@ public class Driver { final Map watching = new IdentityHashMap<>(); final Heap timeheap = new Heap<>(Comparator.naturalOrder()); final Map paused = new IdentityHashMap<>(); + final Collection cancelled = new HashSet<>(); SelectPool(SelectorProvider provider) { this.provider = provider; @@ -112,14 +113,26 @@ public class Driver { return; } if(first != null) - timeout = Math.max((long)Math.ceil((first - now) * 1000), 0); + timeout = Math.max((long)Math.ceil((first - now) * 1000), 1); } + Collection precancelled; + synchronized(cancelled) { + precancelled = new ArrayList<>(cancelled); + } + if(!precancelled.isEmpty()) + timeout = 1; poll.selectedKeys().clear(); try { poll.select(timeout); } catch(IOException e) { throw(new RuntimeException(e)); } + if(!precancelled.isEmpty()) { + synchronized(cancelled) { + cancelled.removeAll(precancelled); + cancelled.notifyAll(); + } + } for(SelectionKey key : poll.selectedKeys()) handle((Watcher)key.attachment(), key.readyOps()); now = time(); @@ -193,14 +206,28 @@ public class Driver { SelectionKey wc = watching.remove(w); Object tc = timeheap.remove(w); Object pc = paused.remove(w); - if(wc != null) - wc.cancel(); + if(wc != null) { + synchronized(cancelled) { + cancelled.add(wc); + wc.cancel(); + poll.wakeup(); + boolean irq = false; + while(cancelled.contains(wc)) { + try { + cancelled.wait(); + } catch(InterruptedException e) { + irq = true; + } + } + if(irq) + Thread.currentThread().interrupt(); + } + } if(((wc != null) || (tc != null)) && (pc != null)) throw(new RuntimeException(w + ": inconsistent internal state")); if(wc == null) throw(new IllegalStateException(w + ": not registered")); submit(() -> close(w)); - poll.wakeup(); } void update(Watcher w) { -- 2.11.0