From 32dcd895bac5d426dfc78521cd35a1d44c04d76d Mon Sep 17 00:00:00 2001 From: "igor%mir2.org" Date: Wed, 23 Oct 2002 09:56:26 +0000 Subject: [PATCH] I modified Context.enter/Context.exit to remove explicit synchronization on threadContexts as implicit implicit synchronization when calling threadContexts.get/threadContexts.put/threadContexts.remove is enough to ensure thread safety. It reduces time spend in synchronized code so Context.enter/Context.exit is less problematic with script execution on many threads. The change also allows with simple modifications of Context.getCurrentContext and Context.setThreadContext to use java.lang.ThreadLocal from JDK 1.2 to remove any synchronization on global data structures during Context.enter/Context.exit/Context.getCurrentContext. --- .../src/org/mozilla/javascript/Context.java | 96 ++++++++++--------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/js/rhino/src/org/mozilla/javascript/Context.java b/js/rhino/src/org/mozilla/javascript/Context.java index a919c1047752..b7485d5a1eb8 100644 --- a/js/rhino/src/org/mozilla/javascript/Context.java +++ b/js/rhino/src/org/mozilla/javascript/Context.java @@ -157,41 +157,42 @@ public class Context { * @return a Context associated with the current thread */ public static Context enter(Context cx) { - Thread t = Thread.currentThread(); - Object[] listeners; - Context current; - synchronized (threadContexts) { - current = (Context) threadContexts.get(t); - if (cx != null) { - // Check supplied context sanity - Thread old = cx.currentThread; - if (old != null && old != t) { + + Context old = getCurrentContext(); + + if (cx == null) { + if (old != null) { + cx = old; + } else { + cx = new Context(); + setThreadContext(cx); + } + } else { + if (cx.enterCount != 0) { + // The suplied context must be the context for + // the current thread if it is already entered + if (cx != old) { throw new RuntimeException ("Cannot enter Context active on another thread"); } - if (Context.check && old == t && cx != current) - Context.codeBug(); - } - - if (current == null) { - if (cx == null) { - cx = new Context(); + } else { + if (old != null) { + cx = old; + } else { + setThreadContext(cx); } - cx.currentThread = t; - threadContexts.put(t, cx); - current = cx; } - - ++current.enterCount; - listeners = contextListeners; } + ++cx.enterCount; + + Object[] listeners = contextListeners; if (listeners != null) { for (int i = listeners.length; i-- != 0;) { - ((ContextListener)listeners[i]).contextEntered(current); + ((ContextListener)listeners[i]).contextEntered(cx); } } - return current; + return cx; } /** @@ -208,29 +209,20 @@ public class Context { * @see org.mozilla.javascript.Context#enter */ public static void exit() { - Thread t = Thread.currentThread(); boolean released = false; - Context cx; - Object[] listeners; - synchronized (threadContexts) { - cx = (Context)threadContexts.get(t); - if (cx == null) { - throw new RuntimeException - ("Calling Context.exit without previous Context.enter"); - } - if (Context.check && (cx.currentThread != t || cx.enterCount < 1)) - Context.codeBug(); - - --cx.enterCount; - if (cx.enterCount == 0) { - released = true; - threadContexts.remove(t); - cx.currentThread = null; - } - - listeners = contextListeners; + Context cx = getCurrentContext(); + if (cx == null) { + throw new RuntimeException + ("Calling Context.exit without previous Context.enter"); + } + if (Context.check && cx.enterCount < 1) Context.codeBug(); + --cx.enterCount; + if (cx.enterCount == 0) { + released = true; + setThreadContext(null); } + Object[] listeners = contextListeners; if (listeners != null) { for (int i = listeners.length; i-- != 0;) { ((ContextListener)listeners[i]).contextExited(cx); @@ -247,7 +239,7 @@ public class Context { * Add a Context listener. */ public static void addContextListener(ContextListener listener) { - synchronized (threadContexts) { + synchronized (contextListenersLock) { contextListeners = ListenerArray.add(contextListeners, listener); } } @@ -257,7 +249,7 @@ public class Context { * @param listener the listener to remove. */ public static void removeContextListener(ContextListener listener) { - synchronized (threadContexts) { + synchronized (contextListenersLock) { contextListeners = ListenerArray.remove(contextListeners, listener); } } @@ -279,6 +271,15 @@ public class Context { return (Context) threadContexts.get(t); } + private static void setThreadContext(Context cx) { + Thread t = Thread.currentThread(); + if (cx != null) { + threadContexts.put(t, cx); + } else { + threadContexts.remove(t); + } + } + /** * Language versions * @@ -2191,6 +2192,8 @@ public class Context { static boolean isCachingEnabled = true; private static Hashtable threadContexts = new Hashtable(11); + + private static final Object contextListenersLock = new Object(); private static Object[] contextListeners; /** @@ -2211,7 +2214,6 @@ public class Context { private SecurityController securityController; private ClassShutter classShutter; private ErrorReporter errorReporter; - private Thread currentThread; private RegExpProxy regExpProxy; private Locale locale; private boolean generatingDebug;