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 (self
->wr_object
!= Py_None
) {
56 PyWeakReference
**list
= GET_WEAKREFS_LISTPTR(self
->wr_object
);
59 /* If 'self' is the end of the list (and thus self->wr_next == NULL)
60 then the weakref list itself (and thus the value of *list) will
61 end up being set to NULL. */
62 *list
= self
->wr_next
;
63 self
->wr_object
= Py_None
;
64 if (self
->wr_prev
!= NULL
)
65 self
->wr_prev
->wr_next
= self
->wr_next
;
66 if (self
->wr_next
!= NULL
)
67 self
->wr_next
->wr_prev
= self
->wr_prev
;
71 if (callback
!= NULL
) {
73 self
->wr_callback
= NULL
;
77 /* Cyclic gc uses this to *just* clear the passed-in reference, leaving
78 * the callback intact and uncalled. It must be possible to call self's
79 * tp_dealloc() after calling this, so self has to be left in a sane enough
80 * state for that to work. We expect tp_dealloc to decref the callback
81 * then. The reason for not letting clear_weakref() decref the callback
82 * right now is that if the callback goes away, that may in turn trigger
83 * another callback (if a weak reference to the callback exists) -- running
84 * arbitrary Python code in the middle of gc is a disaster. The convolution
85 * here allows gc to delay triggering such callbacks until the world is in
89 _PyWeakref_ClearRef(PyWeakReference
*self
)
94 assert(PyWeakref_Check(self
));
95 /* Preserve and restore the callback around clear_weakref. */
96 callback
= self
->wr_callback
;
97 self
->wr_callback
= NULL
;
99 self
->wr_callback
= callback
;
103 weakref_dealloc(PyObject
*self
)
105 PyObject_GC_UnTrack(self
);
106 clear_weakref((PyWeakReference
*) self
);
107 Py_TYPE(self
)->tp_free(self
);
112 gc_traverse(PyWeakReference
*self
, visitproc visit
, void *arg
)
114 Py_VISIT(self
->wr_callback
);
120 gc_clear(PyWeakReference
*self
)
128 weakref_call(PyWeakReference
*self
, PyObject
*args
, PyObject
*kw
)
130 static char *kwlist
[] = {NULL
};
132 if (PyArg_ParseTupleAndKeywords(args
, kw
, ":__call__", kwlist
)) {
133 PyObject
*object
= PyWeakref_GET_OBJECT(self
);
142 weakref_hash(PyWeakReference
*self
)
144 if (self
->hash
!= -1)
146 if (PyWeakref_GET_OBJECT(self
) == Py_None
) {
147 PyErr_SetString(PyExc_TypeError
, "weak object has gone away");
150 self
->hash
= PyObject_Hash(PyWeakref_GET_OBJECT(self
));
156 weakref_repr(PyWeakReference
*self
)
159 if (PyWeakref_GET_OBJECT(self
) == Py_None
) {
160 PyOS_snprintf(buffer
, sizeof(buffer
), "<weakref at %p; dead>", self
);
164 PyObject
*nameobj
= PyObject_GetAttrString(PyWeakref_GET_OBJECT(self
),
168 else if (PyString_Check(nameobj
))
169 name
= PyString_AS_STRING(nameobj
);
171 PyOS_snprintf(buffer
, sizeof(buffer
),
172 "<weakref at %p; to '%.50s' at %p (%s)>",
174 Py_TYPE(PyWeakref_GET_OBJECT(self
))->tp_name
,
175 PyWeakref_GET_OBJECT(self
),
179 PyOS_snprintf(buffer
, sizeof(buffer
),
180 "<weakref at %p; to '%.50s' at %p>",
182 Py_TYPE(PyWeakref_GET_OBJECT(self
))->tp_name
,
183 PyWeakref_GET_OBJECT(self
));
187 return PyString_FromString(buffer
);
190 /* Weak references only support equality, not ordering. Two weak references
191 are equal if the underlying objects are equal. If the underlying object has
192 gone away, they are equal if they are identical. */
195 weakref_richcompare(PyWeakReference
* self
, PyWeakReference
* other
, int op
)
197 if ((op
!= Py_EQ
&& op
!= Py_NE
) || self
->ob_type
!= other
->ob_type
) {
198 Py_INCREF(Py_NotImplemented
);
199 return Py_NotImplemented
;
201 if (PyWeakref_GET_OBJECT(self
) == Py_None
202 || PyWeakref_GET_OBJECT(other
) == Py_None
) {
203 int res
= (self
== other
);
211 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self
),
212 PyWeakref_GET_OBJECT(other
), op
);
215 /* Given the head of an object's list of weak references, extract the
216 * two callback-less refs (ref and proxy). Used to determine if the
217 * shared references exist and to determine the back link for newly
218 * inserted references.
221 get_basic_refs(PyWeakReference
*head
,
222 PyWeakReference
**refp
, PyWeakReference
**proxyp
)
227 if (head
!= NULL
&& head
->wr_callback
== NULL
) {
228 /* We need to be careful that the "basic refs" aren't
229 subclasses of the main types. That complicates this a
231 if (PyWeakref_CheckRefExact(head
)) {
233 head
= head
->wr_next
;
236 && head
->wr_callback
== NULL
237 && PyWeakref_CheckProxy(head
)) {
239 /* head = head->wr_next; */
244 /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
246 insert_after(PyWeakReference
*newref
, PyWeakReference
*prev
)
248 newref
->wr_prev
= prev
;
249 newref
->wr_next
= prev
->wr_next
;
250 if (prev
->wr_next
!= NULL
)
251 prev
->wr_next
->wr_prev
= newref
;
252 prev
->wr_next
= newref
;
255 /* Insert 'newref' at the head of the list; 'list' points to the variable
256 * that stores the head.
259 insert_head(PyWeakReference
*newref
, PyWeakReference
**list
)
261 PyWeakReference
*next
= *list
;
263 newref
->wr_prev
= NULL
;
264 newref
->wr_next
= next
;
266 next
->wr_prev
= newref
;
271 parse_weakref_init_args(char *funcname
, PyObject
*args
, PyObject
*kwargs
,
272 PyObject
**obp
, PyObject
**callbackp
)
274 /* XXX Should check that kwargs == NULL or is empty. */
275 return PyArg_UnpackTuple(args
, funcname
, 1, 2, obp
, callbackp
);
279 weakref___new__(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
281 PyWeakReference
*self
= NULL
;
282 PyObject
*ob
, *callback
= NULL
;
284 if (parse_weakref_init_args("__new__", args
, kwargs
, &ob
, &callback
)) {
285 PyWeakReference
*ref
, *proxy
;
286 PyWeakReference
**list
;
288 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob
))) {
289 PyErr_Format(PyExc_TypeError
,
290 "cannot create weak reference to '%s' object",
291 Py_TYPE(ob
)->tp_name
);
294 if (callback
== Py_None
)
296 list
= GET_WEAKREFS_LISTPTR(ob
);
297 get_basic_refs(*list
, &ref
, &proxy
);
298 if (callback
== NULL
&& type
== &_PyWeakref_RefType
) {
300 /* We can re-use an existing reference. */
302 return (PyObject
*)ref
;
305 /* We have to create a new reference. */
306 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
307 list on ob can be mutated. This means that the ref and
308 proxy pointers we got back earlier may have been collected,
309 so we need to compute these values again before we use
311 self
= (PyWeakReference
*) (type
->tp_alloc(type
, 0));
313 init_weakref(self
, ob
, callback
);
314 if (callback
== NULL
&& type
== &_PyWeakref_RefType
) {
315 insert_head(self
, list
);
318 PyWeakReference
*prev
;
320 get_basic_refs(*list
, &ref
, &proxy
);
321 prev
= (proxy
== NULL
) ? ref
: proxy
;
323 insert_head(self
, list
);
325 insert_after(self
, prev
);
329 return (PyObject
*)self
;
333 weakref___init__(PyObject
*self
, PyObject
*args
, PyObject
*kwargs
)
337 if (parse_weakref_init_args("__init__", args
, kwargs
, &tmp
, &tmp
))
345 _PyWeakref_RefType
= {
346 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
348 sizeof(PyWeakReference
),
350 weakref_dealloc
, /*tp_dealloc*/
355 (reprfunc
)weakref_repr
, /*tp_repr*/
357 0, /*tp_as_sequence*/
359 (hashfunc
)weakref_hash
, /*tp_hash*/
360 (ternaryfunc
)weakref_call
, /*tp_call*/
365 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
| Py_TPFLAGS_HAVE_RICHCOMPARE
366 | Py_TPFLAGS_BASETYPE
, /*tp_flags*/
368 (traverseproc
)gc_traverse
, /*tp_traverse*/
369 (inquiry
)gc_clear
, /*tp_clear*/
370 (richcmpfunc
)weakref_richcompare
, /*tp_richcompare*/
371 0, /*tp_weaklistoffset*/
382 weakref___init__
, /*tp_init*/
383 PyType_GenericAlloc
, /*tp_alloc*/
384 weakref___new__
, /*tp_new*/
385 PyObject_GC_Del
, /*tp_free*/
390 proxy_checkref(PyWeakReference
*proxy
)
392 if (PyWeakref_GET_OBJECT(proxy
) == Py_None
) {
393 PyErr_SetString(PyExc_ReferenceError
,
394 "weakly-referenced object no longer exists");
401 /* If a parameter is a proxy, check that it is still "live" and wrap it,
402 * replacing the original value with the raw object. Raises ReferenceError
403 * if the param is a dead proxy.
406 if (PyWeakref_CheckProxy(o)) { \
407 if (!proxy_checkref((PyWeakReference *)o)) \
409 o = PyWeakref_GET_OBJECT(o); \
412 #define UNWRAP_I(o) \
413 if (PyWeakref_CheckProxy(o)) { \
414 if (!proxy_checkref((PyWeakReference *)o)) \
416 o = PyWeakref_GET_OBJECT(o); \
419 #define WRAP_UNARY(method, generic) \
421 method(PyObject *proxy) { \
423 return generic(proxy); \
426 #define WRAP_BINARY(method, generic) \
428 method(PyObject *x, PyObject *y) { \
431 return generic(x, y); \
434 /* Note that the third arg needs to be checked for NULL since the tp_call
435 * slot can receive NULL for this arg.
437 #define WRAP_TERNARY(method, generic) \
439 method(PyObject *proxy, PyObject *v, PyObject *w) { \
444 return generic(proxy, v, w); \
447 #define WRAP_METHOD(method, special) \
449 method(PyObject *proxy) { \
451 return PyObject_CallMethod(proxy, special, ""); \
457 WRAP_BINARY(proxy_getattr
, PyObject_GetAttr
)
458 WRAP_UNARY(proxy_str
, PyObject_Str
)
459 WRAP_TERNARY(proxy_call
, PyEval_CallObjectWithKeywords
)
462 proxy_repr(PyWeakReference
*proxy
)
465 PyOS_snprintf(buf
, sizeof(buf
),
466 "<weakproxy at %p to %.100s at %p>", proxy
,
467 Py_TYPE(PyWeakref_GET_OBJECT(proxy
))->tp_name
,
468 PyWeakref_GET_OBJECT(proxy
));
469 return PyString_FromString(buf
);
474 proxy_setattr(PyWeakReference
*proxy
, PyObject
*name
, PyObject
*value
)
476 if (!proxy_checkref(proxy
))
478 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy
), name
, value
);
482 proxy_compare(PyObject
*proxy
, PyObject
*v
)
486 return PyObject_Compare(proxy
, v
);
490 WRAP_BINARY(proxy_add
, PyNumber_Add
)
491 WRAP_BINARY(proxy_sub
, PyNumber_Subtract
)
492 WRAP_BINARY(proxy_mul
, PyNumber_Multiply
)
493 WRAP_BINARY(proxy_div
, PyNumber_Divide
)
494 WRAP_BINARY(proxy_floor_div
, PyNumber_FloorDivide
)
495 WRAP_BINARY(proxy_true_div
, PyNumber_TrueDivide
)
496 WRAP_BINARY(proxy_mod
, PyNumber_Remainder
)
497 WRAP_BINARY(proxy_divmod
, PyNumber_Divmod
)
498 WRAP_TERNARY(proxy_pow
, PyNumber_Power
)
499 WRAP_UNARY(proxy_neg
, PyNumber_Negative
)
500 WRAP_UNARY(proxy_pos
, PyNumber_Positive
)
501 WRAP_UNARY(proxy_abs
, PyNumber_Absolute
)
502 WRAP_UNARY(proxy_invert
, PyNumber_Invert
)
503 WRAP_BINARY(proxy_lshift
, PyNumber_Lshift
)
504 WRAP_BINARY(proxy_rshift
, PyNumber_Rshift
)
505 WRAP_BINARY(proxy_and
, PyNumber_And
)
506 WRAP_BINARY(proxy_xor
, PyNumber_Xor
)
507 WRAP_BINARY(proxy_or
, PyNumber_Or
)
508 WRAP_UNARY(proxy_int
, PyNumber_Int
)
509 WRAP_UNARY(proxy_long
, PyNumber_Long
)
510 WRAP_UNARY(proxy_float
, PyNumber_Float
)
511 WRAP_BINARY(proxy_iadd
, PyNumber_InPlaceAdd
)
512 WRAP_BINARY(proxy_isub
, PyNumber_InPlaceSubtract
)
513 WRAP_BINARY(proxy_imul
, PyNumber_InPlaceMultiply
)
514 WRAP_BINARY(proxy_idiv
, PyNumber_InPlaceDivide
)
515 WRAP_BINARY(proxy_ifloor_div
, PyNumber_InPlaceFloorDivide
)
516 WRAP_BINARY(proxy_itrue_div
, PyNumber_InPlaceTrueDivide
)
517 WRAP_BINARY(proxy_imod
, PyNumber_InPlaceRemainder
)
518 WRAP_TERNARY(proxy_ipow
, PyNumber_InPlacePower
)
519 WRAP_BINARY(proxy_ilshift
, PyNumber_InPlaceLshift
)
520 WRAP_BINARY(proxy_irshift
, PyNumber_InPlaceRshift
)
521 WRAP_BINARY(proxy_iand
, PyNumber_InPlaceAnd
)
522 WRAP_BINARY(proxy_ixor
, PyNumber_InPlaceXor
)
523 WRAP_BINARY(proxy_ior
, PyNumber_InPlaceOr
)
524 WRAP_UNARY(proxy_index
, PyNumber_Index
)
527 proxy_nonzero(PyWeakReference
*proxy
)
529 PyObject
*o
= PyWeakref_GET_OBJECT(proxy
);
530 if (!proxy_checkref(proxy
))
532 return PyObject_IsTrue(o
);
536 proxy_dealloc(PyWeakReference
*self
)
538 if (self
->wr_callback
!= NULL
)
539 PyObject_GC_UnTrack((PyObject
*)self
);
541 PyObject_GC_Del(self
);
547 proxy_slice(PyWeakReference
*proxy
, Py_ssize_t i
, Py_ssize_t j
)
549 if (!proxy_checkref(proxy
))
551 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
);
555 proxy_ass_slice(PyWeakReference
*proxy
, Py_ssize_t i
, Py_ssize_t j
, PyObject
*value
)
557 if (!proxy_checkref(proxy
))
559 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
, value
);
563 proxy_contains(PyWeakReference
*proxy
, PyObject
*value
)
565 if (!proxy_checkref(proxy
))
567 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy
), value
);
574 proxy_length(PyWeakReference
*proxy
)
576 if (!proxy_checkref(proxy
))
578 return PyObject_Length(PyWeakref_GET_OBJECT(proxy
));
581 WRAP_BINARY(proxy_getitem
, PyObject_GetItem
)
584 proxy_setitem(PyWeakReference
*proxy
, PyObject
*key
, PyObject
*value
)
586 if (!proxy_checkref(proxy
))
590 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy
), key
);
592 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy
), key
, value
);
598 proxy_iter(PyWeakReference
*proxy
)
600 if (!proxy_checkref(proxy
))
602 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy
));
606 proxy_iternext(PyWeakReference
*proxy
)
608 if (!proxy_checkref(proxy
))
610 return PyIter_Next(PyWeakref_GET_OBJECT(proxy
));
614 WRAP_METHOD(proxy_unicode
, "__unicode__");
617 static PyMethodDef proxy_methods
[] = {
618 {"__unicode__", (PyCFunction
)proxy_unicode
, METH_NOARGS
},
623 static PyNumberMethods proxy_as_number
= {
624 proxy_add
, /*nb_add*/
625 proxy_sub
, /*nb_subtract*/
626 proxy_mul
, /*nb_multiply*/
627 proxy_div
, /*nb_divide*/
628 proxy_mod
, /*nb_remainder*/
629 proxy_divmod
, /*nb_divmod*/
630 proxy_pow
, /*nb_power*/
631 proxy_neg
, /*nb_negative*/
632 proxy_pos
, /*nb_positive*/
633 proxy_abs
, /*nb_absolute*/
634 (inquiry
)proxy_nonzero
, /*nb_nonzero*/
635 proxy_invert
, /*nb_invert*/
636 proxy_lshift
, /*nb_lshift*/
637 proxy_rshift
, /*nb_rshift*/
638 proxy_and
, /*nb_and*/
639 proxy_xor
, /*nb_xor*/
642 proxy_int
, /*nb_int*/
643 proxy_long
, /*nb_long*/
644 proxy_float
, /*nb_float*/
647 proxy_iadd
, /*nb_inplace_add*/
648 proxy_isub
, /*nb_inplace_subtract*/
649 proxy_imul
, /*nb_inplace_multiply*/
650 proxy_idiv
, /*nb_inplace_divide*/
651 proxy_imod
, /*nb_inplace_remainder*/
652 proxy_ipow
, /*nb_inplace_power*/
653 proxy_ilshift
, /*nb_inplace_lshift*/
654 proxy_irshift
, /*nb_inplace_rshift*/
655 proxy_iand
, /*nb_inplace_and*/
656 proxy_ixor
, /*nb_inplace_xor*/
657 proxy_ior
, /*nb_inplace_or*/
658 proxy_floor_div
, /*nb_floor_divide*/
659 proxy_true_div
, /*nb_true_divide*/
660 proxy_ifloor_div
, /*nb_inplace_floor_divide*/
661 proxy_itrue_div
, /*nb_inplace_true_divide*/
662 proxy_index
, /*nb_index*/
665 static PySequenceMethods proxy_as_sequence
= {
666 (lenfunc
)proxy_length
, /*sq_length*/
670 (ssizessizeargfunc
)proxy_slice
, /*sq_slice*/
672 (ssizessizeobjargproc
)proxy_ass_slice
, /*sq_ass_slice*/
673 (objobjproc
)proxy_contains
, /* sq_contains */
676 static PyMappingMethods proxy_as_mapping
= {
677 (lenfunc
)proxy_length
, /*mp_length*/
678 proxy_getitem
, /*mp_subscript*/
679 (objobjargproc
)proxy_setitem
, /*mp_ass_subscript*/
684 _PyWeakref_ProxyType
= {
685 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
687 sizeof(PyWeakReference
),
690 (destructor
)proxy_dealloc
, /* tp_dealloc */
694 proxy_compare
, /* tp_compare */
695 (reprfunc
)proxy_repr
, /* tp_repr */
696 &proxy_as_number
, /* tp_as_number */
697 &proxy_as_sequence
, /* tp_as_sequence */
698 &proxy_as_mapping
, /* tp_as_mapping */
701 proxy_str
, /* tp_str */
702 proxy_getattr
, /* tp_getattro */
703 (setattrofunc
)proxy_setattr
, /* tp_setattro */
704 0, /* tp_as_buffer */
705 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
706 | Py_TPFLAGS_CHECKTYPES
, /* tp_flags */
708 (traverseproc
)gc_traverse
, /* tp_traverse */
709 (inquiry
)gc_clear
, /* tp_clear */
710 0, /* tp_richcompare */
711 0, /* tp_weaklistoffset */
712 (getiterfunc
)proxy_iter
, /* tp_iter */
713 (iternextfunc
)proxy_iternext
, /* tp_iternext */
714 proxy_methods
, /* tp_methods */
719 _PyWeakref_CallableProxyType
= {
720 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
722 sizeof(PyWeakReference
),
725 (destructor
)proxy_dealloc
, /* tp_dealloc */
729 proxy_compare
, /* tp_compare */
730 (unaryfunc
)proxy_repr
, /* tp_repr */
731 &proxy_as_number
, /* tp_as_number */
732 &proxy_as_sequence
, /* tp_as_sequence */
733 &proxy_as_mapping
, /* tp_as_mapping */
735 proxy_call
, /* tp_call */
736 proxy_str
, /* tp_str */
737 proxy_getattr
, /* tp_getattro */
738 (setattrofunc
)proxy_setattr
, /* tp_setattro */
739 0, /* tp_as_buffer */
740 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
741 | Py_TPFLAGS_CHECKTYPES
, /* tp_flags */
743 (traverseproc
)gc_traverse
, /* tp_traverse */
744 (inquiry
)gc_clear
, /* tp_clear */
745 0, /* tp_richcompare */
746 0, /* tp_weaklistoffset */
747 (getiterfunc
)proxy_iter
, /* tp_iter */
748 (iternextfunc
)proxy_iternext
, /* tp_iternext */
754 PyWeakref_NewRef(PyObject
*ob
, PyObject
*callback
)
756 PyWeakReference
*result
= NULL
;
757 PyWeakReference
**list
;
758 PyWeakReference
*ref
, *proxy
;
760 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob
))) {
761 PyErr_Format(PyExc_TypeError
,
762 "cannot create weak reference to '%s' object",
763 Py_TYPE(ob
)->tp_name
);
766 list
= GET_WEAKREFS_LISTPTR(ob
);
767 get_basic_refs(*list
, &ref
, &proxy
);
768 if (callback
== Py_None
)
770 if (callback
== NULL
)
771 /* return existing weak reference if it exists */
776 /* Note: new_weakref() can trigger cyclic GC, so the weakref
777 list on ob can be mutated. This means that the ref and
778 proxy pointers we got back earlier may have been collected,
779 so we need to compute these values again before we use
781 result
= new_weakref(ob
, callback
);
782 if (result
!= NULL
) {
783 get_basic_refs(*list
, &ref
, &proxy
);
784 if (callback
== NULL
) {
786 insert_head(result
, list
);
788 /* Someone else added a ref without a callback
789 during GC. Return that one instead of this one
790 to avoid violating the invariants of the list
791 of weakrefs for ob. */
798 PyWeakReference
*prev
;
800 prev
= (proxy
== NULL
) ? ref
: proxy
;
802 insert_head(result
, list
);
804 insert_after(result
, prev
);
808 return (PyObject
*) result
;
813 PyWeakref_NewProxy(PyObject
*ob
, PyObject
*callback
)
815 PyWeakReference
*result
= NULL
;
816 PyWeakReference
**list
;
817 PyWeakReference
*ref
, *proxy
;
819 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob
))) {
820 PyErr_Format(PyExc_TypeError
,
821 "cannot create weak reference to '%s' object",
822 Py_TYPE(ob
)->tp_name
);
825 list
= GET_WEAKREFS_LISTPTR(ob
);
826 get_basic_refs(*list
, &ref
, &proxy
);
827 if (callback
== Py_None
)
829 if (callback
== NULL
)
830 /* attempt to return an existing weak reference if it exists */
835 /* Note: new_weakref() can trigger cyclic GC, so the weakref
836 list on ob can be mutated. This means that the ref and
837 proxy pointers we got back earlier may have been collected,
838 so we need to compute these values again before we use
840 result
= new_weakref(ob
, callback
);
841 if (result
!= NULL
) {
842 PyWeakReference
*prev
;
844 if (PyCallable_Check(ob
))
845 Py_TYPE(result
) = &_PyWeakref_CallableProxyType
;
847 Py_TYPE(result
) = &_PyWeakref_ProxyType
;
848 get_basic_refs(*list
, &ref
, &proxy
);
849 if (callback
== NULL
) {
851 /* Someone else added a proxy without a callback
852 during GC. Return that one instead of this one
853 to avoid violating the invariants of the list
854 of weakrefs for ob. */
856 Py_INCREF(result
= proxy
);
862 prev
= (proxy
== NULL
) ? ref
: proxy
;
865 insert_head(result
, list
);
867 insert_after(result
, prev
);
872 return (PyObject
*) result
;
877 PyWeakref_GetObject(PyObject
*ref
)
879 if (ref
== NULL
|| !PyWeakref_Check(ref
)) {
880 PyErr_BadInternalCall();
883 return PyWeakref_GET_OBJECT(ref
);
886 /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
890 handle_callback(PyWeakReference
*ref
, PyObject
*callback
)
892 PyObject
*cbresult
= PyObject_CallFunctionObjArgs(callback
, ref
, NULL
);
894 if (cbresult
== NULL
)
895 PyErr_WriteUnraisable(callback
);
900 /* This function is called by the tp_dealloc handler to clear weak references.
902 * This iterates through the weak references for 'object' and calls callbacks
903 * for those references which have one. It returns when all callbacks have
907 PyObject_ClearWeakRefs(PyObject
*object
)
909 PyWeakReference
**list
;
912 || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object
))
913 || object
->ob_refcnt
!= 0) {
914 PyErr_BadInternalCall();
917 list
= GET_WEAKREFS_LISTPTR(object
);
918 /* Remove the callback-less basic and proxy references */
919 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
) {
920 clear_weakref(*list
);
921 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
)
922 clear_weakref(*list
);
925 PyWeakReference
*current
= *list
;
926 Py_ssize_t count
= _PyWeakref_GetWeakrefCount(current
);
927 PyObject
*err_type
, *err_value
, *err_tb
;
929 PyErr_Fetch(&err_type
, &err_value
, &err_tb
);
931 PyObject
*callback
= current
->wr_callback
;
933 current
->wr_callback
= NULL
;
934 clear_weakref(current
);
935 if (callback
!= NULL
) {
936 if (current
->ob_refcnt
> 0)
937 handle_callback(current
, callback
);
945 tuple
= PyTuple_New(count
* 2);
947 _PyErr_ReplaceException(err_type
, err_value
, err_tb
);
951 for (i
= 0; i
< count
; ++i
) {
952 PyWeakReference
*next
= current
->wr_next
;
954 if (current
->ob_refcnt
> 0)
957 PyTuple_SET_ITEM(tuple
, i
* 2, (PyObject
*) current
);
958 PyTuple_SET_ITEM(tuple
, i
* 2 + 1, current
->wr_callback
);
961 Py_DECREF(current
->wr_callback
);
963 current
->wr_callback
= NULL
;
964 clear_weakref(current
);
967 for (i
= 0; i
< count
; ++i
) {
968 PyObject
*callback
= PyTuple_GET_ITEM(tuple
, i
* 2 + 1);
970 /* The tuple may have slots left to NULL */
971 if (callback
!= NULL
) {
972 PyObject
*item
= PyTuple_GET_ITEM(tuple
, i
* 2);
973 handle_callback((PyWeakReference
*)item
, callback
);
978 assert(!PyErr_Occurred());
979 PyErr_Restore(err_type
, err_value
, err_tb
);