From 79e9ddc5247ae154d5f63ceeeb02afb293dbc91f Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 2 May 2013 14:19:06 +0300 Subject: Make access() throw if another session is already locked (#11757) Change-Id: Ic8571b0d078c3ff64e8b9914e55c51766ae49024 --- server/src/com/vaadin/server/VaadinService.java | 19 +++++++++++++++++++ server/src/com/vaadin/server/VaadinSession.java | 12 ++++++++++++ server/src/com/vaadin/ui/UI.java | 10 ++++++++++ 3 files changed, 41 insertions(+) diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index f6b520d4b0..083bd4bedf 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -1540,6 +1540,25 @@ public abstract class VaadinService implements Serializable { return false; } + /** + * Checks that another {@link VaadinSession} instance is not locked. This is + * internally used by {@link VaadinSession#access(Runnable)} and + * {@link UI#access(Runnable)} to help avoid causing deadlocks. + * + * @since 7.1 + * @param session + * the session that is being locked + * @throws IllegalStateException + * if the current thread holds the lock for another session + */ + public static void verifyNoOtherSessionLocked(VaadinSession session) { + VaadinSession otherSession = VaadinSession.getCurrent(); + if (otherSession != null && otherSession != session) { + throw new IllegalStateException( + "Can't access session while another session is locked by the same thread. This restriction is intended to help avoid deadlocks."); + } + } + /** * Verifies that the given CSRF token (aka double submit cookie) is valid * for the given session. This is used to protect against Cross Site Request diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index fe786ad52b..317ea6cf7b 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -1075,15 +1075,27 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * as the session is automatically locked by the framework during request * handling. *

+ *

+ * Note that calling this method while another session is locked by the + * current thread will cause an exception. This is to prevent deadlock + * situations when two threads have locked one session each and are both + * waiting for the lock for the other session. + *

* * @param runnable * the runnable which accesses the session * + * @throws IllegalStateException + * if the current thread holds the lock for another session + * + * * @see #lock() * @see #getCurrent() * @see UI#access(Runnable) */ public void access(Runnable runnable) { + VaadinService.verifyNoOtherSessionLocked(this); + Map, CurrentInstance> old = null; lock(); try { diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index f260a6af79..6433bebbe4 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -1103,12 +1103,20 @@ public abstract class UI extends AbstractSingleComponentContainer implements * RPC handlers for components inside this UI do not need this method as the * session is automatically locked by the framework during request handling. *

+ *

+ * Note that calling this method while another session is locked by the + * current thread will cause an exception. This is to prevent deadlock + * situations when two threads have locked one session each and are both + * waiting for the lock for the other session. + *

* * @param runnable * the runnable which accesses the UI * @throws UIDetachedException * if the UI is not attached to a session (and locking can * therefore not be done) + * @throws IllegalStateException + * if the current thread holds the lock for another session * * @see #getCurrent() * @see VaadinSession#access(Runnable) @@ -1123,6 +1131,8 @@ public abstract class UI extends AbstractSingleComponentContainer implements throw new UIDetachedException(); } + VaadinService.verifyNoOtherSessionLocked(session); + session.lock(); try { if (getSession() == null) { -- cgit v1.2.3