2 #include "structmember.h"
5 #define GET_WEAKREFS_LISTPTR(o) \
6 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
10 _PyWeakref_GetWeakrefCount(PyWeakReference
*head
)
14 while (head
!= NULL
) {
23 init_weakref(PyWeakReference
*self
, PyObject
*ob
, PyObject
*callback
)
28 self
->wr_callback
= callback
;
31 static PyWeakReference
*
32 new_weakref(PyObject
*ob
, PyObject
*callback
)
34 PyWeakReference
*result
;
36 result
= PyObject_GC_New(PyWeakReference
, &_PyWeakref_RefType
);
38 init_weakref(result
, ob
, callback
);
39 PyObject_GC_Track(result
);
45 /* This function clears the passed-in reference and removes it from the
46 * list of weak references for the referent. This is the only code that
47 * removes an item from the doubly-linked list of weak references for an
48 * object; it is also responsible for clearing the callback slot.
51 clear_weakref(PyWeakReference
*self
)
53 PyObject
*callback
= self
->wr_callback
;
55 if (PyWeakref_GET_OBJECT(self
) != Py_None
) {
56 PyWeakReference
**list
= GET_WEAKREFS_LISTPTR(
57 PyWeakref_GET_OBJECT(self
));
60 /* If 'self' is the end of the list (and thus self->wr_next == NULL)
61 then the weakref list itself (and thus the value of *list) will
62 end up being set to NULL. */
63 *list
= self
->wr_next
;
64 self
->wr_object
= Py_None
;
65 if (self
->wr_prev
!= NULL
)
66 self
->wr_prev
->wr_next
= self
->wr_next
;
67 if (self
->wr_next
!= NULL
)
68 self
->wr_next
->wr_prev
= self
->wr_prev
;
72 if (callback
!= NULL
) {
74 self
->wr_callback
= NULL
;
78 /* Cyclic gc uses this to *just* clear the passed-in reference, leaving
79 * the callback intact and uncalled. It must be possible to call self's
80 * tp_dealloc() after calling this, so self has to be left in a sane enough
81 * state for that to work. We expect tp_dealloc to decref the callback
82 * then. The reason for not letting clear_weakref() decref the callback
83 * right now is that if the callback goes away, that may in turn trigger
84 * another callback (if a weak reference to the callback exists) -- running
85 * arbitrary Python code in the middle of gc is a disaster. The convolution
86 * here allows gc to delay triggering such callbacks until the world is in
90 _PyWeakref_ClearRef(PyWeakReference
*self
)
95 assert(PyWeakref_Check(self
));
96 /* Preserve and restore the callback around clear_weakref. */
97 callback
= self
->wr_callback
;
98 self
->wr_callback
= NULL
;
100 self
->wr_callback
= callback
;
104 weakref_dealloc(PyObject
*self
)
106 PyObject_GC_UnTrack(self
);
107 clear_weakref((PyWeakReference
*) self
);
108 Py_TYPE(self
)->tp_free(self
);
113 gc_traverse(PyWeakReference
*self
, visitproc visit
, void *arg
)
115 Py_VISIT(self
->wr_callback
);
121 gc_clear(PyWeakReference
*self
)
129 weakref_call(PyWeakReference
*self
, PyObject
*args
, PyObject
*kw
)
131 static char *kwlist
[] = {NULL
};
133 if (PyArg_ParseTupleAndKeywords(args
, kw
, ":__call__", kwlist
)) {
134 PyObject
*object
= PyWeakref_GET_OBJECT(self
);
143 weakref_hash(PyWeakReference
*self
)
145 if (self
->hash
!= -1)
147 if (PyWeakref_GET_OBJECT(self
) == Py_None
) {
148 PyErr_SetString(PyExc_TypeError
, "weak object has gone away");
151 self
->hash
= PyObject_Hash(PyWeakref_GET_OBJECT(self
));
157 weakref_repr(PyWeakReference
*self
)
160 if (PyWeakref_GET_OBJECT(self
) == Py_None
) {
161 PyOS_snprintf(buffer
, sizeof(buffer
), "<weakref at %p; dead>", self
);
165 PyObject
*nameobj
= PyObject_GetAttrString(PyWeakref_GET_OBJECT(self
),
169 else if (PyString_Check(nameobj
))
170 name
= PyString_AS_STRING(nameobj
);
171 PyOS_snprintf(buffer
, sizeof(buffer
),
172 name
? "<weakref at %p; to '%.50s' at %p (%s)>"
173 : "<weakref at %p; to '%.50s' at %p>",
175 Py_TYPE(PyWeakref_GET_OBJECT(self
))->tp_name
,
176 PyWeakref_GET_OBJECT(self
),
180 return PyString_FromString(buffer
);
183 /* Weak references only support equality, not ordering. Two weak references
184 are equal if the underlying objects are equal. If the underlying object has
185 gone away, they are equal if they are identical. */
188 weakref_richcompare(PyWeakReference
* self
, PyWeakReference
* other
, int op
)
190 if (op
!= Py_EQ
|| self
->ob_type
!= other
->ob_type
) {
191 Py_INCREF(Py_NotImplemented
);
192 return Py_NotImplemented
;
194 if (PyWeakref_GET_OBJECT(self
) == Py_None
195 || PyWeakref_GET_OBJECT(other
) == Py_None
) {
196 PyObject
*res
= self
==other
? Py_True
: Py_False
;
200 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self
),
201 PyWeakref_GET_OBJECT(other
), op
);
204 /* Given the head of an object's list of weak references, extract the
205 * two callback-less refs (ref and proxy). Used to determine if the
206 * shared references exist and to determine the back link for newly
207 * inserted references.
210 get_basic_refs(PyWeakReference
*head
,
211 PyWeakReference
**refp
, PyWeakReference
**proxyp
)
216 if (head
!= NULL
&& head
->wr_callback
== NULL
) {
217 /* We need to be careful that the "basic refs" aren't
218 subclasses of the main types. That complicates this a
220 if (PyWeakref_CheckRefExact(head
)) {
222 head
= head
->wr_next
;
225 && head
->wr_callback
== NULL
226 && PyWeakref_CheckProxy(head
)) {
228 /* head = head->wr_next; */
233 /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
235 insert_after(PyWeakReference
*newref
, PyWeakReference
*prev
)
237 newref
->wr_prev
= prev
;
238 newref
->wr_next
= prev
->wr_next
;
239 if (prev
->wr_next
!= NULL
)
240 prev
->wr_next
->wr_prev
= newref
;
241 prev
->wr_next
= newref
;
244 /* Insert 'newref' at the head of the list; 'list' points to the variable
245 * that stores the head.
248 insert_head(PyWeakReference
*newref
, PyWeakReference
**list
)
250 PyWeakReference
*next
= *list
;
252 newref
->wr_prev
= NULL
;
253 newref
->wr_next
= next
;
255 next
->wr_prev
= newref
;
260 parse_weakref_init_args(char *funcname
, PyObject
*args
, PyObject
*kwargs
,
261 PyObject
**obp
, PyObject
**callbackp
)
263 /* XXX Should check that kwargs == NULL or is empty. */
264 return PyArg_UnpackTuple(args
, funcname
, 1, 2, obp
, callbackp
);
268 weakref___new__(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
270 PyWeakReference
*self
= NULL
;
271 PyObject
*ob
, *callback
= NULL
;
273 if (parse_weakref_init_args("__new__", args
, kwargs
, &ob
, &callback
)) {
274 PyWeakReference
*ref
, *proxy
;
275 PyWeakReference
**list
;
277 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob
))) {
278 PyErr_Format(PyExc_TypeError
,
279 "cannot create weak reference to '%s' object",
280 Py_TYPE(ob
)->tp_name
);
283 if (callback
== Py_None
)
285 list
= GET_WEAKREFS_LISTPTR(ob
);
286 get_basic_refs(*list
, &ref
, &proxy
);
287 if (callback
== NULL
&& type
== &_PyWeakref_RefType
) {
289 /* We can re-use an existing reference. */
291 return (PyObject
*)ref
;
294 /* We have to create a new reference. */
295 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
296 list on ob can be mutated. This means that the ref and
297 proxy pointers we got back earlier may have been collected,
298 so we need to compute these values again before we use
300 self
= (PyWeakReference
*) (type
->tp_alloc(type
, 0));
302 init_weakref(self
, ob
, callback
);
303 if (callback
== NULL
&& type
== &_PyWeakref_RefType
) {
304 insert_head(self
, list
);
307 PyWeakReference
*prev
;
309 get_basic_refs(*list
, &ref
, &proxy
);
310 prev
= (proxy
== NULL
) ? ref
: proxy
;
312 insert_head(self
, list
);
314 insert_after(self
, prev
);
318 return (PyObject
*)self
;
322 weakref___init__(PyObject
*self
, PyObject
*args
, PyObject
*kwargs
)
326 if (parse_weakref_init_args("__init__", args
, kwargs
, &tmp
, &tmp
))
334 _PyWeakref_RefType
= {
335 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
337 sizeof(PyWeakReference
),
339 weakref_dealloc
, /*tp_dealloc*/
344 (reprfunc
)weakref_repr
, /*tp_repr*/
346 0, /*tp_as_sequence*/
348 (hashfunc
)weakref_hash
, /*tp_hash*/
349 (ternaryfunc
)weakref_call
, /*tp_call*/
354 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
| Py_TPFLAGS_HAVE_RICHCOMPARE
355 | Py_TPFLAGS_BASETYPE
, /*tp_flags*/
357 (traverseproc
)gc_traverse
, /*tp_traverse*/
358 (inquiry
)gc_clear
, /*tp_clear*/
359 (richcmpfunc
)weakref_richcompare
, /*tp_richcompare*/
360 0, /*tp_weaklistoffset*/
371 weakref___init__
, /*tp_init*/
372 PyType_GenericAlloc
, /*tp_alloc*/
373 weakref___new__
, /*tp_new*/
374 PyObject_GC_Del
, /*tp_free*/
379 proxy_checkref(PyWeakReference
*proxy
)
381 if (PyWeakref_GET_OBJECT(proxy
) == Py_None
) {
382 PyErr_SetString(PyExc_ReferenceError
,
383 "weakly-referenced object no longer exists");
390 /* If a parameter is a proxy, check that it is still "live" and wrap it,
391 * replacing the original value with the raw object. Raises ReferenceError
392 * if the param is a dead proxy.
395 if (PyWeakref_CheckProxy(o)) { \
396 if (!proxy_checkref((PyWeakReference *)o)) \
398 o = PyWeakref_GET_OBJECT(o); \
401 #define UNWRAP_I(o) \
402 if (PyWeakref_CheckProxy(o)) { \
403 if (!proxy_checkref((PyWeakReference *)o)) \
405 o = PyWeakref_GET_OBJECT(o); \
408 #define WRAP_UNARY(method, generic) \
410 method(PyObject *proxy) { \
412 return generic(proxy); \
415 #define WRAP_BINARY(method, generic) \
417 method(PyObject *x, PyObject *y) { \
420 return generic(x, y); \
423 /* Note that the third arg needs to be checked for NULL since the tp_call
424 * slot can receive NULL for this arg.
426 #define WRAP_TERNARY(method, generic) \
428 method(PyObject *proxy, PyObject *v, PyObject *w) { \
433 return generic(proxy, v, w); \
436 #define WRAP_METHOD(method, special) \
438 method(PyObject *proxy) { \
440 return PyObject_CallMethod(proxy, special, ""); \
446 WRAP_BINARY(proxy_getattr
, PyObject_GetAttr
)
447 WRAP_UNARY(proxy_str
, PyObject_Str
)
448 WRAP_TERNARY(proxy_call
, PyEval_CallObjectWithKeywords
)
451 proxy_repr(PyWeakReference
*proxy
)
454 PyOS_snprintf(buf
, sizeof(buf
),
455 "<weakproxy at %p to %.100s at %p>", proxy
,
456 Py_TYPE(PyWeakref_GET_OBJECT(proxy
))->tp_name
,
457 PyWeakref_GET_OBJECT(proxy
));
458 return PyString_FromString(buf
);
463 proxy_setattr(PyWeakReference
*proxy
, PyObject
*name
, PyObject
*value
)
465 if (!proxy_checkref(proxy
))
467 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy
), name
, value
);
471 proxy_compare(PyObject
*proxy
, PyObject
*v
)
475 return PyObject_Compare(proxy
, v
);
479 WRAP_BINARY(proxy_add
, PyNumber_Add
)
480 WRAP_BINARY(proxy_sub
, PyNumber_Subtract
)
481 WRAP_BINARY(proxy_mul
, PyNumber_Multiply
)
482 WRAP_BINARY(proxy_div
, PyNumber_Divide
)
483 WRAP_BINARY(proxy_floor_div
, PyNumber_FloorDivide
)
484 WRAP_BINARY(proxy_true_div
, PyNumber_TrueDivide
)
485 WRAP_BINARY(proxy_mod
, PyNumber_Remainder
)
486 WRAP_BINARY(proxy_divmod
, PyNumber_Divmod
)
487 WRAP_TERNARY(proxy_pow
, PyNumber_Power
)
488 WRAP_UNARY(proxy_neg
, PyNumber_Negative
)
489 WRAP_UNARY(proxy_pos
, PyNumber_Positive
)
490 WRAP_UNARY(proxy_abs
, PyNumber_Absolute
)
491 WRAP_UNARY(proxy_invert
, PyNumber_Invert
)
492 WRAP_BINARY(proxy_lshift
, PyNumber_Lshift
)
493 WRAP_BINARY(proxy_rshift
, PyNumber_Rshift
)
494 WRAP_BINARY(proxy_and
, PyNumber_And
)
495 WRAP_BINARY(proxy_xor
, PyNumber_Xor
)
496 WRAP_BINARY(proxy_or
, PyNumber_Or
)
497 WRAP_UNARY(proxy_int
, PyNumber_Int
)
498 WRAP_UNARY(proxy_long
, PyNumber_Long
)
499 WRAP_UNARY(proxy_float
, PyNumber_Float
)
500 WRAP_BINARY(proxy_iadd
, PyNumber_InPlaceAdd
)
501 WRAP_BINARY(proxy_isub
, PyNumber_InPlaceSubtract
)
502 WRAP_BINARY(proxy_imul
, PyNumber_InPlaceMultiply
)
503 WRAP_BINARY(proxy_idiv
, PyNumber_InPlaceDivide
)
504 WRAP_BINARY(proxy_ifloor_div
, PyNumber_InPlaceFloorDivide
)
505 WRAP_BINARY(proxy_itrue_div
, PyNumber_InPlaceTrueDivide
)
506 WRAP_BINARY(proxy_imod
, PyNumber_InPlaceRemainder
)
507 WRAP_TERNARY(proxy_ipow
, PyNumber_InPlacePower
)
508 WRAP_BINARY(proxy_ilshift
, PyNumber_InPlaceLshift
)
509 WRAP_BINARY(proxy_irshift
, PyNumber_InPlaceRshift
)
510 WRAP_BINARY(proxy_iand
, PyNumber_InPlaceAnd
)
511 WRAP_BINARY(proxy_ixor
, PyNumber_InPlaceXor
)
512 WRAP_BINARY(proxy_ior
, PyNumber_InPlaceOr
)
513 WRAP_UNARY(proxy_index
, PyNumber_Index
)
516 proxy_nonzero(PyWeakReference
*proxy
)
518 PyObject
*o
= PyWeakref_GET_OBJECT(proxy
);
519 if (!proxy_checkref(proxy
))
521 return PyObject_IsTrue(o
);
525 proxy_dealloc(PyWeakReference
*self
)
527 if (self
->wr_callback
!= NULL
)
528 PyObject_GC_UnTrack((PyObject
*)self
);
530 PyObject_GC_Del(self
);
536 proxy_slice(PyWeakReference
*proxy
, Py_ssize_t i
, Py_ssize_t j
)
538 if (!proxy_checkref(proxy
))
540 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
);
544 proxy_ass_slice(PyWeakReference
*proxy
, Py_ssize_t i
, Py_ssize_t j
, PyObject
*value
)
546 if (!proxy_checkref(proxy
))
548 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
, value
);
552 proxy_contains(PyWeakReference
*proxy
, PyObject
*value
)
554 if (!proxy_checkref(proxy
))
556 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy
), value
);
563 proxy_length(PyWeakReference
*proxy
)
565 if (!proxy_checkref(proxy
))
567 return PyObject_Length(PyWeakref_GET_OBJECT(proxy
));
570 WRAP_BINARY(proxy_getitem
, PyObject_GetItem
)
573 proxy_setitem(PyWeakReference
*proxy
, PyObject
*key
, PyObject
*value
)
575 if (!proxy_checkref(proxy
))
579 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy
), key
);
581 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy
), key
, value
);
587 proxy_iter(PyWeakReference
*proxy
)
589 if (!proxy_checkref(proxy
))
591 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy
));
595 proxy_iternext(PyWeakReference
*proxy
)
597 if (!proxy_checkref(proxy
))
599 return PyIter_Next(PyWeakref_GET_OBJECT(proxy
));
603 WRAP_METHOD(proxy_unicode
, "__unicode__");
606 static PyMethodDef proxy_methods
[] = {
607 {"__unicode__", (PyCFunction
)proxy_unicode
, METH_NOARGS
},
612 static PyNumberMethods proxy_as_number
= {
613 proxy_add
, /*nb_add*/
614 proxy_sub
, /*nb_subtract*/
615 proxy_mul
, /*nb_multiply*/
616 proxy_div
, /*nb_divide*/
617 proxy_mod
, /*nb_remainder*/
618 proxy_divmod
, /*nb_divmod*/
619 proxy_pow
, /*nb_power*/
620 proxy_neg
, /*nb_negative*/
621 proxy_pos
, /*nb_positive*/
622 proxy_abs
, /*nb_absolute*/
623 (inquiry
)proxy_nonzero
, /*nb_nonzero*/
624 proxy_invert
, /*nb_invert*/
625 proxy_lshift
, /*nb_lshift*/
626 proxy_rshift
, /*nb_rshift*/
627 proxy_and
, /*nb_and*/
628 proxy_xor
, /*nb_xor*/
631 proxy_int
, /*nb_int*/
632 proxy_long
, /*nb_long*/
633 proxy_float
, /*nb_float*/
636 proxy_iadd
, /*nb_inplace_add*/
637 proxy_isub
, /*nb_inplace_subtract*/
638 proxy_imul
, /*nb_inplace_multiply*/
639 proxy_idiv
, /*nb_inplace_divide*/
640 proxy_imod
, /*nb_inplace_remainder*/
641 proxy_ipow
, /*nb_inplace_power*/
642 proxy_ilshift
, /*nb_inplace_lshift*/
643 proxy_irshift
, /*nb_inplace_rshift*/
644 proxy_iand
, /*nb_inplace_and*/
645 proxy_ixor
, /*nb_inplace_xor*/
646 proxy_ior
, /*nb_inplace_or*/
647 proxy_floor_div
, /*nb_floor_divide*/
648 proxy_true_div
, /*nb_true_divide*/
649 proxy_ifloor_div
, /*nb_inplace_floor_divide*/
650 proxy_itrue_div
, /*nb_inplace_true_divide*/
651 proxy_index
, /*nb_index*/
654 static PySequenceMethods proxy_as_sequence
= {
655 (lenfunc
)proxy_length
, /*sq_length*/
659 (ssizessizeargfunc
)proxy_slice
, /*sq_slice*/
661 (ssizessizeobjargproc
)proxy_ass_slice
, /*sq_ass_slice*/
662 (objobjproc
)proxy_contains
, /* sq_contains */
665 static PyMappingMethods proxy_as_mapping
= {
666 (lenfunc
)proxy_length
, /*mp_length*/
667 proxy_getitem
, /*mp_subscript*/
668 (objobjargproc
)proxy_setitem
, /*mp_ass_subscript*/
673 _PyWeakref_ProxyType
= {
674 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
676 sizeof(PyWeakReference
),
679 (destructor
)proxy_dealloc
, /* tp_dealloc */
683 proxy_compare
, /* tp_compare */
684 (reprfunc
)proxy_repr
, /* tp_repr */
685 &proxy_as_number
, /* tp_as_number */
686 &proxy_as_sequence
, /* tp_as_sequence */
687 &proxy_as_mapping
, /* tp_as_mapping */
690 proxy_str
, /* tp_str */
691 proxy_getattr
, /* tp_getattro */
692 (setattrofunc
)proxy_setattr
, /* tp_setattro */
693 0, /* tp_as_buffer */
694 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
695 | Py_TPFLAGS_CHECKTYPES
, /* tp_flags */
697 (traverseproc
)gc_traverse
, /* tp_traverse */
698 (inquiry
)gc_clear
, /* tp_clear */
699 0, /* tp_richcompare */
700 0, /* tp_weaklistoffset */
701 (getiterfunc
)proxy_iter
, /* tp_iter */
702 (iternextfunc
)proxy_iternext
, /* tp_iternext */
703 proxy_methods
, /* tp_methods */
708 _PyWeakref_CallableProxyType
= {
709 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
711 sizeof(PyWeakReference
),
714 (destructor
)proxy_dealloc
, /* tp_dealloc */
718 proxy_compare
, /* tp_compare */
719 (unaryfunc
)proxy_repr
, /* tp_repr */
720 &proxy_as_number
, /* tp_as_number */
721 &proxy_as_sequence
, /* tp_as_sequence */
722 &proxy_as_mapping
, /* tp_as_mapping */
724 proxy_call
, /* tp_call */
725 proxy_str
, /* tp_str */
726 proxy_getattr
, /* tp_getattro */
727 (setattrofunc
)proxy_setattr
, /* tp_setattro */
728 0, /* tp_as_buffer */
729 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
730 | Py_TPFLAGS_CHECKTYPES
, /* tp_flags */
732 (traverseproc
)gc_traverse
, /* tp_traverse */
733 (inquiry
)gc_clear
, /* tp_clear */
734 0, /* tp_richcompare */
735 0, /* tp_weaklistoffset */
736 (getiterfunc
)proxy_iter
, /* tp_iter */
737 (iternextfunc
)proxy_iternext
, /* tp_iternext */
743 PyWeakref_NewRef(PyObject
*ob
, PyObject
*callback
)
745 PyWeakReference
*result
= NULL
;
746 PyWeakReference
**list
;
747 PyWeakReference
*ref
, *proxy
;
749 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob
))) {
750 PyErr_Format(PyExc_TypeError
,
751 "cannot create weak reference to '%s' object",
752 Py_TYPE(ob
)->tp_name
);
755 list
= GET_WEAKREFS_LISTPTR(ob
);
756 get_basic_refs(*list
, &ref
, &proxy
);
757 if (callback
== Py_None
)
759 if (callback
== NULL
)
760 /* return existing weak reference if it exists */
765 /* Note: new_weakref() can trigger cyclic GC, so the weakref
766 list on ob can be mutated. This means that the ref and
767 proxy pointers we got back earlier may have been collected,
768 so we need to compute these values again before we use
770 result
= new_weakref(ob
, callback
);
771 if (result
!= NULL
) {
772 get_basic_refs(*list
, &ref
, &proxy
);
773 if (callback
== NULL
) {
775 insert_head(result
, list
);
777 /* Someone else added a ref without a callback
778 during GC. Return that one instead of this one
779 to avoid violating the invariants of the list
780 of weakrefs for ob. */
787 PyWeakReference
*prev
;
789 prev
= (proxy
== NULL
) ? ref
: proxy
;
791 insert_head(result
, list
);
793 insert_after(result
, prev
);
797 return (PyObject
*) result
;
802 PyWeakref_NewProxy(PyObject
*ob
, PyObject
*callback
)
804 PyWeakReference
*result
= NULL
;
805 PyWeakReference
**list
;
806 PyWeakReference
*ref
, *proxy
;
808 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob
))) {
809 PyErr_Format(PyExc_TypeError
,
810 "cannot create weak reference to '%s' object",
811 Py_TYPE(ob
)->tp_name
);
814 list
= GET_WEAKREFS_LISTPTR(ob
);
815 get_basic_refs(*list
, &ref
, &proxy
);
816 if (callback
== Py_None
)
818 if (callback
== NULL
)
819 /* attempt to return an existing weak reference if it exists */
824 /* Note: new_weakref() can trigger cyclic GC, so the weakref
825 list on ob can be mutated. This means that the ref and
826 proxy pointers we got back earlier may have been collected,
827 so we need to compute these values again before we use
829 result
= new_weakref(ob
, callback
);
830 if (result
!= NULL
) {
831 PyWeakReference
*prev
;
833 if (PyCallable_Check(ob
))
834 Py_TYPE(result
) = &_PyWeakref_CallableProxyType
;
836 Py_TYPE(result
) = &_PyWeakref_ProxyType
;
837 get_basic_refs(*list
, &ref
, &proxy
);
838 if (callback
== NULL
) {
840 /* Someone else added a proxy without a callback
841 during GC. Return that one instead of this one
842 to avoid violating the invariants of the list
843 of weakrefs for ob. */
845 Py_INCREF(result
= proxy
);
851 prev
= (proxy
== NULL
) ? ref
: proxy
;
854 insert_head(result
, list
);
856 insert_after(result
, prev
);
861 return (PyObject
*) result
;
866 PyWeakref_GetObject(PyObject
*ref
)
868 if (ref
== NULL
|| !PyWeakref_Check(ref
)) {
869 PyErr_BadInternalCall();
872 return PyWeakref_GET_OBJECT(ref
);
875 /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
879 handle_callback(PyWeakReference
*ref
, PyObject
*callback
)
881 PyObject
*cbresult
= PyObject_CallFunctionObjArgs(callback
, ref
, NULL
);
883 if (cbresult
== NULL
)
884 PyErr_WriteUnraisable(callback
);
889 /* This function is called by the tp_dealloc handler to clear weak references.
891 * This iterates through the weak references for 'object' and calls callbacks
892 * for those references which have one. It returns when all callbacks have
896 PyObject_ClearWeakRefs(PyObject
*object
)
898 PyWeakReference
**list
;
901 || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object
))
902 || object
->ob_refcnt
!= 0) {
903 PyErr_BadInternalCall();
906 list
= GET_WEAKREFS_LISTPTR(object
);
907 /* Remove the callback-less basic and proxy references */
908 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
) {
909 clear_weakref(*list
);
910 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
)
911 clear_weakref(*list
);
914 PyWeakReference
*current
= *list
;
915 Py_ssize_t count
= _PyWeakref_GetWeakrefCount(current
);
916 int restore_error
= PyErr_Occurred() ? 1 : 0;
917 PyObject
*err_type
, *err_value
, *err_tb
;
920 PyErr_Fetch(&err_type
, &err_value
, &err_tb
);
922 PyObject
*callback
= current
->wr_callback
;
924 current
->wr_callback
= NULL
;
925 clear_weakref(current
);
926 if (callback
!= NULL
) {
927 if (current
->ob_refcnt
> 0)
928 handle_callback(current
, callback
);
936 tuple
= PyTuple_New(count
* 2);
939 PyErr_Fetch(&err_type
, &err_value
, &err_tb
);
943 for (i
= 0; i
< count
; ++i
) {
944 PyWeakReference
*next
= current
->wr_next
;
946 if (current
->ob_refcnt
> 0)
949 PyTuple_SET_ITEM(tuple
, i
* 2, (PyObject
*) current
);
950 PyTuple_SET_ITEM(tuple
, i
* 2 + 1, current
->wr_callback
);
953 Py_DECREF(current
->wr_callback
);
955 current
->wr_callback
= NULL
;
956 clear_weakref(current
);
959 for (i
= 0; i
< count
; ++i
) {
960 PyObject
*callback
= PyTuple_GET_ITEM(tuple
, i
* 2 + 1);
962 /* The tuple may have slots left to NULL */
963 if (callback
!= NULL
) {
964 PyObject
*item
= PyTuple_GET_ITEM(tuple
, i
* 2);
965 handle_callback((PyWeakReference
*)item
, callback
);
971 PyErr_Restore(err_type
, err_value
, err_tb
);