diff options
Diffstat (limited to 'lang/python23/patches/patch-aj')
-rw-r--r-- | lang/python23/patches/patch-aj | 209 |
1 files changed, 197 insertions, 12 deletions
diff --git a/lang/python23/patches/patch-aj b/lang/python23/patches/patch-aj index a1f281a79ff..19948262988 100644 --- a/lang/python23/patches/patch-aj +++ b/lang/python23/patches/patch-aj @@ -1,13 +1,198 @@ -$NetBSD: patch-aj,v 1.1.1.1 2003/08/04 08:25:23 drochner Exp $ +$NetBSD: patch-aj,v 1.2 2003/12/08 21:13:56 recht Exp $ ---- Lib/distutils/command/build_scripts.py.orig 2003-08-03 12:32:35.000000000 +0200 -+++ Lib/distutils/command/build_scripts.py 2003-08-03 12:34:50.000000000 +0200 -@@ -99,7 +99,7 @@ - outf.write("#!%s%s\n" % - (os.path.join( - sysconfig.get_config_var("BINDIR"), -- "python" + sysconfig.get_config_var("EXE")), -+ "python2.3" + sysconfig.get_config_var("EXE")), - post_interp)) - outf.writelines(f.readlines()) - outf.close() +--- Modules/gcmodule.c.orig 2003-04-17 19:29:21.000000000 +0200 ++++ Modules/gcmodule.c +@@ -377,13 +377,17 @@ has_finalizer(PyObject *op) + 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 @@ move_finalizers(PyGC_Head *unreachable, + 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 @@ move_finalizer_reachable(PyGC_Head *fina + } + } + ++/* 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 @@ collect(int generation) + 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 @@ collect(int generation) + /* 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++; +@@ -624,6 +735,11 @@ collect(int generation) + */ + 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. */ + for (gc = finalizers.gc.gc_next; |