mirror of
https://git.freebsd.org/ports.git
synced 2025-06-01 02:46:27 -04:00
- Update to Python-2.3.3
- Pass PYTHON_VERSION variable to dependent builds. - Enable email package to use cjkcodecs. - Decrease default recursion limit to 900 on sparc64.
This commit is contained in:
parent
10a8a72040
commit
60d09f59f5
Notes:
svn2git
2021-03-31 03:12:20 +00:00
svn path=/head/; revision=96254
29 changed files with 134 additions and 1526 deletions
|
@ -180,6 +180,7 @@ PYTHON_VERSION?= python${_PYTHON_VERSION}
|
|||
PYTHON_CMD?= ${_PYTHON_CMD}
|
||||
PYTHONBASE!= (${PYTHON_CMD} -c 'import sys; print sys.prefix') \
|
||||
2> /dev/null || echo ${LOCALBASE}
|
||||
DEPENDS_ARGS+= PYTHON_VERSION=${PYTHON_VERSION}
|
||||
_PYTHON_PORTVERSION!= (${PYTHON_CMD} -c 'import string, sys; \
|
||||
print string.split(sys.version)[0]') 2> /dev/null || ${TRUE}
|
||||
.if !defined(PYTHON_NO_DEPENDS) && !empty(_PYTHON_PORTVERSION)
|
||||
|
@ -195,9 +196,9 @@ PYTHON_SUFFIX= 24
|
|||
|
||||
# Python-2.3
|
||||
.elif ${PYTHON_VERSION} == "python2.3"
|
||||
PYTHON_PORTVERSION?=2.3.2
|
||||
PYTHON_PORTVERSION?=2.3.3
|
||||
PYTHON_PORTSDIR= ${PORTSDIR}/lang/python
|
||||
PYTHON_REL= 232
|
||||
PYTHON_REL= 233
|
||||
PYTHON_SUFFIX= 23
|
||||
|
||||
# Python-2.2
|
||||
|
|
|
@ -59,3 +59,8 @@ MD5 (python/pdf-a4-2.3.2.tar.bz2) = eae1a8eb7f13534ebf068808ac99b0e9
|
|||
MD5 (python/pdf-letter-2.3.2.tar.bz2) = 2677385da2db8c3fd05de937a9e148d3
|
||||
MD5 (python/postscript-a4-2.3.2.tar.bz2) = fc1752ce42810b87870688327bedecc7
|
||||
MD5 (python/postscript-letter-2.3.2.tar.bz2) = 5cca4937bf2b3b662d2c815ebc72a9d5
|
||||
MD5 (python/html-2.3.3.tar.bz2) = 5ec6e5782a3caf5177a3d47272a0267f
|
||||
MD5 (python/pdf-a4-2.3.3.tar.bz2) = ab6642490eb0ad0db894ec988b498db1
|
||||
MD5 (python/pdf-letter-2.3.3.tar.bz2) = 427334c0b5abdc579a494cbae1b64686
|
||||
MD5 (python/postscript-a4-2.3.3.tar.bz2) = 4176f64c51e1a975a4547f40f1075684
|
||||
MD5 (python/postscript-letter-2.3.3.tar.bz2) = d1954831f9d4c5be1457bae57fdb0ae4
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
#
|
||||
|
||||
PORTNAME= python
|
||||
PORTVERSION= 2.3.2
|
||||
PORTREVISION= 3
|
||||
PORTVERSION= 2.3.3
|
||||
CATEGORIES= lang python ipv6
|
||||
MASTER_SITES= ${PYTHON_MASTER_SITES}
|
||||
MASTER_SITE_SUBDIR= ${PYTHON_MASTER_SITE_SUBDIR}
|
||||
|
@ -83,6 +82,9 @@ PLIST_SUB+= 32BIT_ONLY="@comment "
|
|||
.else
|
||||
PLIST_SUB+= 32BIT_ONLY=""
|
||||
.endif
|
||||
.if ${ARCH} == sparc64
|
||||
CFLAGS+= -DPYTHON_DEFAULT_RECURSION_LIMIT=900
|
||||
.endif
|
||||
|
||||
.if ${OSVERSION} < 400000
|
||||
LIB_DEPENDS+= ncurses.5:${PORTSDIR}/devel/ncurses
|
||||
|
|
|
@ -13,4 +13,5 @@ MD5 (python/Python-2.2.3.tgz) = 169f89f318e252dac0c54dd1b165d229
|
|||
MD5 (python/Python-2.3.tgz) = 595620a4769073a812e353597585c4e8
|
||||
MD5 (python/Python-2.3.1.tgz) = a3dcbe1c7f173c8e3c7cce28495016ae
|
||||
MD5 (python/Python-2.3.2.tgz) = f54d7a529d444994b4b33429bbb45479
|
||||
MD5 (python/Python-2.3.3.tgz) = 4d16732b1cfccc0ed250956d41463c61
|
||||
MD5 (python/Python-2.4.a0.20031022.tgz) = 79581105c218886dd9dc382a84c64043
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
--- Include/weakrefobject.h.orig Mon Aug 12 16:21:58 2002
|
||||
+++ Include/weakrefobject.h Fri Nov 21 11:39:53 2003
|
||||
@@ -39,6 +39,8 @@
|
||||
|
||||
PyAPI_FUNC(long) _PyWeakref_GetWeakrefCount(PyWeakReference *head);
|
||||
|
||||
+PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self);
|
||||
+
|
||||
#define PyWeakref_GET_OBJECT(ref) (((PyWeakReference *)(ref))->wr_object)
|
||||
|
||||
|
23
lang/python/files/patch-Lib::email::Charset.py
Normal file
23
lang/python/files/patch-Lib::email::Charset.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
--- Lib/email/Charset.py.orig Sat Dec 20 15:16:29 2003
|
||||
+++ Lib/email/Charset.py Sat Dec 20 15:16:54 2003
|
||||
@@ -99,13 +99,13 @@
|
||||
# of stability and useability.
|
||||
|
||||
CODEC_MAP = {
|
||||
- 'euc-jp': 'japanese.euc-jp',
|
||||
- 'iso-2022-jp': 'japanese.iso-2022-jp',
|
||||
- 'shift_jis': 'japanese.shift_jis',
|
||||
- 'euc-kr': 'korean.euc-kr',
|
||||
- 'ks_c_5601-1987': 'korean.cp949',
|
||||
- 'iso-2022-kr': 'korean.iso-2022-kr',
|
||||
- 'johab': 'korean.johab',
|
||||
+ 'euc-jp': 'euc-jp',
|
||||
+ 'iso-2022-jp': 'iso-2022-jp',
|
||||
+ 'shift_jis': 'shift_jis',
|
||||
+ 'euc-kr': 'euc-kr',
|
||||
+ 'ks_c_5601-1987': 'cp949',
|
||||
+ 'iso-2022-kr': 'iso-2022-kr',
|
||||
+ 'johab': 'johab',
|
||||
'gb2132': 'eucgb2312_cn',
|
||||
'big5': 'big5_tw',
|
||||
'utf-8': 'utf-8',
|
|
@ -1,214 +0,0 @@
|
|||
--- Lib/test/test_weakref.py.orig Tue Jul 15 06:37:17 2003
|
||||
+++ Lib/test/test_weakref.py Fri Nov 21 11:39:53 2003
|
||||
@@ -299,6 +299,211 @@
|
||||
self.fail("exception not properly restored")
|
||||
|
||||
|
||||
+ def test_callback_in_cycle_1(self):
|
||||
+ import gc
|
||||
+
|
||||
+ class J(object):
|
||||
+ pass
|
||||
+
|
||||
+ class II(object):
|
||||
+ def acallback(self, ignore):
|
||||
+ self.J
|
||||
+
|
||||
+ I = II()
|
||||
+ I.J = J
|
||||
+ I.wr = weakref.ref(J, I.acallback)
|
||||
+
|
||||
+ # Now J and II are each in a self-cycle (as all new-style class
|
||||
+ # objects are, since their __mro__ points back to them). I holds
|
||||
+ # both a weak reference (I.wr) and a strong reference (I.J) to class
|
||||
+ # J. I is also in a cycle (I.wr points to a weakref that references
|
||||
+ # I.acallback). When we del these three, they all become trash, but
|
||||
+ # the cycles prevent any of them from getting cleaned up immediately.
|
||||
+ # Instead they have to wait for cyclic gc to deduce that they're
|
||||
+ # trash.
|
||||
+ #
|
||||
+ # gc used to call tp_clear on all of them, and the order in which
|
||||
+ # it does that is pretty accidental. The exact order in which we
|
||||
+ # built up these things manages to provoke gc into running tp_clear
|
||||
+ # in just the right order (I last). Calling tp_clear on II leaves
|
||||
+ # behind an insane class object (its __mro__ becomes NULL). Calling
|
||||
+ # tp_clear on J breaks its self-cycle, but J doesn't get deleted
|
||||
+ # just then because of the strong reference from I.J. Calling
|
||||
+ # tp_clear on I starts to clear I's __dict__, and just happens to
|
||||
+ # clear I.J first -- I.wr is still intact. That removes the last
|
||||
+ # reference to J, which triggers the weakref callback. The callback
|
||||
+ # tries to do "self.J", and instances of new-style classes look up
|
||||
+ # attributes ("J") in the class dict first. The class (II) wants to
|
||||
+ # search II.__mro__, but that's NULL. The result was a segfault in
|
||||
+ # a release build, and an assert failure in a debug build.
|
||||
+ del I, J, II
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_2(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # This is just like test_callback_in_cycle_1, except that II is an
|
||||
+ # old-style class. The symptom is different then: an instance of an
|
||||
+ # old-style class looks in its own __dict__ first. 'J' happens to
|
||||
+ # get cleared from I.__dict__ before 'wr', and 'J' was never in II's
|
||||
+ # __dict__, so the attribute isn't found. The difference is that
|
||||
+ # the old-style II doesn't have a NULL __mro__ (it doesn't have any
|
||||
+ # __mro__), so no segfault occurs. Instead it got:
|
||||
+ # test_callback_in_cycle_2 (__main__.ReferencesTestCase) ...
|
||||
+ # Exception exceptions.AttributeError:
|
||||
+ # "II instance has no attribute 'J'" in <bound method II.acallback
|
||||
+ # of <?.II instance at 0x00B9B4B8>> ignored
|
||||
+
|
||||
+ class J(object):
|
||||
+ pass
|
||||
+
|
||||
+ class II:
|
||||
+ def acallback(self, ignore):
|
||||
+ self.J
|
||||
+
|
||||
+ I = II()
|
||||
+ I.J = J
|
||||
+ I.wr = weakref.ref(J, I.acallback)
|
||||
+
|
||||
+ del I, J, II
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_3(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # This one broke the first patch that fixed the last two. In this
|
||||
+ # case, the objects reachable from the callback aren't also reachable
|
||||
+ # from the object (c1) *triggering* the callback: you can get to
|
||||
+ # c1 from c2, but not vice-versa. The result was that c2's __dict__
|
||||
+ # got tp_clear'ed by the time the c2.cb callback got invoked.
|
||||
+
|
||||
+ class C:
|
||||
+ def cb(self, ignore):
|
||||
+ self.me
|
||||
+ self.c1
|
||||
+ self.wr
|
||||
+
|
||||
+ c1, c2 = C(), C()
|
||||
+
|
||||
+ c2.me = c2
|
||||
+ c2.c1 = c1
|
||||
+ c2.wr = weakref.ref(c1, c2.cb)
|
||||
+
|
||||
+ del c1, c2
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_4(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # Like test_callback_in_cycle_3, except c2 and c1 have different
|
||||
+ # classes. c2's class (C) isn't reachable from c1 then, so protecting
|
||||
+ # objects reachable from the dying object (c1) isn't enough to stop
|
||||
+ # c2's class (C) from getting tp_clear'ed before c2.cb is invoked.
|
||||
+ # The result was a segfault (C.__mro__ was NULL when the callback
|
||||
+ # tried to look up self.me).
|
||||
+
|
||||
+ class C(object):
|
||||
+ def cb(self, ignore):
|
||||
+ self.me
|
||||
+ self.c1
|
||||
+ self.wr
|
||||
+
|
||||
+ class D:
|
||||
+ pass
|
||||
+
|
||||
+ c1, c2 = D(), C()
|
||||
+
|
||||
+ c2.me = c2
|
||||
+ c2.c1 = c1
|
||||
+ c2.wr = weakref.ref(c1, c2.cb)
|
||||
+
|
||||
+ del c1, c2, C, D
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_resurrection(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # Do something nasty in a weakref callback: resurrect objects
|
||||
+ # from dead cycles. For this to be attempted, the weakref and
|
||||
+ # its callback must also be part of the cyclic trash (else the
|
||||
+ # objects reachable via the callback couldn't be in cyclic trash
|
||||
+ # to begin with -- the callback would act like an external root).
|
||||
+ # But gc clears trash weakrefs with callbacks early now, which
|
||||
+ # disables the callbacks, so the callbacks shouldn't get called
|
||||
+ # at all (and so nothing actually gets resurrected).
|
||||
+
|
||||
+ alist = []
|
||||
+ class C(object):
|
||||
+ def __init__(self, value):
|
||||
+ self.attribute = value
|
||||
+
|
||||
+ def acallback(self, ignore):
|
||||
+ alist.append(self.c)
|
||||
+
|
||||
+ c1, c2 = C(1), C(2)
|
||||
+ c1.c = c2
|
||||
+ c2.c = c1
|
||||
+ c1.wr = weakref.ref(c2, c1.acallback)
|
||||
+ c2.wr = weakref.ref(c1, c2.acallback)
|
||||
+
|
||||
+ def C_went_away(ignore):
|
||||
+ alist.append("C went away")
|
||||
+ wr = weakref.ref(C, C_went_away)
|
||||
+
|
||||
+ del c1, c2, C # make them all trash
|
||||
+ self.assertEqual(alist, []) # del isn't enough to reclaim anything
|
||||
+
|
||||
+ gc.collect()
|
||||
+ # c1.wr and c2.wr were part of the cyclic trash, so should have
|
||||
+ # been cleared without their callbacks executing. OTOH, the weakref
|
||||
+ # to C is bound to a function local (wr), and wasn't trash, so that
|
||||
+ # callback should have been invoked when C went away.
|
||||
+ self.assertEqual(alist, ["C went away"])
|
||||
+ # The remaining weakref should be dead now (its callback ran).
|
||||
+ self.assertEqual(wr(), None)
|
||||
+
|
||||
+ del alist[:]
|
||||
+ gc.collect()
|
||||
+ self.assertEqual(alist, [])
|
||||
+
|
||||
+ def test_callbacks_on_callback(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # Set up weakref callbacks *on* weakref callbacks.
|
||||
+ alist = []
|
||||
+ def safe_callback(ignore):
|
||||
+ alist.append("safe_callback called")
|
||||
+
|
||||
+ class C(object):
|
||||
+ def cb(self, ignore):
|
||||
+ alist.append("cb called")
|
||||
+
|
||||
+ c, d = C(), C()
|
||||
+ c.other = d
|
||||
+ d.other = c
|
||||
+ callback = c.cb
|
||||
+ c.wr = weakref.ref(d, callback) # this won't trigger
|
||||
+ d.wr = weakref.ref(callback, d.cb) # ditto
|
||||
+ external_wr = weakref.ref(callback, safe_callback) # but this will
|
||||
+ self.assert_(external_wr() is callback)
|
||||
+
|
||||
+ # The weakrefs attached to c and d should get cleared, so that
|
||||
+ # C.cb is never called. But external_wr isn't part of the cyclic
|
||||
+ # trash, and no cyclic trash is reachable from it, so safe_callback
|
||||
+ # should get invoked when the bound method object callback (c.cb)
|
||||
+ # -- which is itself a callback, and also part of the cyclic trash --
|
||||
+ # gets reclaimed at the end of gc.
|
||||
+
|
||||
+ del callback, c, d, C
|
||||
+ self.assertEqual(alist, []) # del isn't enough to clean up cycles
|
||||
+ gc.collect()
|
||||
+ self.assertEqual(alist, ["safe_callback called"])
|
||||
+ self.assertEqual(external_wr(), None)
|
||||
+
|
||||
+ del alist[:]
|
||||
+ gc.collect()
|
||||
+ self.assertEqual(alist, [])
|
||||
+
|
||||
class Object:
|
||||
def __init__(self, arg):
|
||||
self.arg = arg
|
|
@ -1,19 +0,0 @@
|
|||
--- Modules/_sre.c 26 Jun 2003 14:41:08 -0000 2.99
|
||||
+++ Modules/_sre.c 27 Sep 2003 18:13:15 -0000
|
||||
@@ -71,9 +71,14 @@
|
||||
Win64 (MS_WIN64), Linux64 (__LP64__), Monterey (64-bit AIX) (_LP64) */
|
||||
/* FIXME: maybe the limit should be 40000 / sizeof(void*) ? */
|
||||
#define USE_RECURSION_LIMIT 7500
|
||||
-#else
|
||||
|
||||
-#if defined(__GNUC__) && defined(WITH_THREAD) && defined(__FreeBSD__)
|
||||
+#elif defined(__FreeBSD__)
|
||||
+/* FreeBSD/amd64 and /sparc64 requires even smaller limit */
|
||||
+#if defined(__amd64__)
|
||||
+#define USE_RECURSION_LIMIT 6000
|
||||
+#elif defined(__sparc64__)
|
||||
+#define USE_RECURSION_LIMIT 3000
|
||||
+#elif defined(__GNUC__) && defined(WITH_THREAD)
|
||||
/* the pthreads library on FreeBSD has a fixed 1MB stack size for the
|
||||
* initial (or "primary") thread, which is insufficient for the default
|
||||
* recursion limit. gcc 3.x at the default optimisation
|
|
@ -1,196 +0,0 @@
|
|||
--- Modules/gcmodule.c.orig Fri Apr 18 02:29:21 2003
|
||||
+++ Modules/gcmodule.c Fri Nov 21 11:39:52 2003
|
||||
@@ -377,13 +377,17 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
-/* Move the objects in unreachable with __del__ methods into finalizers.
|
||||
- * The objects remaining in unreachable do not have __del__ methods, and
|
||||
- * gc_refs remains GC_TENTATIVELY_UNREACHABLE for them. The objects
|
||||
- * moved into finalizers have gc_refs changed to GC_REACHABLE.
|
||||
+/* Move the objects in unreachable with __del__ methods into finalizers,
|
||||
+ * and weakrefs with callbacks into wr_callbacks.
|
||||
+ * The objects remaining in unreachable do not have __del__ methods, and are
|
||||
+ * not weakrefs with callbacks.
|
||||
+ * The objects moved have gc_refs changed to GC_REACHABLE; the objects
|
||||
+ * remaining in unreachable are left at GC_TENTATIVELY_UNREACHABLE.
|
||||
*/
|
||||
static void
|
||||
-move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
|
||||
+move_troublemakers(PyGC_Head *unreachable,
|
||||
+ PyGC_Head *finalizers,
|
||||
+ PyGC_Head *wr_callbacks)
|
||||
{
|
||||
PyGC_Head *gc = unreachable->gc.gc_next;
|
||||
|
||||
@@ -398,6 +402,12 @@
|
||||
gc_list_append(gc, finalizers);
|
||||
gc->gc.gc_refs = GC_REACHABLE;
|
||||
}
|
||||
+ else if (PyWeakref_Check(op) &&
|
||||
+ ((PyWeakReference *)op)->wr_callback) {
|
||||
+ gc_list_remove(gc);
|
||||
+ gc_list_append(gc, wr_callbacks);
|
||||
+ gc->gc.gc_refs = GC_REACHABLE;
|
||||
+ }
|
||||
gc = next;
|
||||
}
|
||||
}
|
||||
@@ -434,6 +444,93 @@
|
||||
}
|
||||
}
|
||||
|
||||
+/* Clear all trash weakrefs with callbacks. This clears weakrefs first,
|
||||
+ * which has the happy result of disabling the callbacks without executing
|
||||
+ * them. A nasty technical complication: a weakref callback can itself be
|
||||
+ * the target of a weakref, in which case decrefing the callback can cause
|
||||
+ * another callback to trigger. But we can't allow arbitrary Python code to
|
||||
+ * get executed at this point (the callback on the callback may try to muck
|
||||
+ * with other cyclic trash we're trying to collect, even resurrecting it
|
||||
+ * while we're in the middle of doing tp_clear() on the trash).
|
||||
+ *
|
||||
+ * The private _PyWeakref_ClearRef() function exists so that we can clear
|
||||
+ * the reference in a weakref without triggering a callback on the callback.
|
||||
+ *
|
||||
+ * We have to save the callback objects and decref them later. But we can't
|
||||
+ * allocate new memory to save them (if we can't get new memory, we're dead).
|
||||
+ * So we grab a new reference on the clear'ed weakref, which prevents the
|
||||
+ * rest of gc from reclaiming it. _PyWeakref_ClearRef() leaves the
|
||||
+ * weakref's wr_callback member intact.
|
||||
+ *
|
||||
+ * In the end, then, wr_callbacks consists of cleared weakrefs that are
|
||||
+ * immune from collection. Near the end of gc, after collecting all the
|
||||
+ * cyclic trash, we call release_weakrefs(). That releases our references
|
||||
+ * to the cleared weakrefs, which in turn may trigger callbacks on their
|
||||
+ * callbacks.
|
||||
+ */
|
||||
+static void
|
||||
+clear_weakrefs(PyGC_Head *wr_callbacks)
|
||||
+{
|
||||
+ PyGC_Head *gc = wr_callbacks->gc.gc_next;
|
||||
+
|
||||
+ for (; gc != wr_callbacks; gc = gc->gc.gc_next) {
|
||||
+ PyObject *op = FROM_GC(gc);
|
||||
+ PyWeakReference *wr;
|
||||
+
|
||||
+ assert(IS_REACHABLE(op));
|
||||
+ assert(PyWeakref_Check(op));
|
||||
+ wr = (PyWeakReference *)op;
|
||||
+ assert(wr->wr_callback != NULL);
|
||||
+ Py_INCREF(op);
|
||||
+ _PyWeakref_ClearRef(wr);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Called near the end of gc. This gives up the references we own to
|
||||
+ * cleared weakrefs, allowing them to get collected, and in turn decref'ing
|
||||
+ * their callbacks.
|
||||
+ *
|
||||
+ * If a callback object is itself the target of a weakref callback,
|
||||
+ * decref'ing the callback object may trigger that other callback. If
|
||||
+ * that other callback was part of the cyclic trash in this generation,
|
||||
+ * that won't happen, since we cleared *all* trash-weakref callbacks near
|
||||
+ * the start of gc. If that other callback was not part of the cyclic trash
|
||||
+ * in this generation, then it acted like an external root to this round
|
||||
+ * of gc, so all the objects reachable from that callback are still alive.
|
||||
+ *
|
||||
+ * Giving up the references to the weakref objects will probably make
|
||||
+ * them go away too. However, if a weakref is reachable from finalizers,
|
||||
+ * it won't go away. We move it to the old generation then. Since a
|
||||
+ * weakref object doesn't have a finalizer, that's the right thing to do (it
|
||||
+ * doesn't belong in gc.garbage).
|
||||
+ *
|
||||
+ * We return the number of weakref objects freed (those not appended to old).
|
||||
+ */
|
||||
+static int
|
||||
+release_weakrefs(PyGC_Head *wr_callbacks, PyGC_Head *old)
|
||||
+{
|
||||
+ int num_freed = 0;
|
||||
+
|
||||
+ while (! gc_list_is_empty(wr_callbacks)) {
|
||||
+ PyGC_Head *gc = wr_callbacks->gc.gc_next;
|
||||
+ PyObject *op = FROM_GC(gc);
|
||||
+ PyWeakReference *wr = (PyWeakReference *)op;
|
||||
+
|
||||
+ assert(IS_REACHABLE(op));
|
||||
+ assert(PyWeakref_Check(op));
|
||||
+ assert(wr->wr_callback != NULL);
|
||||
+ Py_DECREF(op);
|
||||
+ if (wr_callbacks->gc.gc_next == gc) {
|
||||
+ /* object is still alive -- move it */
|
||||
+ gc_list_remove(gc);
|
||||
+ gc_list_append(gc, old);
|
||||
+ }
|
||||
+ else
|
||||
+ ++num_freed;
|
||||
+ }
|
||||
+ return num_freed;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
debug_instance(char *msg, PyInstanceObject *inst)
|
||||
{
|
||||
@@ -535,8 +632,9 @@
|
||||
long n = 0; /* # unreachable objects that couldn't be collected */
|
||||
PyGC_Head *young; /* the generation we are examining */
|
||||
PyGC_Head *old; /* next older generation */
|
||||
- PyGC_Head unreachable;
|
||||
- PyGC_Head finalizers;
|
||||
+ PyGC_Head unreachable; /* non-problematic unreachable trash */
|
||||
+ PyGC_Head finalizers; /* objects with, & reachable from, __del__ */
|
||||
+ PyGC_Head wr_callbacks; /* weakrefs with callbacks */
|
||||
PyGC_Head *gc;
|
||||
|
||||
if (delstr == NULL) {
|
||||
@@ -597,20 +695,33 @@
|
||||
/* All objects in unreachable are trash, but objects reachable from
|
||||
* finalizers can't safely be deleted. Python programmers should take
|
||||
* care not to create such things. For Python, finalizers means
|
||||
- * instance objects with __del__ methods.
|
||||
+ * instance objects with __del__ methods. Weakrefs with callbacks
|
||||
+ * can call arbitrary Python code, so those are special-cased too.
|
||||
*
|
||||
- * Move unreachable objects with finalizers into a different list.
|
||||
+ * Move unreachable objects with finalizers, and weakrefs with
|
||||
+ * callbacks, into different lists.
|
||||
*/
|
||||
gc_list_init(&finalizers);
|
||||
- move_finalizers(&unreachable, &finalizers);
|
||||
+ gc_list_init(&wr_callbacks);
|
||||
+ move_troublemakers(&unreachable, &finalizers, &wr_callbacks);
|
||||
+ /* Clear the trash weakrefs with callbacks. This prevents their
|
||||
+ * callbacks from getting invoked (when a weakref goes away, so does
|
||||
+ * its callback).
|
||||
+ * We do this even if the weakrefs are reachable from finalizers.
|
||||
+ * If we didn't, breaking cycles in unreachable later could trigger
|
||||
+ * deallocation of objects in finalizers, which could in turn
|
||||
+ * cause callbacks to trigger. This may not be ideal behavior.
|
||||
+ */
|
||||
+ clear_weakrefs(&wr_callbacks);
|
||||
/* finalizers contains the unreachable objects with a finalizer;
|
||||
- * unreachable objects reachable only *from* those are also
|
||||
- * uncollectable, and we move those into the finalizers list too.
|
||||
+ * unreachable objects reachable *from* those are also uncollectable,
|
||||
+ * and we move those into the finalizers list too.
|
||||
*/
|
||||
move_finalizer_reachable(&finalizers);
|
||||
|
||||
/* Collect statistics on collectable objects found and print
|
||||
- * debugging information. */
|
||||
+ * debugging information.
|
||||
+ */
|
||||
for (gc = unreachable.gc.gc_next; gc != &unreachable;
|
||||
gc = gc->gc.gc_next) {
|
||||
m++;
|
||||
@@ -623,6 +734,11 @@
|
||||
* in finalizers to be freed.
|
||||
*/
|
||||
delete_garbage(&unreachable, old);
|
||||
+
|
||||
+ /* Now that we're done analyzing stuff and breaking cycles, let
|
||||
+ * delayed weakref callbacks run.
|
||||
+ */
|
||||
+ m += release_weakrefs(&wr_callbacks, old);
|
||||
|
||||
/* Collect statistics on uncollectable objects found and print
|
||||
* debugging information. */
|
|
@ -1,66 +0,0 @@
|
|||
--- Objects/weakrefobject.c.orig Tue Jul 15 06:46:23 2003
|
||||
+++ Objects/weakrefobject.c Fri Nov 21 11:39:53 2003
|
||||
@@ -53,17 +53,43 @@
|
||||
if (*list == self)
|
||||
*list = self->wr_next;
|
||||
self->wr_object = Py_None;
|
||||
- self->wr_callback = NULL;
|
||||
if (self->wr_prev != NULL)
|
||||
self->wr_prev->wr_next = self->wr_next;
|
||||
if (self->wr_next != NULL)
|
||||
self->wr_next->wr_prev = self->wr_prev;
|
||||
self->wr_prev = NULL;
|
||||
self->wr_next = NULL;
|
||||
- Py_XDECREF(callback);
|
||||
+ }
|
||||
+ if (callback != NULL) {
|
||||
+ Py_DECREF(callback);
|
||||
+ self->wr_callback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
|
||||
+ * the callback intact and uncalled. It must be possible to call self's
|
||||
+ * tp_dealloc() after calling this, so self has to be left in a sane enough
|
||||
+ * state for that to work. We expect tp_dealloc to decref the callback
|
||||
+ * then. The reason for not letting clear_weakref() decref the callback
|
||||
+ * right now is that if the callback goes away, that may in turn trigger
|
||||
+ * another callback (if a weak reference to the callback exists) -- running
|
||||
+ * arbitrary Python code in the middle of gc is a disaster. The convolution
|
||||
+ * here allows gc to delay triggering such callbacks until the world is in
|
||||
+ * a sane state again.
|
||||
+ */
|
||||
+void
|
||||
+_PyWeakref_ClearRef(PyWeakReference *self)
|
||||
+{
|
||||
+ PyObject *callback;
|
||||
+
|
||||
+ assert(self != NULL);
|
||||
+ assert(PyWeakref_Check(self));
|
||||
+ /* Preserve and restore the callback around clear_weakref. */
|
||||
+ callback = self->wr_callback;
|
||||
+ self->wr_callback = NULL;
|
||||
+ clear_weakref(self);
|
||||
+ self->wr_callback = callback;
|
||||
+}
|
||||
|
||||
static void
|
||||
weakref_dealloc(PyWeakReference *self)
|
||||
@@ -117,7 +143,7 @@
|
||||
self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
|
||||
return self->hash;
|
||||
}
|
||||
-
|
||||
+
|
||||
|
||||
static PyObject *
|
||||
weakref_repr(PyWeakReference *self)
|
||||
@@ -324,7 +350,7 @@
|
||||
WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
|
||||
WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
|
||||
|
||||
-static int
|
||||
+static int
|
||||
proxy_nonzero(PyWeakReference *proxy)
|
||||
{
|
||||
PyObject *o = PyWeakref_GET_OBJECT(proxy);
|
14
lang/python/files/patch-Python::ceval.c
Normal file
14
lang/python/files/patch-Python::ceval.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
--- Python/ceval.c.orig Sat Dec 20 15:13:53 2003
|
||||
+++ Python/ceval.c Sat Dec 20 15:15:46 2003
|
||||
@@ -496,7 +496,10 @@
|
||||
|
||||
/* The interpreter's recursion limit */
|
||||
|
||||
-static int recursion_limit = 1000;
|
||||
+#ifndef PYTHON_DEFAULT_RECURSION_LIMIT
|
||||
+#define PYTHON_DEFAULT_RECURSION_LIMIT 1000
|
||||
+#endif
|
||||
+static int recursion_limit = PYTHON_DEFAULT_RECURSION_LIMIT;
|
||||
|
||||
int
|
||||
Py_GetRecursionLimit(void)
|
|
@ -6,8 +6,7 @@
|
|||
#
|
||||
|
||||
PORTNAME= python
|
||||
PORTVERSION= 2.3.2
|
||||
PORTREVISION= 3
|
||||
PORTVERSION= 2.3.3
|
||||
CATEGORIES= lang python ipv6
|
||||
MASTER_SITES= ${PYTHON_MASTER_SITES}
|
||||
MASTER_SITE_SUBDIR= ${PYTHON_MASTER_SITE_SUBDIR}
|
||||
|
@ -83,6 +82,9 @@ PLIST_SUB+= 32BIT_ONLY="@comment "
|
|||
.else
|
||||
PLIST_SUB+= 32BIT_ONLY=""
|
||||
.endif
|
||||
.if ${ARCH} == sparc64
|
||||
CFLAGS+= -DPYTHON_DEFAULT_RECURSION_LIMIT=900
|
||||
.endif
|
||||
|
||||
.if ${OSVERSION} < 400000
|
||||
LIB_DEPENDS+= ncurses.5:${PORTSDIR}/devel/ncurses
|
||||
|
|
|
@ -13,4 +13,5 @@ MD5 (python/Python-2.2.3.tgz) = 169f89f318e252dac0c54dd1b165d229
|
|||
MD5 (python/Python-2.3.tgz) = 595620a4769073a812e353597585c4e8
|
||||
MD5 (python/Python-2.3.1.tgz) = a3dcbe1c7f173c8e3c7cce28495016ae
|
||||
MD5 (python/Python-2.3.2.tgz) = f54d7a529d444994b4b33429bbb45479
|
||||
MD5 (python/Python-2.3.3.tgz) = 4d16732b1cfccc0ed250956d41463c61
|
||||
MD5 (python/Python-2.4.a0.20031022.tgz) = 79581105c218886dd9dc382a84c64043
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
--- Include/weakrefobject.h.orig Mon Aug 12 16:21:58 2002
|
||||
+++ Include/weakrefobject.h Fri Nov 21 11:39:53 2003
|
||||
@@ -39,6 +39,8 @@
|
||||
|
||||
PyAPI_FUNC(long) _PyWeakref_GetWeakrefCount(PyWeakReference *head);
|
||||
|
||||
+PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self);
|
||||
+
|
||||
#define PyWeakref_GET_OBJECT(ref) (((PyWeakReference *)(ref))->wr_object)
|
||||
|
||||
|
23
lang/python23/files/patch-Lib::email::Charset.py
Normal file
23
lang/python23/files/patch-Lib::email::Charset.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
--- Lib/email/Charset.py.orig Sat Dec 20 15:16:29 2003
|
||||
+++ Lib/email/Charset.py Sat Dec 20 15:16:54 2003
|
||||
@@ -99,13 +99,13 @@
|
||||
# of stability and useability.
|
||||
|
||||
CODEC_MAP = {
|
||||
- 'euc-jp': 'japanese.euc-jp',
|
||||
- 'iso-2022-jp': 'japanese.iso-2022-jp',
|
||||
- 'shift_jis': 'japanese.shift_jis',
|
||||
- 'euc-kr': 'korean.euc-kr',
|
||||
- 'ks_c_5601-1987': 'korean.cp949',
|
||||
- 'iso-2022-kr': 'korean.iso-2022-kr',
|
||||
- 'johab': 'korean.johab',
|
||||
+ 'euc-jp': 'euc-jp',
|
||||
+ 'iso-2022-jp': 'iso-2022-jp',
|
||||
+ 'shift_jis': 'shift_jis',
|
||||
+ 'euc-kr': 'euc-kr',
|
||||
+ 'ks_c_5601-1987': 'cp949',
|
||||
+ 'iso-2022-kr': 'iso-2022-kr',
|
||||
+ 'johab': 'johab',
|
||||
'gb2132': 'eucgb2312_cn',
|
||||
'big5': 'big5_tw',
|
||||
'utf-8': 'utf-8',
|
|
@ -1,214 +0,0 @@
|
|||
--- Lib/test/test_weakref.py.orig Tue Jul 15 06:37:17 2003
|
||||
+++ Lib/test/test_weakref.py Fri Nov 21 11:39:53 2003
|
||||
@@ -299,6 +299,211 @@
|
||||
self.fail("exception not properly restored")
|
||||
|
||||
|
||||
+ def test_callback_in_cycle_1(self):
|
||||
+ import gc
|
||||
+
|
||||
+ class J(object):
|
||||
+ pass
|
||||
+
|
||||
+ class II(object):
|
||||
+ def acallback(self, ignore):
|
||||
+ self.J
|
||||
+
|
||||
+ I = II()
|
||||
+ I.J = J
|
||||
+ I.wr = weakref.ref(J, I.acallback)
|
||||
+
|
||||
+ # Now J and II are each in a self-cycle (as all new-style class
|
||||
+ # objects are, since their __mro__ points back to them). I holds
|
||||
+ # both a weak reference (I.wr) and a strong reference (I.J) to class
|
||||
+ # J. I is also in a cycle (I.wr points to a weakref that references
|
||||
+ # I.acallback). When we del these three, they all become trash, but
|
||||
+ # the cycles prevent any of them from getting cleaned up immediately.
|
||||
+ # Instead they have to wait for cyclic gc to deduce that they're
|
||||
+ # trash.
|
||||
+ #
|
||||
+ # gc used to call tp_clear on all of them, and the order in which
|
||||
+ # it does that is pretty accidental. The exact order in which we
|
||||
+ # built up these things manages to provoke gc into running tp_clear
|
||||
+ # in just the right order (I last). Calling tp_clear on II leaves
|
||||
+ # behind an insane class object (its __mro__ becomes NULL). Calling
|
||||
+ # tp_clear on J breaks its self-cycle, but J doesn't get deleted
|
||||
+ # just then because of the strong reference from I.J. Calling
|
||||
+ # tp_clear on I starts to clear I's __dict__, and just happens to
|
||||
+ # clear I.J first -- I.wr is still intact. That removes the last
|
||||
+ # reference to J, which triggers the weakref callback. The callback
|
||||
+ # tries to do "self.J", and instances of new-style classes look up
|
||||
+ # attributes ("J") in the class dict first. The class (II) wants to
|
||||
+ # search II.__mro__, but that's NULL. The result was a segfault in
|
||||
+ # a release build, and an assert failure in a debug build.
|
||||
+ del I, J, II
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_2(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # This is just like test_callback_in_cycle_1, except that II is an
|
||||
+ # old-style class. The symptom is different then: an instance of an
|
||||
+ # old-style class looks in its own __dict__ first. 'J' happens to
|
||||
+ # get cleared from I.__dict__ before 'wr', and 'J' was never in II's
|
||||
+ # __dict__, so the attribute isn't found. The difference is that
|
||||
+ # the old-style II doesn't have a NULL __mro__ (it doesn't have any
|
||||
+ # __mro__), so no segfault occurs. Instead it got:
|
||||
+ # test_callback_in_cycle_2 (__main__.ReferencesTestCase) ...
|
||||
+ # Exception exceptions.AttributeError:
|
||||
+ # "II instance has no attribute 'J'" in <bound method II.acallback
|
||||
+ # of <?.II instance at 0x00B9B4B8>> ignored
|
||||
+
|
||||
+ class J(object):
|
||||
+ pass
|
||||
+
|
||||
+ class II:
|
||||
+ def acallback(self, ignore):
|
||||
+ self.J
|
||||
+
|
||||
+ I = II()
|
||||
+ I.J = J
|
||||
+ I.wr = weakref.ref(J, I.acallback)
|
||||
+
|
||||
+ del I, J, II
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_3(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # This one broke the first patch that fixed the last two. In this
|
||||
+ # case, the objects reachable from the callback aren't also reachable
|
||||
+ # from the object (c1) *triggering* the callback: you can get to
|
||||
+ # c1 from c2, but not vice-versa. The result was that c2's __dict__
|
||||
+ # got tp_clear'ed by the time the c2.cb callback got invoked.
|
||||
+
|
||||
+ class C:
|
||||
+ def cb(self, ignore):
|
||||
+ self.me
|
||||
+ self.c1
|
||||
+ self.wr
|
||||
+
|
||||
+ c1, c2 = C(), C()
|
||||
+
|
||||
+ c2.me = c2
|
||||
+ c2.c1 = c1
|
||||
+ c2.wr = weakref.ref(c1, c2.cb)
|
||||
+
|
||||
+ del c1, c2
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_4(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # Like test_callback_in_cycle_3, except c2 and c1 have different
|
||||
+ # classes. c2's class (C) isn't reachable from c1 then, so protecting
|
||||
+ # objects reachable from the dying object (c1) isn't enough to stop
|
||||
+ # c2's class (C) from getting tp_clear'ed before c2.cb is invoked.
|
||||
+ # The result was a segfault (C.__mro__ was NULL when the callback
|
||||
+ # tried to look up self.me).
|
||||
+
|
||||
+ class C(object):
|
||||
+ def cb(self, ignore):
|
||||
+ self.me
|
||||
+ self.c1
|
||||
+ self.wr
|
||||
+
|
||||
+ class D:
|
||||
+ pass
|
||||
+
|
||||
+ c1, c2 = D(), C()
|
||||
+
|
||||
+ c2.me = c2
|
||||
+ c2.c1 = c1
|
||||
+ c2.wr = weakref.ref(c1, c2.cb)
|
||||
+
|
||||
+ del c1, c2, C, D
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_resurrection(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # Do something nasty in a weakref callback: resurrect objects
|
||||
+ # from dead cycles. For this to be attempted, the weakref and
|
||||
+ # its callback must also be part of the cyclic trash (else the
|
||||
+ # objects reachable via the callback couldn't be in cyclic trash
|
||||
+ # to begin with -- the callback would act like an external root).
|
||||
+ # But gc clears trash weakrefs with callbacks early now, which
|
||||
+ # disables the callbacks, so the callbacks shouldn't get called
|
||||
+ # at all (and so nothing actually gets resurrected).
|
||||
+
|
||||
+ alist = []
|
||||
+ class C(object):
|
||||
+ def __init__(self, value):
|
||||
+ self.attribute = value
|
||||
+
|
||||
+ def acallback(self, ignore):
|
||||
+ alist.append(self.c)
|
||||
+
|
||||
+ c1, c2 = C(1), C(2)
|
||||
+ c1.c = c2
|
||||
+ c2.c = c1
|
||||
+ c1.wr = weakref.ref(c2, c1.acallback)
|
||||
+ c2.wr = weakref.ref(c1, c2.acallback)
|
||||
+
|
||||
+ def C_went_away(ignore):
|
||||
+ alist.append("C went away")
|
||||
+ wr = weakref.ref(C, C_went_away)
|
||||
+
|
||||
+ del c1, c2, C # make them all trash
|
||||
+ self.assertEqual(alist, []) # del isn't enough to reclaim anything
|
||||
+
|
||||
+ gc.collect()
|
||||
+ # c1.wr and c2.wr were part of the cyclic trash, so should have
|
||||
+ # been cleared without their callbacks executing. OTOH, the weakref
|
||||
+ # to C is bound to a function local (wr), and wasn't trash, so that
|
||||
+ # callback should have been invoked when C went away.
|
||||
+ self.assertEqual(alist, ["C went away"])
|
||||
+ # The remaining weakref should be dead now (its callback ran).
|
||||
+ self.assertEqual(wr(), None)
|
||||
+
|
||||
+ del alist[:]
|
||||
+ gc.collect()
|
||||
+ self.assertEqual(alist, [])
|
||||
+
|
||||
+ def test_callbacks_on_callback(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # Set up weakref callbacks *on* weakref callbacks.
|
||||
+ alist = []
|
||||
+ def safe_callback(ignore):
|
||||
+ alist.append("safe_callback called")
|
||||
+
|
||||
+ class C(object):
|
||||
+ def cb(self, ignore):
|
||||
+ alist.append("cb called")
|
||||
+
|
||||
+ c, d = C(), C()
|
||||
+ c.other = d
|
||||
+ d.other = c
|
||||
+ callback = c.cb
|
||||
+ c.wr = weakref.ref(d, callback) # this won't trigger
|
||||
+ d.wr = weakref.ref(callback, d.cb) # ditto
|
||||
+ external_wr = weakref.ref(callback, safe_callback) # but this will
|
||||
+ self.assert_(external_wr() is callback)
|
||||
+
|
||||
+ # The weakrefs attached to c and d should get cleared, so that
|
||||
+ # C.cb is never called. But external_wr isn't part of the cyclic
|
||||
+ # trash, and no cyclic trash is reachable from it, so safe_callback
|
||||
+ # should get invoked when the bound method object callback (c.cb)
|
||||
+ # -- which is itself a callback, and also part of the cyclic trash --
|
||||
+ # gets reclaimed at the end of gc.
|
||||
+
|
||||
+ del callback, c, d, C
|
||||
+ self.assertEqual(alist, []) # del isn't enough to clean up cycles
|
||||
+ gc.collect()
|
||||
+ self.assertEqual(alist, ["safe_callback called"])
|
||||
+ self.assertEqual(external_wr(), None)
|
||||
+
|
||||
+ del alist[:]
|
||||
+ gc.collect()
|
||||
+ self.assertEqual(alist, [])
|
||||
+
|
||||
class Object:
|
||||
def __init__(self, arg):
|
||||
self.arg = arg
|
|
@ -1,19 +0,0 @@
|
|||
--- Modules/_sre.c 26 Jun 2003 14:41:08 -0000 2.99
|
||||
+++ Modules/_sre.c 27 Sep 2003 18:13:15 -0000
|
||||
@@ -71,9 +71,14 @@
|
||||
Win64 (MS_WIN64), Linux64 (__LP64__), Monterey (64-bit AIX) (_LP64) */
|
||||
/* FIXME: maybe the limit should be 40000 / sizeof(void*) ? */
|
||||
#define USE_RECURSION_LIMIT 7500
|
||||
-#else
|
||||
|
||||
-#if defined(__GNUC__) && defined(WITH_THREAD) && defined(__FreeBSD__)
|
||||
+#elif defined(__FreeBSD__)
|
||||
+/* FreeBSD/amd64 and /sparc64 requires even smaller limit */
|
||||
+#if defined(__amd64__)
|
||||
+#define USE_RECURSION_LIMIT 6000
|
||||
+#elif defined(__sparc64__)
|
||||
+#define USE_RECURSION_LIMIT 3000
|
||||
+#elif defined(__GNUC__) && defined(WITH_THREAD)
|
||||
/* the pthreads library on FreeBSD has a fixed 1MB stack size for the
|
||||
* initial (or "primary") thread, which is insufficient for the default
|
||||
* recursion limit. gcc 3.x at the default optimisation
|
|
@ -1,196 +0,0 @@
|
|||
--- Modules/gcmodule.c.orig Fri Apr 18 02:29:21 2003
|
||||
+++ Modules/gcmodule.c Fri Nov 21 11:39:52 2003
|
||||
@@ -377,13 +377,17 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
-/* Move the objects in unreachable with __del__ methods into finalizers.
|
||||
- * The objects remaining in unreachable do not have __del__ methods, and
|
||||
- * gc_refs remains GC_TENTATIVELY_UNREACHABLE for them. The objects
|
||||
- * moved into finalizers have gc_refs changed to GC_REACHABLE.
|
||||
+/* Move the objects in unreachable with __del__ methods into finalizers,
|
||||
+ * and weakrefs with callbacks into wr_callbacks.
|
||||
+ * The objects remaining in unreachable do not have __del__ methods, and are
|
||||
+ * not weakrefs with callbacks.
|
||||
+ * The objects moved have gc_refs changed to GC_REACHABLE; the objects
|
||||
+ * remaining in unreachable are left at GC_TENTATIVELY_UNREACHABLE.
|
||||
*/
|
||||
static void
|
||||
-move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
|
||||
+move_troublemakers(PyGC_Head *unreachable,
|
||||
+ PyGC_Head *finalizers,
|
||||
+ PyGC_Head *wr_callbacks)
|
||||
{
|
||||
PyGC_Head *gc = unreachable->gc.gc_next;
|
||||
|
||||
@@ -398,6 +402,12 @@
|
||||
gc_list_append(gc, finalizers);
|
||||
gc->gc.gc_refs = GC_REACHABLE;
|
||||
}
|
||||
+ else if (PyWeakref_Check(op) &&
|
||||
+ ((PyWeakReference *)op)->wr_callback) {
|
||||
+ gc_list_remove(gc);
|
||||
+ gc_list_append(gc, wr_callbacks);
|
||||
+ gc->gc.gc_refs = GC_REACHABLE;
|
||||
+ }
|
||||
gc = next;
|
||||
}
|
||||
}
|
||||
@@ -434,6 +444,93 @@
|
||||
}
|
||||
}
|
||||
|
||||
+/* Clear all trash weakrefs with callbacks. This clears weakrefs first,
|
||||
+ * which has the happy result of disabling the callbacks without executing
|
||||
+ * them. A nasty technical complication: a weakref callback can itself be
|
||||
+ * the target of a weakref, in which case decrefing the callback can cause
|
||||
+ * another callback to trigger. But we can't allow arbitrary Python code to
|
||||
+ * get executed at this point (the callback on the callback may try to muck
|
||||
+ * with other cyclic trash we're trying to collect, even resurrecting it
|
||||
+ * while we're in the middle of doing tp_clear() on the trash).
|
||||
+ *
|
||||
+ * The private _PyWeakref_ClearRef() function exists so that we can clear
|
||||
+ * the reference in a weakref without triggering a callback on the callback.
|
||||
+ *
|
||||
+ * We have to save the callback objects and decref them later. But we can't
|
||||
+ * allocate new memory to save them (if we can't get new memory, we're dead).
|
||||
+ * So we grab a new reference on the clear'ed weakref, which prevents the
|
||||
+ * rest of gc from reclaiming it. _PyWeakref_ClearRef() leaves the
|
||||
+ * weakref's wr_callback member intact.
|
||||
+ *
|
||||
+ * In the end, then, wr_callbacks consists of cleared weakrefs that are
|
||||
+ * immune from collection. Near the end of gc, after collecting all the
|
||||
+ * cyclic trash, we call release_weakrefs(). That releases our references
|
||||
+ * to the cleared weakrefs, which in turn may trigger callbacks on their
|
||||
+ * callbacks.
|
||||
+ */
|
||||
+static void
|
||||
+clear_weakrefs(PyGC_Head *wr_callbacks)
|
||||
+{
|
||||
+ PyGC_Head *gc = wr_callbacks->gc.gc_next;
|
||||
+
|
||||
+ for (; gc != wr_callbacks; gc = gc->gc.gc_next) {
|
||||
+ PyObject *op = FROM_GC(gc);
|
||||
+ PyWeakReference *wr;
|
||||
+
|
||||
+ assert(IS_REACHABLE(op));
|
||||
+ assert(PyWeakref_Check(op));
|
||||
+ wr = (PyWeakReference *)op;
|
||||
+ assert(wr->wr_callback != NULL);
|
||||
+ Py_INCREF(op);
|
||||
+ _PyWeakref_ClearRef(wr);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Called near the end of gc. This gives up the references we own to
|
||||
+ * cleared weakrefs, allowing them to get collected, and in turn decref'ing
|
||||
+ * their callbacks.
|
||||
+ *
|
||||
+ * If a callback object is itself the target of a weakref callback,
|
||||
+ * decref'ing the callback object may trigger that other callback. If
|
||||
+ * that other callback was part of the cyclic trash in this generation,
|
||||
+ * that won't happen, since we cleared *all* trash-weakref callbacks near
|
||||
+ * the start of gc. If that other callback was not part of the cyclic trash
|
||||
+ * in this generation, then it acted like an external root to this round
|
||||
+ * of gc, so all the objects reachable from that callback are still alive.
|
||||
+ *
|
||||
+ * Giving up the references to the weakref objects will probably make
|
||||
+ * them go away too. However, if a weakref is reachable from finalizers,
|
||||
+ * it won't go away. We move it to the old generation then. Since a
|
||||
+ * weakref object doesn't have a finalizer, that's the right thing to do (it
|
||||
+ * doesn't belong in gc.garbage).
|
||||
+ *
|
||||
+ * We return the number of weakref objects freed (those not appended to old).
|
||||
+ */
|
||||
+static int
|
||||
+release_weakrefs(PyGC_Head *wr_callbacks, PyGC_Head *old)
|
||||
+{
|
||||
+ int num_freed = 0;
|
||||
+
|
||||
+ while (! gc_list_is_empty(wr_callbacks)) {
|
||||
+ PyGC_Head *gc = wr_callbacks->gc.gc_next;
|
||||
+ PyObject *op = FROM_GC(gc);
|
||||
+ PyWeakReference *wr = (PyWeakReference *)op;
|
||||
+
|
||||
+ assert(IS_REACHABLE(op));
|
||||
+ assert(PyWeakref_Check(op));
|
||||
+ assert(wr->wr_callback != NULL);
|
||||
+ Py_DECREF(op);
|
||||
+ if (wr_callbacks->gc.gc_next == gc) {
|
||||
+ /* object is still alive -- move it */
|
||||
+ gc_list_remove(gc);
|
||||
+ gc_list_append(gc, old);
|
||||
+ }
|
||||
+ else
|
||||
+ ++num_freed;
|
||||
+ }
|
||||
+ return num_freed;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
debug_instance(char *msg, PyInstanceObject *inst)
|
||||
{
|
||||
@@ -535,8 +632,9 @@
|
||||
long n = 0; /* # unreachable objects that couldn't be collected */
|
||||
PyGC_Head *young; /* the generation we are examining */
|
||||
PyGC_Head *old; /* next older generation */
|
||||
- PyGC_Head unreachable;
|
||||
- PyGC_Head finalizers;
|
||||
+ PyGC_Head unreachable; /* non-problematic unreachable trash */
|
||||
+ PyGC_Head finalizers; /* objects with, & reachable from, __del__ */
|
||||
+ PyGC_Head wr_callbacks; /* weakrefs with callbacks */
|
||||
PyGC_Head *gc;
|
||||
|
||||
if (delstr == NULL) {
|
||||
@@ -597,20 +695,33 @@
|
||||
/* All objects in unreachable are trash, but objects reachable from
|
||||
* finalizers can't safely be deleted. Python programmers should take
|
||||
* care not to create such things. For Python, finalizers means
|
||||
- * instance objects with __del__ methods.
|
||||
+ * instance objects with __del__ methods. Weakrefs with callbacks
|
||||
+ * can call arbitrary Python code, so those are special-cased too.
|
||||
*
|
||||
- * Move unreachable objects with finalizers into a different list.
|
||||
+ * Move unreachable objects with finalizers, and weakrefs with
|
||||
+ * callbacks, into different lists.
|
||||
*/
|
||||
gc_list_init(&finalizers);
|
||||
- move_finalizers(&unreachable, &finalizers);
|
||||
+ gc_list_init(&wr_callbacks);
|
||||
+ move_troublemakers(&unreachable, &finalizers, &wr_callbacks);
|
||||
+ /* Clear the trash weakrefs with callbacks. This prevents their
|
||||
+ * callbacks from getting invoked (when a weakref goes away, so does
|
||||
+ * its callback).
|
||||
+ * We do this even if the weakrefs are reachable from finalizers.
|
||||
+ * If we didn't, breaking cycles in unreachable later could trigger
|
||||
+ * deallocation of objects in finalizers, which could in turn
|
||||
+ * cause callbacks to trigger. This may not be ideal behavior.
|
||||
+ */
|
||||
+ clear_weakrefs(&wr_callbacks);
|
||||
/* finalizers contains the unreachable objects with a finalizer;
|
||||
- * unreachable objects reachable only *from* those are also
|
||||
- * uncollectable, and we move those into the finalizers list too.
|
||||
+ * unreachable objects reachable *from* those are also uncollectable,
|
||||
+ * and we move those into the finalizers list too.
|
||||
*/
|
||||
move_finalizer_reachable(&finalizers);
|
||||
|
||||
/* Collect statistics on collectable objects found and print
|
||||
- * debugging information. */
|
||||
+ * debugging information.
|
||||
+ */
|
||||
for (gc = unreachable.gc.gc_next; gc != &unreachable;
|
||||
gc = gc->gc.gc_next) {
|
||||
m++;
|
||||
@@ -623,6 +734,11 @@
|
||||
* in finalizers to be freed.
|
||||
*/
|
||||
delete_garbage(&unreachable, old);
|
||||
+
|
||||
+ /* Now that we're done analyzing stuff and breaking cycles, let
|
||||
+ * delayed weakref callbacks run.
|
||||
+ */
|
||||
+ m += release_weakrefs(&wr_callbacks, old);
|
||||
|
||||
/* Collect statistics on uncollectable objects found and print
|
||||
* debugging information. */
|
|
@ -1,66 +0,0 @@
|
|||
--- Objects/weakrefobject.c.orig Tue Jul 15 06:46:23 2003
|
||||
+++ Objects/weakrefobject.c Fri Nov 21 11:39:53 2003
|
||||
@@ -53,17 +53,43 @@
|
||||
if (*list == self)
|
||||
*list = self->wr_next;
|
||||
self->wr_object = Py_None;
|
||||
- self->wr_callback = NULL;
|
||||
if (self->wr_prev != NULL)
|
||||
self->wr_prev->wr_next = self->wr_next;
|
||||
if (self->wr_next != NULL)
|
||||
self->wr_next->wr_prev = self->wr_prev;
|
||||
self->wr_prev = NULL;
|
||||
self->wr_next = NULL;
|
||||
- Py_XDECREF(callback);
|
||||
+ }
|
||||
+ if (callback != NULL) {
|
||||
+ Py_DECREF(callback);
|
||||
+ self->wr_callback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
|
||||
+ * the callback intact and uncalled. It must be possible to call self's
|
||||
+ * tp_dealloc() after calling this, so self has to be left in a sane enough
|
||||
+ * state for that to work. We expect tp_dealloc to decref the callback
|
||||
+ * then. The reason for not letting clear_weakref() decref the callback
|
||||
+ * right now is that if the callback goes away, that may in turn trigger
|
||||
+ * another callback (if a weak reference to the callback exists) -- running
|
||||
+ * arbitrary Python code in the middle of gc is a disaster. The convolution
|
||||
+ * here allows gc to delay triggering such callbacks until the world is in
|
||||
+ * a sane state again.
|
||||
+ */
|
||||
+void
|
||||
+_PyWeakref_ClearRef(PyWeakReference *self)
|
||||
+{
|
||||
+ PyObject *callback;
|
||||
+
|
||||
+ assert(self != NULL);
|
||||
+ assert(PyWeakref_Check(self));
|
||||
+ /* Preserve and restore the callback around clear_weakref. */
|
||||
+ callback = self->wr_callback;
|
||||
+ self->wr_callback = NULL;
|
||||
+ clear_weakref(self);
|
||||
+ self->wr_callback = callback;
|
||||
+}
|
||||
|
||||
static void
|
||||
weakref_dealloc(PyWeakReference *self)
|
||||
@@ -117,7 +143,7 @@
|
||||
self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
|
||||
return self->hash;
|
||||
}
|
||||
-
|
||||
+
|
||||
|
||||
static PyObject *
|
||||
weakref_repr(PyWeakReference *self)
|
||||
@@ -324,7 +350,7 @@
|
||||
WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
|
||||
WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
|
||||
|
||||
-static int
|
||||
+static int
|
||||
proxy_nonzero(PyWeakReference *proxy)
|
||||
{
|
||||
PyObject *o = PyWeakref_GET_OBJECT(proxy);
|
14
lang/python23/files/patch-Python::ceval.c
Normal file
14
lang/python23/files/patch-Python::ceval.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
--- Python/ceval.c.orig Sat Dec 20 15:13:53 2003
|
||||
+++ Python/ceval.c Sat Dec 20 15:15:46 2003
|
||||
@@ -496,7 +496,10 @@
|
||||
|
||||
/* The interpreter's recursion limit */
|
||||
|
||||
-static int recursion_limit = 1000;
|
||||
+#ifndef PYTHON_DEFAULT_RECURSION_LIMIT
|
||||
+#define PYTHON_DEFAULT_RECURSION_LIMIT 1000
|
||||
+#endif
|
||||
+static int recursion_limit = PYTHON_DEFAULT_RECURSION_LIMIT;
|
||||
|
||||
int
|
||||
Py_GetRecursionLimit(void)
|
|
@ -6,8 +6,7 @@
|
|||
#
|
||||
|
||||
PORTNAME= python
|
||||
PORTVERSION= 2.3.2
|
||||
PORTREVISION= 3
|
||||
PORTVERSION= 2.3.3
|
||||
CATEGORIES= lang python ipv6
|
||||
MASTER_SITES= ${PYTHON_MASTER_SITES}
|
||||
MASTER_SITE_SUBDIR= ${PYTHON_MASTER_SITE_SUBDIR}
|
||||
|
@ -83,6 +82,9 @@ PLIST_SUB+= 32BIT_ONLY="@comment "
|
|||
.else
|
||||
PLIST_SUB+= 32BIT_ONLY=""
|
||||
.endif
|
||||
.if ${ARCH} == sparc64
|
||||
CFLAGS+= -DPYTHON_DEFAULT_RECURSION_LIMIT=900
|
||||
.endif
|
||||
|
||||
.if ${OSVERSION} < 400000
|
||||
LIB_DEPENDS+= ncurses.5:${PORTSDIR}/devel/ncurses
|
||||
|
|
|
@ -13,4 +13,5 @@ MD5 (python/Python-2.2.3.tgz) = 169f89f318e252dac0c54dd1b165d229
|
|||
MD5 (python/Python-2.3.tgz) = 595620a4769073a812e353597585c4e8
|
||||
MD5 (python/Python-2.3.1.tgz) = a3dcbe1c7f173c8e3c7cce28495016ae
|
||||
MD5 (python/Python-2.3.2.tgz) = f54d7a529d444994b4b33429bbb45479
|
||||
MD5 (python/Python-2.3.3.tgz) = 4d16732b1cfccc0ed250956d41463c61
|
||||
MD5 (python/Python-2.4.a0.20031022.tgz) = 79581105c218886dd9dc382a84c64043
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
--- Include/weakrefobject.h.orig Mon Aug 12 16:21:58 2002
|
||||
+++ Include/weakrefobject.h Fri Nov 21 11:39:53 2003
|
||||
@@ -39,6 +39,8 @@
|
||||
|
||||
PyAPI_FUNC(long) _PyWeakref_GetWeakrefCount(PyWeakReference *head);
|
||||
|
||||
+PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self);
|
||||
+
|
||||
#define PyWeakref_GET_OBJECT(ref) (((PyWeakReference *)(ref))->wr_object)
|
||||
|
||||
|
23
lang/python24/files/patch-Lib::email::Charset.py
Normal file
23
lang/python24/files/patch-Lib::email::Charset.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
--- Lib/email/Charset.py.orig Sat Dec 20 15:16:29 2003
|
||||
+++ Lib/email/Charset.py Sat Dec 20 15:16:54 2003
|
||||
@@ -99,13 +99,13 @@
|
||||
# of stability and useability.
|
||||
|
||||
CODEC_MAP = {
|
||||
- 'euc-jp': 'japanese.euc-jp',
|
||||
- 'iso-2022-jp': 'japanese.iso-2022-jp',
|
||||
- 'shift_jis': 'japanese.shift_jis',
|
||||
- 'euc-kr': 'korean.euc-kr',
|
||||
- 'ks_c_5601-1987': 'korean.cp949',
|
||||
- 'iso-2022-kr': 'korean.iso-2022-kr',
|
||||
- 'johab': 'korean.johab',
|
||||
+ 'euc-jp': 'euc-jp',
|
||||
+ 'iso-2022-jp': 'iso-2022-jp',
|
||||
+ 'shift_jis': 'shift_jis',
|
||||
+ 'euc-kr': 'euc-kr',
|
||||
+ 'ks_c_5601-1987': 'cp949',
|
||||
+ 'iso-2022-kr': 'iso-2022-kr',
|
||||
+ 'johab': 'johab',
|
||||
'gb2132': 'eucgb2312_cn',
|
||||
'big5': 'big5_tw',
|
||||
'utf-8': 'utf-8',
|
|
@ -1,214 +0,0 @@
|
|||
--- Lib/test/test_weakref.py.orig Tue Jul 15 06:37:17 2003
|
||||
+++ Lib/test/test_weakref.py Fri Nov 21 11:39:53 2003
|
||||
@@ -299,6 +299,211 @@
|
||||
self.fail("exception not properly restored")
|
||||
|
||||
|
||||
+ def test_callback_in_cycle_1(self):
|
||||
+ import gc
|
||||
+
|
||||
+ class J(object):
|
||||
+ pass
|
||||
+
|
||||
+ class II(object):
|
||||
+ def acallback(self, ignore):
|
||||
+ self.J
|
||||
+
|
||||
+ I = II()
|
||||
+ I.J = J
|
||||
+ I.wr = weakref.ref(J, I.acallback)
|
||||
+
|
||||
+ # Now J and II are each in a self-cycle (as all new-style class
|
||||
+ # objects are, since their __mro__ points back to them). I holds
|
||||
+ # both a weak reference (I.wr) and a strong reference (I.J) to class
|
||||
+ # J. I is also in a cycle (I.wr points to a weakref that references
|
||||
+ # I.acallback). When we del these three, they all become trash, but
|
||||
+ # the cycles prevent any of them from getting cleaned up immediately.
|
||||
+ # Instead they have to wait for cyclic gc to deduce that they're
|
||||
+ # trash.
|
||||
+ #
|
||||
+ # gc used to call tp_clear on all of them, and the order in which
|
||||
+ # it does that is pretty accidental. The exact order in which we
|
||||
+ # built up these things manages to provoke gc into running tp_clear
|
||||
+ # in just the right order (I last). Calling tp_clear on II leaves
|
||||
+ # behind an insane class object (its __mro__ becomes NULL). Calling
|
||||
+ # tp_clear on J breaks its self-cycle, but J doesn't get deleted
|
||||
+ # just then because of the strong reference from I.J. Calling
|
||||
+ # tp_clear on I starts to clear I's __dict__, and just happens to
|
||||
+ # clear I.J first -- I.wr is still intact. That removes the last
|
||||
+ # reference to J, which triggers the weakref callback. The callback
|
||||
+ # tries to do "self.J", and instances of new-style classes look up
|
||||
+ # attributes ("J") in the class dict first. The class (II) wants to
|
||||
+ # search II.__mro__, but that's NULL. The result was a segfault in
|
||||
+ # a release build, and an assert failure in a debug build.
|
||||
+ del I, J, II
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_2(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # This is just like test_callback_in_cycle_1, except that II is an
|
||||
+ # old-style class. The symptom is different then: an instance of an
|
||||
+ # old-style class looks in its own __dict__ first. 'J' happens to
|
||||
+ # get cleared from I.__dict__ before 'wr', and 'J' was never in II's
|
||||
+ # __dict__, so the attribute isn't found. The difference is that
|
||||
+ # the old-style II doesn't have a NULL __mro__ (it doesn't have any
|
||||
+ # __mro__), so no segfault occurs. Instead it got:
|
||||
+ # test_callback_in_cycle_2 (__main__.ReferencesTestCase) ...
|
||||
+ # Exception exceptions.AttributeError:
|
||||
+ # "II instance has no attribute 'J'" in <bound method II.acallback
|
||||
+ # of <?.II instance at 0x00B9B4B8>> ignored
|
||||
+
|
||||
+ class J(object):
|
||||
+ pass
|
||||
+
|
||||
+ class II:
|
||||
+ def acallback(self, ignore):
|
||||
+ self.J
|
||||
+
|
||||
+ I = II()
|
||||
+ I.J = J
|
||||
+ I.wr = weakref.ref(J, I.acallback)
|
||||
+
|
||||
+ del I, J, II
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_3(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # This one broke the first patch that fixed the last two. In this
|
||||
+ # case, the objects reachable from the callback aren't also reachable
|
||||
+ # from the object (c1) *triggering* the callback: you can get to
|
||||
+ # c1 from c2, but not vice-versa. The result was that c2's __dict__
|
||||
+ # got tp_clear'ed by the time the c2.cb callback got invoked.
|
||||
+
|
||||
+ class C:
|
||||
+ def cb(self, ignore):
|
||||
+ self.me
|
||||
+ self.c1
|
||||
+ self.wr
|
||||
+
|
||||
+ c1, c2 = C(), C()
|
||||
+
|
||||
+ c2.me = c2
|
||||
+ c2.c1 = c1
|
||||
+ c2.wr = weakref.ref(c1, c2.cb)
|
||||
+
|
||||
+ del c1, c2
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_4(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # Like test_callback_in_cycle_3, except c2 and c1 have different
|
||||
+ # classes. c2's class (C) isn't reachable from c1 then, so protecting
|
||||
+ # objects reachable from the dying object (c1) isn't enough to stop
|
||||
+ # c2's class (C) from getting tp_clear'ed before c2.cb is invoked.
|
||||
+ # The result was a segfault (C.__mro__ was NULL when the callback
|
||||
+ # tried to look up self.me).
|
||||
+
|
||||
+ class C(object):
|
||||
+ def cb(self, ignore):
|
||||
+ self.me
|
||||
+ self.c1
|
||||
+ self.wr
|
||||
+
|
||||
+ class D:
|
||||
+ pass
|
||||
+
|
||||
+ c1, c2 = D(), C()
|
||||
+
|
||||
+ c2.me = c2
|
||||
+ c2.c1 = c1
|
||||
+ c2.wr = weakref.ref(c1, c2.cb)
|
||||
+
|
||||
+ del c1, c2, C, D
|
||||
+ gc.collect()
|
||||
+
|
||||
+ def test_callback_in_cycle_resurrection(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # Do something nasty in a weakref callback: resurrect objects
|
||||
+ # from dead cycles. For this to be attempted, the weakref and
|
||||
+ # its callback must also be part of the cyclic trash (else the
|
||||
+ # objects reachable via the callback couldn't be in cyclic trash
|
||||
+ # to begin with -- the callback would act like an external root).
|
||||
+ # But gc clears trash weakrefs with callbacks early now, which
|
||||
+ # disables the callbacks, so the callbacks shouldn't get called
|
||||
+ # at all (and so nothing actually gets resurrected).
|
||||
+
|
||||
+ alist = []
|
||||
+ class C(object):
|
||||
+ def __init__(self, value):
|
||||
+ self.attribute = value
|
||||
+
|
||||
+ def acallback(self, ignore):
|
||||
+ alist.append(self.c)
|
||||
+
|
||||
+ c1, c2 = C(1), C(2)
|
||||
+ c1.c = c2
|
||||
+ c2.c = c1
|
||||
+ c1.wr = weakref.ref(c2, c1.acallback)
|
||||
+ c2.wr = weakref.ref(c1, c2.acallback)
|
||||
+
|
||||
+ def C_went_away(ignore):
|
||||
+ alist.append("C went away")
|
||||
+ wr = weakref.ref(C, C_went_away)
|
||||
+
|
||||
+ del c1, c2, C # make them all trash
|
||||
+ self.assertEqual(alist, []) # del isn't enough to reclaim anything
|
||||
+
|
||||
+ gc.collect()
|
||||
+ # c1.wr and c2.wr were part of the cyclic trash, so should have
|
||||
+ # been cleared without their callbacks executing. OTOH, the weakref
|
||||
+ # to C is bound to a function local (wr), and wasn't trash, so that
|
||||
+ # callback should have been invoked when C went away.
|
||||
+ self.assertEqual(alist, ["C went away"])
|
||||
+ # The remaining weakref should be dead now (its callback ran).
|
||||
+ self.assertEqual(wr(), None)
|
||||
+
|
||||
+ del alist[:]
|
||||
+ gc.collect()
|
||||
+ self.assertEqual(alist, [])
|
||||
+
|
||||
+ def test_callbacks_on_callback(self):
|
||||
+ import gc
|
||||
+
|
||||
+ # Set up weakref callbacks *on* weakref callbacks.
|
||||
+ alist = []
|
||||
+ def safe_callback(ignore):
|
||||
+ alist.append("safe_callback called")
|
||||
+
|
||||
+ class C(object):
|
||||
+ def cb(self, ignore):
|
||||
+ alist.append("cb called")
|
||||
+
|
||||
+ c, d = C(), C()
|
||||
+ c.other = d
|
||||
+ d.other = c
|
||||
+ callback = c.cb
|
||||
+ c.wr = weakref.ref(d, callback) # this won't trigger
|
||||
+ d.wr = weakref.ref(callback, d.cb) # ditto
|
||||
+ external_wr = weakref.ref(callback, safe_callback) # but this will
|
||||
+ self.assert_(external_wr() is callback)
|
||||
+
|
||||
+ # The weakrefs attached to c and d should get cleared, so that
|
||||
+ # C.cb is never called. But external_wr isn't part of the cyclic
|
||||
+ # trash, and no cyclic trash is reachable from it, so safe_callback
|
||||
+ # should get invoked when the bound method object callback (c.cb)
|
||||
+ # -- which is itself a callback, and also part of the cyclic trash --
|
||||
+ # gets reclaimed at the end of gc.
|
||||
+
|
||||
+ del callback, c, d, C
|
||||
+ self.assertEqual(alist, []) # del isn't enough to clean up cycles
|
||||
+ gc.collect()
|
||||
+ self.assertEqual(alist, ["safe_callback called"])
|
||||
+ self.assertEqual(external_wr(), None)
|
||||
+
|
||||
+ del alist[:]
|
||||
+ gc.collect()
|
||||
+ self.assertEqual(alist, [])
|
||||
+
|
||||
class Object:
|
||||
def __init__(self, arg):
|
||||
self.arg = arg
|
|
@ -1,19 +0,0 @@
|
|||
--- Modules/_sre.c 26 Jun 2003 14:41:08 -0000 2.99
|
||||
+++ Modules/_sre.c 27 Sep 2003 18:13:15 -0000
|
||||
@@ -71,9 +71,14 @@
|
||||
Win64 (MS_WIN64), Linux64 (__LP64__), Monterey (64-bit AIX) (_LP64) */
|
||||
/* FIXME: maybe the limit should be 40000 / sizeof(void*) ? */
|
||||
#define USE_RECURSION_LIMIT 7500
|
||||
-#else
|
||||
|
||||
-#if defined(__GNUC__) && defined(WITH_THREAD) && defined(__FreeBSD__)
|
||||
+#elif defined(__FreeBSD__)
|
||||
+/* FreeBSD/amd64 and /sparc64 requires even smaller limit */
|
||||
+#if defined(__amd64__)
|
||||
+#define USE_RECURSION_LIMIT 6000
|
||||
+#elif defined(__sparc64__)
|
||||
+#define USE_RECURSION_LIMIT 3000
|
||||
+#elif defined(__GNUC__) && defined(WITH_THREAD)
|
||||
/* the pthreads library on FreeBSD has a fixed 1MB stack size for the
|
||||
* initial (or "primary") thread, which is insufficient for the default
|
||||
* recursion limit. gcc 3.x at the default optimisation
|
|
@ -1,196 +0,0 @@
|
|||
--- Modules/gcmodule.c.orig Fri Apr 18 02:29:21 2003
|
||||
+++ Modules/gcmodule.c Fri Nov 21 11:39:52 2003
|
||||
@@ -377,13 +377,17 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
-/* Move the objects in unreachable with __del__ methods into finalizers.
|
||||
- * The objects remaining in unreachable do not have __del__ methods, and
|
||||
- * gc_refs remains GC_TENTATIVELY_UNREACHABLE for them. The objects
|
||||
- * moved into finalizers have gc_refs changed to GC_REACHABLE.
|
||||
+/* Move the objects in unreachable with __del__ methods into finalizers,
|
||||
+ * and weakrefs with callbacks into wr_callbacks.
|
||||
+ * The objects remaining in unreachable do not have __del__ methods, and are
|
||||
+ * not weakrefs with callbacks.
|
||||
+ * The objects moved have gc_refs changed to GC_REACHABLE; the objects
|
||||
+ * remaining in unreachable are left at GC_TENTATIVELY_UNREACHABLE.
|
||||
*/
|
||||
static void
|
||||
-move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
|
||||
+move_troublemakers(PyGC_Head *unreachable,
|
||||
+ PyGC_Head *finalizers,
|
||||
+ PyGC_Head *wr_callbacks)
|
||||
{
|
||||
PyGC_Head *gc = unreachable->gc.gc_next;
|
||||
|
||||
@@ -398,6 +402,12 @@
|
||||
gc_list_append(gc, finalizers);
|
||||
gc->gc.gc_refs = GC_REACHABLE;
|
||||
}
|
||||
+ else if (PyWeakref_Check(op) &&
|
||||
+ ((PyWeakReference *)op)->wr_callback) {
|
||||
+ gc_list_remove(gc);
|
||||
+ gc_list_append(gc, wr_callbacks);
|
||||
+ gc->gc.gc_refs = GC_REACHABLE;
|
||||
+ }
|
||||
gc = next;
|
||||
}
|
||||
}
|
||||
@@ -434,6 +444,93 @@
|
||||
}
|
||||
}
|
||||
|
||||
+/* Clear all trash weakrefs with callbacks. This clears weakrefs first,
|
||||
+ * which has the happy result of disabling the callbacks without executing
|
||||
+ * them. A nasty technical complication: a weakref callback can itself be
|
||||
+ * the target of a weakref, in which case decrefing the callback can cause
|
||||
+ * another callback to trigger. But we can't allow arbitrary Python code to
|
||||
+ * get executed at this point (the callback on the callback may try to muck
|
||||
+ * with other cyclic trash we're trying to collect, even resurrecting it
|
||||
+ * while we're in the middle of doing tp_clear() on the trash).
|
||||
+ *
|
||||
+ * The private _PyWeakref_ClearRef() function exists so that we can clear
|
||||
+ * the reference in a weakref without triggering a callback on the callback.
|
||||
+ *
|
||||
+ * We have to save the callback objects and decref them later. But we can't
|
||||
+ * allocate new memory to save them (if we can't get new memory, we're dead).
|
||||
+ * So we grab a new reference on the clear'ed weakref, which prevents the
|
||||
+ * rest of gc from reclaiming it. _PyWeakref_ClearRef() leaves the
|
||||
+ * weakref's wr_callback member intact.
|
||||
+ *
|
||||
+ * In the end, then, wr_callbacks consists of cleared weakrefs that are
|
||||
+ * immune from collection. Near the end of gc, after collecting all the
|
||||
+ * cyclic trash, we call release_weakrefs(). That releases our references
|
||||
+ * to the cleared weakrefs, which in turn may trigger callbacks on their
|
||||
+ * callbacks.
|
||||
+ */
|
||||
+static void
|
||||
+clear_weakrefs(PyGC_Head *wr_callbacks)
|
||||
+{
|
||||
+ PyGC_Head *gc = wr_callbacks->gc.gc_next;
|
||||
+
|
||||
+ for (; gc != wr_callbacks; gc = gc->gc.gc_next) {
|
||||
+ PyObject *op = FROM_GC(gc);
|
||||
+ PyWeakReference *wr;
|
||||
+
|
||||
+ assert(IS_REACHABLE(op));
|
||||
+ assert(PyWeakref_Check(op));
|
||||
+ wr = (PyWeakReference *)op;
|
||||
+ assert(wr->wr_callback != NULL);
|
||||
+ Py_INCREF(op);
|
||||
+ _PyWeakref_ClearRef(wr);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Called near the end of gc. This gives up the references we own to
|
||||
+ * cleared weakrefs, allowing them to get collected, and in turn decref'ing
|
||||
+ * their callbacks.
|
||||
+ *
|
||||
+ * If a callback object is itself the target of a weakref callback,
|
||||
+ * decref'ing the callback object may trigger that other callback. If
|
||||
+ * that other callback was part of the cyclic trash in this generation,
|
||||
+ * that won't happen, since we cleared *all* trash-weakref callbacks near
|
||||
+ * the start of gc. If that other callback was not part of the cyclic trash
|
||||
+ * in this generation, then it acted like an external root to this round
|
||||
+ * of gc, so all the objects reachable from that callback are still alive.
|
||||
+ *
|
||||
+ * Giving up the references to the weakref objects will probably make
|
||||
+ * them go away too. However, if a weakref is reachable from finalizers,
|
||||
+ * it won't go away. We move it to the old generation then. Since a
|
||||
+ * weakref object doesn't have a finalizer, that's the right thing to do (it
|
||||
+ * doesn't belong in gc.garbage).
|
||||
+ *
|
||||
+ * We return the number of weakref objects freed (those not appended to old).
|
||||
+ */
|
||||
+static int
|
||||
+release_weakrefs(PyGC_Head *wr_callbacks, PyGC_Head *old)
|
||||
+{
|
||||
+ int num_freed = 0;
|
||||
+
|
||||
+ while (! gc_list_is_empty(wr_callbacks)) {
|
||||
+ PyGC_Head *gc = wr_callbacks->gc.gc_next;
|
||||
+ PyObject *op = FROM_GC(gc);
|
||||
+ PyWeakReference *wr = (PyWeakReference *)op;
|
||||
+
|
||||
+ assert(IS_REACHABLE(op));
|
||||
+ assert(PyWeakref_Check(op));
|
||||
+ assert(wr->wr_callback != NULL);
|
||||
+ Py_DECREF(op);
|
||||
+ if (wr_callbacks->gc.gc_next == gc) {
|
||||
+ /* object is still alive -- move it */
|
||||
+ gc_list_remove(gc);
|
||||
+ gc_list_append(gc, old);
|
||||
+ }
|
||||
+ else
|
||||
+ ++num_freed;
|
||||
+ }
|
||||
+ return num_freed;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
debug_instance(char *msg, PyInstanceObject *inst)
|
||||
{
|
||||
@@ -535,8 +632,9 @@
|
||||
long n = 0; /* # unreachable objects that couldn't be collected */
|
||||
PyGC_Head *young; /* the generation we are examining */
|
||||
PyGC_Head *old; /* next older generation */
|
||||
- PyGC_Head unreachable;
|
||||
- PyGC_Head finalizers;
|
||||
+ PyGC_Head unreachable; /* non-problematic unreachable trash */
|
||||
+ PyGC_Head finalizers; /* objects with, & reachable from, __del__ */
|
||||
+ PyGC_Head wr_callbacks; /* weakrefs with callbacks */
|
||||
PyGC_Head *gc;
|
||||
|
||||
if (delstr == NULL) {
|
||||
@@ -597,20 +695,33 @@
|
||||
/* All objects in unreachable are trash, but objects reachable from
|
||||
* finalizers can't safely be deleted. Python programmers should take
|
||||
* care not to create such things. For Python, finalizers means
|
||||
- * instance objects with __del__ methods.
|
||||
+ * instance objects with __del__ methods. Weakrefs with callbacks
|
||||
+ * can call arbitrary Python code, so those are special-cased too.
|
||||
*
|
||||
- * Move unreachable objects with finalizers into a different list.
|
||||
+ * Move unreachable objects with finalizers, and weakrefs with
|
||||
+ * callbacks, into different lists.
|
||||
*/
|
||||
gc_list_init(&finalizers);
|
||||
- move_finalizers(&unreachable, &finalizers);
|
||||
+ gc_list_init(&wr_callbacks);
|
||||
+ move_troublemakers(&unreachable, &finalizers, &wr_callbacks);
|
||||
+ /* Clear the trash weakrefs with callbacks. This prevents their
|
||||
+ * callbacks from getting invoked (when a weakref goes away, so does
|
||||
+ * its callback).
|
||||
+ * We do this even if the weakrefs are reachable from finalizers.
|
||||
+ * If we didn't, breaking cycles in unreachable later could trigger
|
||||
+ * deallocation of objects in finalizers, which could in turn
|
||||
+ * cause callbacks to trigger. This may not be ideal behavior.
|
||||
+ */
|
||||
+ clear_weakrefs(&wr_callbacks);
|
||||
/* finalizers contains the unreachable objects with a finalizer;
|
||||
- * unreachable objects reachable only *from* those are also
|
||||
- * uncollectable, and we move those into the finalizers list too.
|
||||
+ * unreachable objects reachable *from* those are also uncollectable,
|
||||
+ * and we move those into the finalizers list too.
|
||||
*/
|
||||
move_finalizer_reachable(&finalizers);
|
||||
|
||||
/* Collect statistics on collectable objects found and print
|
||||
- * debugging information. */
|
||||
+ * debugging information.
|
||||
+ */
|
||||
for (gc = unreachable.gc.gc_next; gc != &unreachable;
|
||||
gc = gc->gc.gc_next) {
|
||||
m++;
|
||||
@@ -623,6 +734,11 @@
|
||||
* in finalizers to be freed.
|
||||
*/
|
||||
delete_garbage(&unreachable, old);
|
||||
+
|
||||
+ /* Now that we're done analyzing stuff and breaking cycles, let
|
||||
+ * delayed weakref callbacks run.
|
||||
+ */
|
||||
+ m += release_weakrefs(&wr_callbacks, old);
|
||||
|
||||
/* Collect statistics on uncollectable objects found and print
|
||||
* debugging information. */
|
|
@ -1,66 +0,0 @@
|
|||
--- Objects/weakrefobject.c.orig Tue Jul 15 06:46:23 2003
|
||||
+++ Objects/weakrefobject.c Fri Nov 21 11:39:53 2003
|
||||
@@ -53,17 +53,43 @@
|
||||
if (*list == self)
|
||||
*list = self->wr_next;
|
||||
self->wr_object = Py_None;
|
||||
- self->wr_callback = NULL;
|
||||
if (self->wr_prev != NULL)
|
||||
self->wr_prev->wr_next = self->wr_next;
|
||||
if (self->wr_next != NULL)
|
||||
self->wr_next->wr_prev = self->wr_prev;
|
||||
self->wr_prev = NULL;
|
||||
self->wr_next = NULL;
|
||||
- Py_XDECREF(callback);
|
||||
+ }
|
||||
+ if (callback != NULL) {
|
||||
+ Py_DECREF(callback);
|
||||
+ self->wr_callback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
|
||||
+ * the callback intact and uncalled. It must be possible to call self's
|
||||
+ * tp_dealloc() after calling this, so self has to be left in a sane enough
|
||||
+ * state for that to work. We expect tp_dealloc to decref the callback
|
||||
+ * then. The reason for not letting clear_weakref() decref the callback
|
||||
+ * right now is that if the callback goes away, that may in turn trigger
|
||||
+ * another callback (if a weak reference to the callback exists) -- running
|
||||
+ * arbitrary Python code in the middle of gc is a disaster. The convolution
|
||||
+ * here allows gc to delay triggering such callbacks until the world is in
|
||||
+ * a sane state again.
|
||||
+ */
|
||||
+void
|
||||
+_PyWeakref_ClearRef(PyWeakReference *self)
|
||||
+{
|
||||
+ PyObject *callback;
|
||||
+
|
||||
+ assert(self != NULL);
|
||||
+ assert(PyWeakref_Check(self));
|
||||
+ /* Preserve and restore the callback around clear_weakref. */
|
||||
+ callback = self->wr_callback;
|
||||
+ self->wr_callback = NULL;
|
||||
+ clear_weakref(self);
|
||||
+ self->wr_callback = callback;
|
||||
+}
|
||||
|
||||
static void
|
||||
weakref_dealloc(PyWeakReference *self)
|
||||
@@ -117,7 +143,7 @@
|
||||
self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
|
||||
return self->hash;
|
||||
}
|
||||
-
|
||||
+
|
||||
|
||||
static PyObject *
|
||||
weakref_repr(PyWeakReference *self)
|
||||
@@ -324,7 +350,7 @@
|
||||
WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
|
||||
WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
|
||||
|
||||
-static int
|
||||
+static int
|
||||
proxy_nonzero(PyWeakReference *proxy)
|
||||
{
|
||||
PyObject *o = PyWeakref_GET_OBJECT(proxy);
|
14
lang/python24/files/patch-Python::ceval.c
Normal file
14
lang/python24/files/patch-Python::ceval.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
--- Python/ceval.c.orig Sat Dec 20 15:13:53 2003
|
||||
+++ Python/ceval.c Sat Dec 20 15:15:46 2003
|
||||
@@ -496,7 +496,10 @@
|
||||
|
||||
/* The interpreter's recursion limit */
|
||||
|
||||
-static int recursion_limit = 1000;
|
||||
+#ifndef PYTHON_DEFAULT_RECURSION_LIMIT
|
||||
+#define PYTHON_DEFAULT_RECURSION_LIMIT 1000
|
||||
+#endif
|
||||
+static int recursion_limit = PYTHON_DEFAULT_RECURSION_LIMIT;
|
||||
|
||||
int
|
||||
Py_GetRecursionLimit(void)
|
Loading…
Add table
Reference in a new issue