[Jython-checkins] jython: No longer causes a stack overflow on "infinite reloads"

jim.baker jython-checkins at python.org
Wed Dec 17 01:35:13 CET 2014


https://hg.python.org/jython/rev/8708596b329f
changeset:   7461:8708596b329f
user:        Jim Baker <jim.baker at rackspace.com>
date:        Tue Dec 16 17:34:50 2014 -0700
summary:
  No longer causes a stack overflow on "infinite reloads"

Previously infinite_reload.py in test_import would cause a
RuntimeError due to a stack overflow. Now handles the same as CPython
by tracking which module is currently being reloaded, and returns
immediately with that module.

files:
  src/org/python/core/PySystemState.java |   5 +-
  src/org/python/core/imp.java           |  26 ++++++++++++-
  2 files changed, 26 insertions(+), 5 deletions(-)


diff --git a/src/org/python/core/PySystemState.java b/src/org/python/core/PySystemState.java
--- a/src/org/python/core/PySystemState.java
+++ b/src/org/python/core/PySystemState.java
@@ -19,6 +19,7 @@
 import java.nio.charset.Charset;
 import java.nio.charset.UnsupportedCharsetException;
 import java.security.AccessControlException;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
@@ -131,7 +132,7 @@
     public PyList argv = new PyList();
 
     public PyObject modules;
-    public PyObject modules_reloading;
+    public Map<String, PyModule> modules_reloading;
     private ReentrantLock importLock;
     private ClassLoader syspathJavaLoader;
     public PyList path;
@@ -194,7 +195,7 @@
         initialize();
         closer = new PySystemStateCloser(this);
         modules = new PyStringMap();
-        modules_reloading = new PyStringMap();
+        modules_reloading = new HashMap<String, PyModule>();
         importLock = new ReentrantLock();
         syspathJavaLoader = new SyspathJavaLoader(imp.getParentClassLoader());
 
diff --git a/src/org/python/core/imp.java b/src/org/python/core/imp.java
--- a/src/org/python/core/imp.java
+++ b/src/org/python/core/imp.java
@@ -7,6 +7,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Map;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.python.compiler.Module;
@@ -1146,15 +1147,34 @@
     }
 
     static PyObject reload(PyModule m) {
+        PySystemState sys = Py.getSystemState();
+        PyObject modules = sys.modules;
+        Map<String, PyModule> modules_reloading = sys.modules_reloading;
+        ReentrantLock importLock = Py.getSystemState().getImportLock();
+        importLock.lock();
+        try {
+            return _reload(m, modules, modules_reloading);
+        } finally {
+            modules_reloading.clear();
+            importLock.unlock();
+        }
+    }
+
+    private static PyObject _reload(PyModule m, PyObject modules, Map<String, PyModule> modules_reloading) {
         String name = m.__getattr__("__name__").toString().intern();
-
-        PyObject modules = Py.getSystemState().modules;
         PyModule nm = (PyModule) modules.__finditem__(name);
-
         if (nm == null || !nm.__getattr__("__name__").toString().equals(name)) {
             throw Py.ImportError("reload(): module " + name
                     + " not in sys.modules");
         }
+        PyModule existing_module = modules_reloading.get(name);
+        if (existing_module != null) {
+        // Due to a recursive reload, this module is already being reloaded.
+            return existing_module;
+        }
+        // Since we are already in a re-entrant lock,
+        // this test & set is guaranteed to be atomic
+        modules_reloading.put(name, nm);
 
         PyList path = Py.getSystemState().path;
         String modName = name;

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list