Skip to content

Commit

Permalink
fix: clear CurrentInstance before invoking new session tasks (vaadin#…
Browse files Browse the repository at this point in the history
  • Loading branch information
archiecobbs committed Oct 15, 2024
1 parent 1937249 commit 1df59e9
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -2147,11 +2147,12 @@ public void runPendingAccessTasks(VaadinSession session) {
// Dump all current instances, not only the ones dumped by setCurrent
Map<Class<?>, CurrentInstance> oldInstances = CurrentInstance
.getInstances();
CurrentInstance.setCurrent(session);
try {
while ((pendingAccess = session.getPendingAccessQueue()
.poll()) != null) {
if (!pendingAccess.isCancelled()) {
CurrentInstance.clearAll();
CurrentInstance.setCurrent(session);
pendingAccess.run();

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -189,6 +191,69 @@ public Map<String, String[]> getParameterMap() {

}

/**
* Test for issue #6349
*/
@Test
public void testCurrentInstancePollution() throws InterruptedException {

// Create a sync object
final AtomicInteger state = new AtomicInteger();

// For sleeping while we wait
final Runnable napper = () -> {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
return;
}
};

// We need to unlock session before running this test
session.unlock();
try {

// Create a thread that holds the session lock until we tell it to
// unlock; this will cause VaadinSession.access() to enqueue tasks
// instead of running them immediately.
Thread thread = new Thread(() -> {
session.accessSynchronously(() -> {
state.incrementAndGet();
while (state.get() == 1)
napper.run();
});
});

// Start thread and wait for it to grab the lock
thread.start();
while (state.get() == 0)
napper.run();

// Enqueue two session commands
session.access(() -> {
UI.setCurrent(ui); // command #1 sets current UI
state.incrementAndGet();
});
final AtomicReference<UI> uiRef = new AtomicReference<>();
session.access(() -> {
uiRef.set(UI.getCurrent()); // command #2 reads current UI
state.incrementAndGet();
});

// Release the session lock, which will run the queue
state.incrementAndGet();

// Wait for enqueued tasks to complete
while (state.get() < 4)
napper.run();

// Command #2 should not have seen command #1's UI
Assert.assertNull(uiRef.get());
} finally {
session.lock();
}
}

/**
* This reproduces #14452 situation with deadlock - see diagram
*/
Expand Down

0 comments on commit 1df59e9

Please sign in to comment.