Ejemplo n.º 1
0
static int
is_dead_weakref(PyObject *value)
{
    if (!PyWeakref_Check(value)) {
        PyErr_SetString(PyExc_TypeError, "not a weakref");
        return -1;
    }
    return PyWeakref_GET_OBJECT(value) == Py_None;
}
PyObject *
PyWeakref_GetObject(PyObject *ref)
{
    if (ref == NULL || !PyWeakref_Check(ref)) {
        PyErr_BadInternalCall();
        return NULL;
    }
    return PyWeakref_GET_OBJECT(ref);
}
Ejemplo n.º 3
0
static PyObject *
weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
{
    if ((op != Py_EQ && op != Py_NE) ||
        !PyWeakref_Check(self) ||
        !PyWeakref_Check(other)) {
        Py_RETURN_NOTIMPLEMENTED;
    }
    if (PyWeakref_GET_OBJECT(self) == Py_None
        || PyWeakref_GET_OBJECT(other) == Py_None) {
        int res = (self == other);
        if (op == Py_NE)
            res = !res;
        if (res)
            Py_RETURN_TRUE;
        else
            Py_RETURN_FALSE;
    }
    return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
                                PyWeakref_GET_OBJECT(other), op);
}
/* 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;
}
Ejemplo n.º 5
0
/* Clear all weakrefs to unreachable objects, and if such a weakref has a
 * callback, invoke it if necessary.  Note that it's possible for such
 * weakrefs to be outside the unreachable set -- indeed, those are precisely
 * the weakrefs whose callbacks must be invoked.  See gc_weakref.txt for
 * overview & some details.  Some weakrefs with callbacks may be reclaimed
 * directly by this routine; the number reclaimed is the return value.  Other
 * weakrefs with callbacks may be moved into the `old` generation.  Objects
 * moved into `old` have gc_refs set to GC_REACHABLE; the objects remaining in
 * unreachable are left at GC_TENTATIVELY_UNREACHABLE.  When this returns,
 * no object in `unreachable` is weakly referenced anymore.
 */
static int
handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
{
	PyGC_Head *gc;
	PyObject *op;		/* generally FROM_GC(gc) */
	PyWeakReference *wr;	/* generally a cast of op */
	PyGC_Head wrcb_to_call;	/* weakrefs with callbacks to call */
	PyGC_Head *next;
	int num_freed = 0;

	gc_list_init(&wrcb_to_call);

	/* Clear all weakrefs to the objects in unreachable.  If such a weakref
	 * also has a callback, move it into `wrcb_to_call` if the callback
	 * needs to be invoked.  Note that we cannot invoke any callbacks until
	 * all weakrefs to unreachable objects are cleared, lest the callback
	 * resurrect an unreachable object via a still-active weakref.  We
	 * make another pass over wrcb_to_call, invoking callbacks, after this
	 * pass completes.
	 */
	for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) {
		PyWeakReference **wrlist;

		op = FROM_GC(gc);
		assert(IS_TENTATIVELY_UNREACHABLE(op));
		next = gc->gc.gc_next;

		if (! PyType_SUPPORTS_WEAKREFS(op->ob_type))
			continue;

		/* It supports weakrefs.  Does it have any? */
		wrlist = (PyWeakReference **)
			     		PyObject_GET_WEAKREFS_LISTPTR(op);

		/* `op` may have some weakrefs.  March over the list, clear
		 * all the weakrefs, and move the weakrefs with callbacks
		 * that must be called into wrcb_to_call.
		 */
		for (wr = *wrlist; wr != NULL; wr = *wrlist) {
			PyGC_Head *wrasgc;	/* AS_GC(wr) */

			/* _PyWeakref_ClearRef clears the weakref but leaves
			 * the callback pointer intact.  Obscure:  it also
			 * changes *wrlist.
			 */
			assert(wr->wr_object == op);
			_PyWeakref_ClearRef(wr);
			assert(wr->wr_object == Py_None);
			if (wr->wr_callback == NULL)
				continue;	/* no callback */

	/* Headache time.  `op` is going away, and is weakly referenced by
	 * `wr`, which has a callback.  Should the callback be invoked?  If wr
	 * is also trash, no:
	 *
	 * 1. There's no need to call it.  The object and the weakref are
	 *    both going away, so it's legitimate to pretend the weakref is
	 *    going away first.  The user has to ensure a weakref outlives its
	 *    referent if they want a guarantee that the wr callback will get
	 *    invoked.
	 *
	 * 2. It may be catastrophic to call it.  If the callback is also in
	 *    cyclic trash (CT), then although the CT is unreachable from
	 *    outside the current generation, CT may be reachable from the
	 *    callback.  Then the callback could resurrect insane objects.
	 *
	 * Since the callback is never needed and may be unsafe in this case,
	 * wr is simply left in the unreachable set.  Note that because we
	 * already called _PyWeakref_ClearRef(wr), its callback will never
	 * trigger.
	 *
	 * OTOH, if wr isn't part of CT, we should invoke the callback:  the
	 * weakref outlived the trash.  Note that since wr isn't CT in this
	 * case, its callback can't be CT either -- wr acted as an external
	 * root to this generation, and therefore its callback did too.  So
	 * nothing in CT is reachable from the callback either, so it's hard
	 * to imagine how calling it later could create a problem for us.  wr
	 * is moved to wrcb_to_call in this case.
	 */
	 		if (IS_TENTATIVELY_UNREACHABLE(wr))
	 			continue;
			assert(IS_REACHABLE(wr));

			/* Create a new reference so that wr can't go away
			 * before we can process it again.
			 */
			Py_INCREF(wr);

			/* Move wr to wrcb_to_call, for the next pass. */
			wrasgc = AS_GC(wr);
			assert(wrasgc != next); /* wrasgc is reachable, but
			                           next isn't, so they can't
			                           be the same */
			gc_list_move(wrasgc, &wrcb_to_call);
		}
	}

	/* Invoke the callbacks we decided to honor.  It's safe to invoke them
	 * because they can't reference unreachable objects.
	 */
	while (! gc_list_is_empty(&wrcb_to_call)) {
		PyObject *temp;
		PyObject *callback;

		gc = wrcb_to_call.gc.gc_next;
		op = FROM_GC(gc);
		assert(IS_REACHABLE(op));
		assert(PyWeakref_Check(op));
		wr = (PyWeakReference *)op;
		callback = wr->wr_callback;
		assert(callback != NULL);

		/* copy-paste of weakrefobject.c's handle_callback() */
		temp = PyObject_CallFunction(callback, "O", wr);
		if (temp == NULL)
			PyErr_WriteUnraisable(callback);
		else
			Py_DECREF(temp);

		/* Give up the reference we created in the first pass.  When
		 * op's refcount hits 0 (which it may or may not do right now),
		 * op's tp_dealloc will decref op->wr_callback too.  Note
		 * that the refcount probably will hit 0 now, and because this
		 * weakref was reachable to begin with, gc didn't already
		 * add it to its count of freed objects.  Example:  a reachable
		 * weak value dict maps some key to this reachable weakref.
		 * The callback removes this key->weakref mapping from the
		 * dict, leaving no other references to the weakref (excepting
		 * ours).
		 */
		Py_DECREF(op);
		if (wrcb_to_call.gc.gc_next == gc) {
			/* object is still alive -- move it */
			gc_list_move(gc, old);
		}
		else
			++num_freed;
	}

	return num_freed;
}