2 #include "structmember.h"
5 #define GET_WEAKREFS_LISTPTR(o) \
6 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
8 static PyWeakReference
*
13 _PyWeakref_GetWeakrefCount(PyWeakReference
*head
)
17 while (head
!= NULL
) {
25 static PyWeakReference
*
28 PyWeakReference
*result
;
30 if (free_list
!= NULL
) {
32 free_list
= result
->wr_next
;
33 result
->ob_type
= &_PyWeakref_RefType
;
34 _Py_NewReference((PyObject
*)result
);
37 result
= PyObject_GC_New(PyWeakReference
, &_PyWeakref_RefType
);
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 *list
= self
->wr_next
;
61 self
->wr_object
= Py_None
;
62 self
->wr_callback
= NULL
;
63 if (self
->wr_prev
!= NULL
)
64 self
->wr_prev
->wr_next
= self
->wr_next
;
65 if (self
->wr_next
!= NULL
)
66 self
->wr_next
->wr_prev
= self
->wr_prev
;
75 weakref_dealloc(PyWeakReference
*self
)
77 PyObject_GC_UnTrack((PyObject
*)self
);
79 self
->wr_next
= free_list
;
85 gc_traverse(PyWeakReference
*self
, visitproc visit
, void *arg
)
87 if (self
->wr_callback
!= NULL
)
88 return visit(self
->wr_callback
, arg
);
94 gc_clear(PyWeakReference
*self
)
102 weakref_call(PyWeakReference
*self
, PyObject
*args
, PyObject
*kw
)
104 static char *argnames
[] = {NULL
};
106 if (PyArg_ParseTupleAndKeywords(args
, kw
, ":__call__", argnames
)) {
107 PyObject
*object
= PyWeakref_GET_OBJECT(self
);
116 weakref_hash(PyWeakReference
*self
)
118 if (self
->hash
!= -1)
120 if (PyWeakref_GET_OBJECT(self
) == Py_None
) {
121 PyErr_SetString(PyExc_TypeError
, "weak object has gone away");
124 self
->hash
= PyObject_Hash(PyWeakref_GET_OBJECT(self
));
130 weakref_repr(PyWeakReference
*self
)
133 if (PyWeakref_GET_OBJECT(self
) == Py_None
) {
134 PyOS_snprintf(buffer
, sizeof(buffer
), "<weakref at %lx; dead>",
138 PyOS_snprintf(buffer
, sizeof(buffer
),
139 "<weakref at %#lx; to '%.50s' at %#lx>",
141 PyWeakref_GET_OBJECT(self
)->ob_type
->tp_name
,
142 (long)(PyWeakref_GET_OBJECT(self
)));
144 return PyString_FromString(buffer
);
147 /* Weak references only support equality, not ordering. Two weak references
148 are equal if the underlying objects are equal. If the underlying object has
149 gone away, they are equal if they are identical. */
152 weakref_richcompare(PyWeakReference
* self
, PyWeakReference
* other
, int op
)
154 if (op
!= Py_EQ
|| self
->ob_type
!= other
->ob_type
) {
155 Py_INCREF(Py_NotImplemented
);
156 return Py_NotImplemented
;
158 if (PyWeakref_GET_OBJECT(self
) == Py_None
159 || PyWeakref_GET_OBJECT(other
) == Py_None
) {
160 PyObject
*res
= self
==other
? Py_True
: Py_False
;
164 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self
),
165 PyWeakref_GET_OBJECT(other
), op
);
170 _PyWeakref_RefType
= {
171 PyObject_HEAD_INIT(&PyType_Type
)
174 sizeof(PyWeakReference
),
176 (destructor
)weakref_dealloc
,/*tp_dealloc*/
181 (reprfunc
)weakref_repr
, /*tp_repr*/
183 0, /*tp_as_sequence*/
185 (hashfunc
)weakref_hash
, /*tp_hash*/
186 (ternaryfunc
)weakref_call
, /*tp_call*/
191 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
| Py_TPFLAGS_HAVE_RICHCOMPARE
,
193 (traverseproc
)gc_traverse
, /*tp_traverse*/
194 (inquiry
)gc_clear
, /*tp_clear*/
195 (richcmpfunc
)weakref_richcompare
, /*tp_richcompare*/
196 0, /*tp_weaklistoffset*/
201 proxy_checkref(PyWeakReference
*proxy
)
203 if (PyWeakref_GET_OBJECT(proxy
) == Py_None
) {
204 PyErr_SetString(PyExc_ReferenceError
,
205 "weakly-referenced object no longer exists");
212 /* If a parameter is a proxy, check that it is still "live" and wrap it,
213 * replacing the original value with the raw object. Raises ReferenceError
214 * if the param is a dead proxy.
217 if (PyWeakref_CheckProxy(o)) { \
218 if (!proxy_checkref((PyWeakReference *)o)) \
220 o = PyWeakref_GET_OBJECT(o); \
223 #define UNWRAP_I(o) \
224 if (PyWeakref_CheckProxy(o)) { \
225 if (!proxy_checkref((PyWeakReference *)o)) \
227 o = PyWeakref_GET_OBJECT(o); \
230 #define WRAP_UNARY(method, generic) \
232 method(PyObject *proxy) { \
234 return generic(proxy); \
237 #define WRAP_BINARY(method, generic) \
239 method(PyObject *x, PyObject *y) { \
242 return generic(x, y); \
245 /* Note that the third arg needs to be checked for NULL since the tp_call
246 * slot can receive NULL for this arg.
248 #define WRAP_TERNARY(method, generic) \
250 method(PyObject *proxy, PyObject *v, PyObject *w) { \
255 return generic(proxy, v, w); \
261 WRAP_BINARY(proxy_getattr
, PyObject_GetAttr
)
262 WRAP_UNARY(proxy_str
, PyObject_Str
)
263 WRAP_TERNARY(proxy_call
, PyEval_CallObjectWithKeywords
)
266 proxy_print(PyWeakReference
*proxy
, FILE *fp
, int flags
)
268 if (!proxy_checkref(proxy
))
270 return PyObject_Print(PyWeakref_GET_OBJECT(proxy
), fp
, flags
);
274 proxy_repr(PyWeakReference
*proxy
)
277 PyOS_snprintf(buf
, sizeof(buf
),
278 "<weakref at %p to %.100s at %p>", proxy
,
279 PyWeakref_GET_OBJECT(proxy
)->ob_type
->tp_name
,
280 PyWeakref_GET_OBJECT(proxy
));
281 return PyString_FromString(buf
);
286 proxy_setattr(PyWeakReference
*proxy
, PyObject
*name
, PyObject
*value
)
288 if (!proxy_checkref(proxy
))
290 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy
), name
, value
);
294 proxy_compare(PyObject
*proxy
, PyObject
*v
)
298 return PyObject_Compare(proxy
, v
);
302 WRAP_BINARY(proxy_add
, PyNumber_Add
)
303 WRAP_BINARY(proxy_sub
, PyNumber_Subtract
)
304 WRAP_BINARY(proxy_mul
, PyNumber_Multiply
)
305 WRAP_BINARY(proxy_div
, PyNumber_Divide
)
306 WRAP_BINARY(proxy_mod
, PyNumber_Remainder
)
307 WRAP_BINARY(proxy_divmod
, PyNumber_Divmod
)
308 WRAP_TERNARY(proxy_pow
, PyNumber_Power
)
309 WRAP_UNARY(proxy_neg
, PyNumber_Negative
)
310 WRAP_UNARY(proxy_pos
, PyNumber_Positive
)
311 WRAP_UNARY(proxy_abs
, PyNumber_Absolute
)
312 WRAP_UNARY(proxy_invert
, PyNumber_Invert
)
313 WRAP_BINARY(proxy_lshift
, PyNumber_Lshift
)
314 WRAP_BINARY(proxy_rshift
, PyNumber_Rshift
)
315 WRAP_BINARY(proxy_and
, PyNumber_And
)
316 WRAP_BINARY(proxy_xor
, PyNumber_Xor
)
317 WRAP_BINARY(proxy_or
, PyNumber_Or
)
318 WRAP_UNARY(proxy_int
, PyNumber_Int
)
319 WRAP_UNARY(proxy_long
, PyNumber_Long
)
320 WRAP_UNARY(proxy_float
, PyNumber_Float
)
321 WRAP_BINARY(proxy_iadd
, PyNumber_InPlaceAdd
)
322 WRAP_BINARY(proxy_isub
, PyNumber_InPlaceSubtract
)
323 WRAP_BINARY(proxy_imul
, PyNumber_InPlaceMultiply
)
324 WRAP_BINARY(proxy_idiv
, PyNumber_InPlaceDivide
)
325 WRAP_BINARY(proxy_imod
, PyNumber_InPlaceRemainder
)
326 WRAP_TERNARY(proxy_ipow
, PyNumber_InPlacePower
)
327 WRAP_BINARY(proxy_ilshift
, PyNumber_InPlaceLshift
)
328 WRAP_BINARY(proxy_irshift
, PyNumber_InPlaceRshift
)
329 WRAP_BINARY(proxy_iand
, PyNumber_InPlaceAnd
)
330 WRAP_BINARY(proxy_ixor
, PyNumber_InPlaceXor
)
331 WRAP_BINARY(proxy_ior
, PyNumber_InPlaceOr
)
334 proxy_nonzero(PyWeakReference
*proxy
)
336 PyObject
*o
= PyWeakref_GET_OBJECT(proxy
);
337 if (!proxy_checkref(proxy
))
339 if (o
->ob_type
->tp_as_number
&&
340 o
->ob_type
->tp_as_number
->nb_nonzero
)
341 return (*o
->ob_type
->tp_as_number
->nb_nonzero
)(o
);
349 proxy_slice(PyWeakReference
*proxy
, int i
, int j
)
351 if (!proxy_checkref(proxy
))
353 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
);
357 proxy_ass_slice(PyWeakReference
*proxy
, int i
, int j
, PyObject
*value
)
359 if (!proxy_checkref(proxy
))
361 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
, value
);
365 proxy_contains(PyWeakReference
*proxy
, PyObject
*value
)
367 if (!proxy_checkref(proxy
))
369 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy
), value
);
376 proxy_length(PyWeakReference
*proxy
)
378 if (!proxy_checkref(proxy
))
380 return PyObject_Length(PyWeakref_GET_OBJECT(proxy
));
383 WRAP_BINARY(proxy_getitem
, PyObject_GetItem
)
386 proxy_setitem(PyWeakReference
*proxy
, PyObject
*key
, PyObject
*value
)
388 if (!proxy_checkref(proxy
))
390 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy
), key
, value
);
394 static PyNumberMethods proxy_as_number
= {
395 (binaryfunc
)proxy_add
, /*nb_add*/
396 (binaryfunc
)proxy_sub
, /*nb_subtract*/
397 (binaryfunc
)proxy_mul
, /*nb_multiply*/
398 (binaryfunc
)proxy_div
, /*nb_divide*/
399 (binaryfunc
)proxy_mod
, /*nb_remainder*/
400 (binaryfunc
)proxy_divmod
, /*nb_divmod*/
401 (ternaryfunc
)proxy_pow
, /*nb_power*/
402 (unaryfunc
)proxy_neg
, /*nb_negative*/
403 (unaryfunc
)proxy_pos
, /*nb_positive*/
404 (unaryfunc
)proxy_abs
, /*nb_absolute*/
405 (inquiry
)proxy_nonzero
, /*nb_nonzero*/
406 (unaryfunc
)proxy_invert
, /*nb_invert*/
407 (binaryfunc
)proxy_lshift
, /*nb_lshift*/
408 (binaryfunc
)proxy_rshift
, /*nb_rshift*/
409 (binaryfunc
)proxy_and
, /*nb_and*/
410 (binaryfunc
)proxy_xor
, /*nb_xor*/
411 (binaryfunc
)proxy_or
, /*nb_or*/
412 (coercion
)0, /*nb_coerce*/
413 (unaryfunc
)proxy_int
, /*nb_int*/
414 (unaryfunc
)proxy_long
, /*nb_long*/
415 (unaryfunc
)proxy_float
, /*nb_float*/
416 (unaryfunc
)0, /*nb_oct*/
417 (unaryfunc
)0, /*nb_hex*/
418 (binaryfunc
)proxy_iadd
, /*nb_inplace_add*/
419 (binaryfunc
)proxy_isub
, /*nb_inplace_subtract*/
420 (binaryfunc
)proxy_imul
, /*nb_inplace_multiply*/
421 (binaryfunc
)proxy_idiv
, /*nb_inplace_divide*/
422 (binaryfunc
)proxy_imod
, /*nb_inplace_remainder*/
423 (ternaryfunc
)proxy_ipow
, /*nb_inplace_power*/
424 (binaryfunc
)proxy_ilshift
, /*nb_inplace_lshift*/
425 (binaryfunc
)proxy_irshift
, /*nb_inplace_rshift*/
426 (binaryfunc
)proxy_iand
, /*nb_inplace_and*/
427 (binaryfunc
)proxy_ixor
, /*nb_inplace_xor*/
428 (binaryfunc
)proxy_ior
, /*nb_inplace_or*/
431 static PySequenceMethods proxy_as_sequence
= {
432 (inquiry
)proxy_length
, /*sq_length*/
436 (intintargfunc
)proxy_slice
, /*sq_slice*/
438 (intintobjargproc
)proxy_ass_slice
, /*sq_ass_slice*/
439 (objobjproc
)proxy_contains
, /* sq_contains */
442 static PyMappingMethods proxy_as_mapping
= {
443 (inquiry
)proxy_length
, /*mp_length*/
444 (binaryfunc
)proxy_getitem
, /*mp_subscript*/
445 (objobjargproc
)proxy_setitem
, /*mp_ass_subscript*/
450 _PyWeakref_ProxyType
= {
451 PyObject_HEAD_INIT(&PyType_Type
)
454 sizeof(PyWeakReference
),
457 (destructor
)weakref_dealloc
,/*tp_dealloc*/
458 (printfunc
)proxy_print
, /*tp_print*/
461 proxy_compare
, /*tp_compare*/
462 (unaryfunc
)proxy_repr
, /*tp_repr*/
463 &proxy_as_number
, /*tp_as_number*/
464 &proxy_as_sequence
, /*tp_as_sequence*/
465 &proxy_as_mapping
, /*tp_as_mapping*/
467 (ternaryfunc
)0, /*tp_call*/
468 (unaryfunc
)proxy_str
, /*tp_str*/
469 (getattrofunc
)proxy_getattr
,/*tp_getattro*/
470 (setattrofunc
)proxy_setattr
,/*tp_setattro*/
472 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
473 |Py_TPFLAGS_CHECKTYPES
, /*tp_flags*/
475 (traverseproc
)gc_traverse
, /*tp_traverse*/
476 (inquiry
)gc_clear
, /*tp_clear*/
481 _PyWeakref_CallableProxyType
= {
482 PyObject_HEAD_INIT(&PyType_Type
)
485 sizeof(PyWeakReference
),
488 (destructor
)weakref_dealloc
,/*tp_dealloc*/
489 (printfunc
)proxy_print
, /*tp_print*/
492 proxy_compare
, /*tp_compare*/
493 (unaryfunc
)proxy_repr
, /*tp_repr*/
494 &proxy_as_number
, /*tp_as_number*/
495 &proxy_as_sequence
, /*tp_as_sequence*/
496 &proxy_as_mapping
, /*tp_as_mapping*/
498 (ternaryfunc
)proxy_call
, /*tp_call*/
499 (unaryfunc
)proxy_str
, /*tp_str*/
500 (getattrofunc
)proxy_getattr
,/*tp_getattro*/
501 (setattrofunc
)proxy_setattr
,/*tp_setattro*/
503 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
504 |Py_TPFLAGS_CHECKTYPES
, /*tp_flags*/
506 (traverseproc
)gc_traverse
, /*tp_traverse*/
507 (inquiry
)gc_clear
, /*tp_clear*/
511 /* Given the head of an object's list of weak references, extract the
512 * two callback-less refs (ref and proxy). Used to determine if the
513 * shared references exist and to determine the back link for newly
514 * inserted references.
517 get_basic_refs(PyWeakReference
*head
,
518 PyWeakReference
**refp
, PyWeakReference
**proxyp
)
523 if (head
!= NULL
&& head
->wr_callback
== NULL
) {
524 if (head
->ob_type
== &_PyWeakref_RefType
) {
526 head
= head
->wr_next
;
528 if (head
!= NULL
&& head
->wr_callback
== NULL
) {
530 head
= head
->wr_next
;
535 /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
537 insert_after(PyWeakReference
*newref
, PyWeakReference
*prev
)
539 newref
->wr_prev
= prev
;
540 newref
->wr_next
= prev
->wr_next
;
541 if (prev
->wr_next
!= NULL
)
542 prev
->wr_next
->wr_prev
= newref
;
543 prev
->wr_next
= newref
;
546 /* Insert 'newref' at the head of the list; 'list' points to the variable
547 * that stores the head.
550 insert_head(PyWeakReference
*newref
, PyWeakReference
**list
)
552 PyWeakReference
*next
= *list
;
554 newref
->wr_prev
= NULL
;
555 newref
->wr_next
= next
;
557 next
->wr_prev
= newref
;
563 PyWeakref_NewRef(PyObject
*ob
, PyObject
*callback
)
565 PyWeakReference
*result
= NULL
;
566 PyWeakReference
**list
;
567 PyWeakReference
*ref
, *proxy
;
569 if (!PyType_SUPPORTS_WEAKREFS(ob
->ob_type
)) {
570 PyErr_Format(PyExc_TypeError
,
571 "cannot create weak reference to '%s' object",
572 ob
->ob_type
->tp_name
);
575 list
= GET_WEAKREFS_LISTPTR(ob
);
576 get_basic_refs(*list
, &ref
, &proxy
);
577 if (callback
== NULL
|| callback
== Py_None
)
578 /* return existing weak reference if it exists */
583 result
= new_weakref();
584 if (result
!= NULL
) {
585 Py_XINCREF(callback
);
586 result
->wr_callback
= callback
;
587 result
->wr_object
= ob
;
588 if (callback
== NULL
) {
589 insert_head(result
, list
);
592 PyWeakReference
*prev
= (proxy
== NULL
) ? ref
: proxy
;
595 insert_head(result
, list
);
597 insert_after(result
, prev
);
599 PyObject_GC_Track(result
);
602 return (PyObject
*) result
;
607 PyWeakref_NewProxy(PyObject
*ob
, PyObject
*callback
)
609 PyWeakReference
*result
= NULL
;
610 PyWeakReference
**list
;
611 PyWeakReference
*ref
, *proxy
;
613 if (!PyType_SUPPORTS_WEAKREFS(ob
->ob_type
)) {
614 PyErr_Format(PyExc_TypeError
,
615 "cannot create weak reference to '%s' object",
616 ob
->ob_type
->tp_name
);
619 list
= GET_WEAKREFS_LISTPTR(ob
);
620 get_basic_refs(*list
, &ref
, &proxy
);
621 if (callback
== NULL
)
622 /* attempt to return an existing weak reference if it exists */
627 result
= new_weakref();
628 if (result
!= NULL
) {
629 PyWeakReference
*prev
;
631 if (PyCallable_Check(ob
))
632 result
->ob_type
= &_PyWeakref_CallableProxyType
;
634 result
->ob_type
= &_PyWeakref_ProxyType
;
635 result
->wr_object
= ob
;
636 Py_XINCREF(callback
);
637 result
->wr_callback
= callback
;
638 if (callback
== NULL
)
641 prev
= (proxy
== NULL
) ? ref
: proxy
;
644 insert_head(result
, list
);
646 insert_after(result
, prev
);
647 PyObject_GC_Track(result
);
650 return (PyObject
*) result
;
655 PyWeakref_GetObject(PyObject
*ref
)
657 if (ref
== NULL
|| !PyWeakref_Check(ref
)) {
658 PyErr_BadInternalCall();
661 return PyWeakref_GET_OBJECT(ref
);
666 handle_callback(PyWeakReference
*ref
, PyObject
*callback
)
668 PyObject
*cbresult
= PyObject_CallFunction(callback
, "O", ref
);
670 if (cbresult
== NULL
)
671 PyErr_WriteUnraisable(callback
);
676 /* This function is called by the tp_dealloc handler to clear weak references.
678 * This iterates through the weak references for 'object' and calls callbacks
679 * for those references which have one. It returns when all callbacks have
683 PyObject_ClearWeakRefs(PyObject
*object
)
685 PyWeakReference
**list
;
688 || !PyType_SUPPORTS_WEAKREFS(object
->ob_type
)
689 || object
->ob_refcnt
!= 0) {
690 PyErr_BadInternalCall();
693 list
= GET_WEAKREFS_LISTPTR(object
);
694 /* Remove the callback-less basic and proxy references */
695 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
) {
696 clear_weakref(*list
);
697 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
)
698 clear_weakref(*list
);
701 PyWeakReference
*current
= *list
;
702 int count
= _PyWeakref_GetWeakrefCount(current
);
703 int restore_error
= PyErr_Occurred() ? 1 : 0;
704 PyObject
*err_type
, *err_value
, *err_tb
;
707 PyErr_Fetch(&err_type
, &err_value
, &err_tb
);
709 PyObject
*callback
= current
->wr_callback
;
711 current
->wr_callback
= NULL
;
712 clear_weakref(current
);
713 handle_callback(current
, callback
);
717 PyObject
*tuple
= PyTuple_New(count
* 2);
720 for (i
= 0; i
< count
; ++i
) {
721 PyWeakReference
*next
= current
->wr_next
;
724 PyTuple_SET_ITEM(tuple
, i
* 2, (PyObject
*) current
);
725 PyTuple_SET_ITEM(tuple
, i
* 2 + 1, current
->wr_callback
);
726 current
->wr_callback
= NULL
;
727 clear_weakref(current
);
730 for (i
= 0; i
< count
; ++i
) {
731 PyObject
*current
= PyTuple_GET_ITEM(tuple
, i
* 2);
732 PyObject
*callback
= PyTuple_GET_ITEM(tuple
, i
* 2 + 1);
734 handle_callback((PyWeakReference
*)current
, callback
);
739 PyErr_Restore(err_type
, err_value
, err_tb
);