From 889ca992f375f824797cbd577cbb0b162ccafb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Kohlschu=CC=88tter?= Date: Thu, 9 Nov 2023 15:24:24 +0100 Subject: [PATCH] Fix concurrency issue with AFSelector Clients may iterate upon AFSelector.selectedKeys() while the selected keys are modified in another thread. Change the underlying datastructure to be thread-safe (use ConcurrentHashMap), and add all "ready" selectors even if they're marked invalid (they will be removed later). We reimplement the fix as the original patch caused a FileDescriptor leak and TIPC test failures. https://github.com/kohlschutter/junixsocket/issues/142 https://github.com/kohlschutter/junixsocket/issues/145 --- .../main/java/org/newsclub/net/unix/AFSelector.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/junixsocket-common/src/main/java/org/newsclub/net/unix/AFSelector.java b/junixsocket-common/src/main/java/org/newsclub/net/unix/AFSelector.java index 433aac740..28119e133 100644 --- a/junixsocket-common/src/main/java/org/newsclub/net/unix/AFSelector.java +++ b/junixsocket-common/src/main/java/org/newsclub/net/unix/AFSelector.java @@ -29,7 +29,6 @@ import java.nio.channels.spi.AbstractSelectableChannel; import java.nio.channels.spi.AbstractSelector; import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -47,8 +46,8 @@ final class AFSelector extends AbstractSelector { private final Set keysRegisteredPublic = Collections.unmodifiableSet( keysRegisteredKeySet); - private final Set selectedKeysSet = new HashSet<>(); - private final Set selectedKeysPublic = new UngrowableSet<>(selectedKeysSet); + private final Map selectedKeysSet = new ConcurrentHashMap<>(); + private final Set selectedKeysPublic = new UngrowableSet<>(selectedKeysSet.keySet()); private PollFd pollFd = null; @@ -185,8 +184,8 @@ private synchronized void setOpsReady(PollFd pfd) { int rops = pfd.rops[i]; AFSelectionKey key = pfd.keys[i]; key.setOpsReady(rops); - if (rops != 0 && key.isValid()) { - selectedKeysSet.add(key); + if (rops != 0) { + selectedKeysSet.put(key, key); } } } @@ -197,7 +196,7 @@ private PollFd initPollFd(PollFd existingPollFd) throws IOException { synchronized (this) { for (Iterator it = keysRegisteredKeySet.iterator(); it.hasNext();) { AFSelectionKey key = it.next(); - if (!key.getAFCore().fd.valid() || key.hasOpInvalid()) { + if (!key.getAFCore().fd.valid() || !key.isValid()) { key.cancelNoRemove(); it.remove(); existingPollFd = null;