]> granicus.if.org Git - python/commitdiff
Convert the internal ctypes array type cache to a WeakValueDict so
authorThomas Heller <theller@ctypes.org>
Wed, 16 Jan 2008 19:16:27 +0000 (19:16 +0000)
committerThomas Heller <theller@ctypes.org>
Wed, 16 Jan 2008 19:16:27 +0000 (19:16 +0000)
that array types do not live longer than needed.

Lib/ctypes/test/test_arrays.py
Misc/NEWS
Modules/_ctypes/_ctypes.c

index e635ae1741d84306d2a7b119d5f12112b0e4b80c..7ee16c1f02d6596174eea8e11452c78ca867d3ca 100644 (file)
@@ -116,5 +116,19 @@ class ArrayTestCase(unittest.TestCase):
             self.failUnlessEqual(sz[1:4:2], "o")
             self.failUnlessEqual(sz.value, "foo")
 
+    def test_cache(self):
+        # Array types are cached internally in the _ctypes extension,
+        # in a WeakValueDictionary.  Make sure the array type is
+        # removed from the cache when the itemtype goes away.  This
+        # test will not fail, but will show a leak in the testsuite.
+
+        # Create a new type:
+        class my_int(c_int):
+            pass
+        # Create a new array type based on it:
+        t1 = my_int * 1
+        t2 = my_int * 1
+        self.failUnless(t1 is t2)
+
 if __name__ == '__main__':
     unittest.main()
index 0be1934f86230c52ad9a2ae4d3a251989770779a..0a7d00c80312f555097d11444b05956046cf6eb3 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -364,6 +364,9 @@ Core and builtins
 Library
 -------
 
+- Convert the internal ctypes array type cache to a WeakValueDict so
+  that array types do not live longer than needed.
+
 - Issue #1786: pdb should use its own stdin/stdout around an exec call
   and when creating a recursive instance.
 
index 9d7290f8e3774ad999b1d11a98b89c0978017030..1ff8e12ce5c17b25f35a5723c977b200eb00969f 100644 (file)
@@ -127,6 +127,7 @@ bytes(cdata)
 
 PyObject *PyExc_ArgError;
 static PyTypeObject Simple_Type;
+PyObject *array_types_cache;
 
 char *conversion_mode_encoding = NULL;
 char *conversion_mode_errors = NULL;
@@ -4086,16 +4087,10 @@ PyTypeObject Array_Type = {
 PyObject *
 CreateArrayType(PyObject *itemtype, Py_ssize_t length)
 {
-       static PyObject *cache;
        PyObject *key;
        PyObject *result;
        char name[256];
 
-       if (cache == NULL) {
-               cache = PyDict_New();
-               if (cache == NULL)
-                       return NULL;
-       }
 #if (PY_VERSION_HEX < 0x02050000)
        key = Py_BuildValue("(Oi)", itemtype, length);
 #else
@@ -4103,12 +4098,12 @@ CreateArrayType(PyObject *itemtype, Py_ssize_t length)
 #endif
        if (!key)
                return NULL;
-       result = PyDict_GetItem(cache, key);
+       result = PyObject_GetItem(array_types_cache, key);
        if (result) {
-               Py_INCREF(result);
                Py_DECREF(key);
                return result;
-       }
+       } else
+               PyErr_Clear();
 
        if (!PyType_Check(itemtype)) {
                PyErr_SetString(PyExc_TypeError,
@@ -4138,7 +4133,11 @@ CreateArrayType(PyObject *itemtype, Py_ssize_t length)
                );
        if (!result)
                return NULL;
-       PyDict_SetItem(cache, key, result);
+       if (-1 == PyObject_SetItem(array_types_cache, key, result)) {
+               Py_DECREF(key);
+               Py_DECREF(result);
+               return NULL;
+       }
        Py_DECREF(key);
        return result;
 }
@@ -4951,6 +4950,7 @@ PyMODINIT_FUNC
 init_ctypes(void)
 {
        PyObject *m;
+       PyObject *weakref;
 
 /* Note:
    ob_type is the metatype (the 'type'), defaults to PyType_Type,
@@ -4963,6 +4963,16 @@ init_ctypes(void)
        if (!m)
                return;
 
+       weakref = PyImport_ImportModule("weakref");
+       if (weakref == NULL)
+               return;
+       array_types_cache = PyObject_CallMethod(weakref,
+                                               "WeakValueDictionary",
+                                               NULL);
+       if (array_types_cache == NULL)
+               return;
+       Py_DECREF(weakref);
+
        if (PyType_Ready(&PyCArg_Type) < 0)
                return;