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
) {
22 static PyWeakReference
*
23 new_weakref(PyObject
*ob
, PyObject
*callback
)
25 PyWeakReference
*result
;
27 result
= PyObject_GC_New(PyWeakReference
, &_PyWeakref_RefType
);
30 result
->wr_object
= ob
;
32 result
->wr_callback
= callback
;
33 PyObject_GC_Track(result
);
39 /* This function clears the passed-in reference and removes it from the
40 * list of weak references for the referent. This is the only code that
41 * removes an item from the doubly-linked list of weak references for an
42 * object; it is also responsible for clearing the callback slot.
45 clear_weakref(PyWeakReference
*self
)
47 PyObject
*callback
= self
->wr_callback
;
49 if (PyWeakref_GET_OBJECT(self
) != Py_None
) {
50 PyWeakReference
**list
= GET_WEAKREFS_LISTPTR(
51 PyWeakref_GET_OBJECT(self
));
54 *list
= self
->wr_next
;
55 self
->wr_object
= Py_None
;
56 self
->wr_callback
= NULL
;
57 if (self
->wr_prev
!= NULL
)
58 self
->wr_prev
->wr_next
= self
->wr_next
;
59 if (self
->wr_next
!= NULL
)
60 self
->wr_next
->wr_prev
= self
->wr_prev
;
69 weakref_dealloc(PyWeakReference
*self
)
71 PyObject_GC_UnTrack((PyObject
*)self
);
73 PyObject_GC_Del(self
);
78 gc_traverse(PyWeakReference
*self
, visitproc visit
, void *arg
)
80 if (self
->wr_callback
!= NULL
)
81 return visit(self
->wr_callback
, arg
);
87 gc_clear(PyWeakReference
*self
)
95 weakref_call(PyWeakReference
*self
, PyObject
*args
, PyObject
*kw
)
97 static char *argnames
[] = {NULL
};
99 if (PyArg_ParseTupleAndKeywords(args
, kw
, ":__call__", argnames
)) {
100 PyObject
*object
= PyWeakref_GET_OBJECT(self
);
109 weakref_hash(PyWeakReference
*self
)
111 if (self
->hash
!= -1)
113 if (PyWeakref_GET_OBJECT(self
) == Py_None
) {
114 PyErr_SetString(PyExc_TypeError
, "weak object has gone away");
117 self
->hash
= PyObject_Hash(PyWeakref_GET_OBJECT(self
));
123 weakref_repr(PyWeakReference
*self
)
126 if (PyWeakref_GET_OBJECT(self
) == Py_None
) {
127 PyOS_snprintf(buffer
, sizeof(buffer
), "<weakref at %lx; dead>",
131 PyOS_snprintf(buffer
, sizeof(buffer
),
132 "<weakref at %#lx; to '%.50s' at %#lx>",
134 PyWeakref_GET_OBJECT(self
)->ob_type
->tp_name
,
135 (long)(PyWeakref_GET_OBJECT(self
)));
137 return PyString_FromString(buffer
);
140 /* Weak references only support equality, not ordering. Two weak references
141 are equal if the underlying objects are equal. If the underlying object has
142 gone away, they are equal if they are identical. */
145 weakref_richcompare(PyWeakReference
* self
, PyWeakReference
* other
, int op
)
147 if (op
!= Py_EQ
|| self
->ob_type
!= other
->ob_type
) {
148 Py_INCREF(Py_NotImplemented
);
149 return Py_NotImplemented
;
151 if (PyWeakref_GET_OBJECT(self
) == Py_None
152 || PyWeakref_GET_OBJECT(other
) == Py_None
) {
153 PyObject
*res
= self
==other
? Py_True
: Py_False
;
157 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self
),
158 PyWeakref_GET_OBJECT(other
), op
);
163 _PyWeakref_RefType
= {
164 PyObject_HEAD_INIT(&PyType_Type
)
167 sizeof(PyWeakReference
),
169 (destructor
)weakref_dealloc
,/*tp_dealloc*/
174 (reprfunc
)weakref_repr
, /*tp_repr*/
176 0, /*tp_as_sequence*/
178 (hashfunc
)weakref_hash
, /*tp_hash*/
179 (ternaryfunc
)weakref_call
, /*tp_call*/
184 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
| Py_TPFLAGS_HAVE_RICHCOMPARE
,
186 (traverseproc
)gc_traverse
, /*tp_traverse*/
187 (inquiry
)gc_clear
, /*tp_clear*/
188 (richcmpfunc
)weakref_richcompare
, /*tp_richcompare*/
189 0, /*tp_weaklistoffset*/
194 proxy_checkref(PyWeakReference
*proxy
)
196 if (PyWeakref_GET_OBJECT(proxy
) == Py_None
) {
197 PyErr_SetString(PyExc_ReferenceError
,
198 "weakly-referenced object no longer exists");
205 /* If a parameter is a proxy, check that it is still "live" and wrap it,
206 * replacing the original value with the raw object. Raises ReferenceError
207 * if the param is a dead proxy.
210 if (PyWeakref_CheckProxy(o)) { \
211 if (!proxy_checkref((PyWeakReference *)o)) \
213 o = PyWeakref_GET_OBJECT(o); \
216 #define UNWRAP_I(o) \
217 if (PyWeakref_CheckProxy(o)) { \
218 if (!proxy_checkref((PyWeakReference *)o)) \
220 o = PyWeakref_GET_OBJECT(o); \
223 #define WRAP_UNARY(method, generic) \
225 method(PyObject *proxy) { \
227 return generic(proxy); \
230 #define WRAP_BINARY(method, generic) \
232 method(PyObject *x, PyObject *y) { \
235 return generic(x, y); \
238 /* Note that the third arg needs to be checked for NULL since the tp_call
239 * slot can receive NULL for this arg.
241 #define WRAP_TERNARY(method, generic) \
243 method(PyObject *proxy, PyObject *v, PyObject *w) { \
248 return generic(proxy, v, w); \
254 WRAP_BINARY(proxy_getattr
, PyObject_GetAttr
)
255 WRAP_UNARY(proxy_str
, PyObject_Str
)
256 WRAP_TERNARY(proxy_call
, PyEval_CallObjectWithKeywords
)
259 proxy_print(PyWeakReference
*proxy
, FILE *fp
, int flags
)
261 if (!proxy_checkref(proxy
))
263 return PyObject_Print(PyWeakref_GET_OBJECT(proxy
), fp
, flags
);
267 proxy_repr(PyWeakReference
*proxy
)
270 PyOS_snprintf(buf
, sizeof(buf
),
271 "<weakref at %p to %.100s at %p>", proxy
,
272 PyWeakref_GET_OBJECT(proxy
)->ob_type
->tp_name
,
273 PyWeakref_GET_OBJECT(proxy
));
274 return PyString_FromString(buf
);
279 proxy_setattr(PyWeakReference
*proxy
, PyObject
*name
, PyObject
*value
)
281 if (!proxy_checkref(proxy
))
283 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy
), name
, value
);
287 proxy_compare(PyObject
*proxy
, PyObject
*v
)
291 return PyObject_Compare(proxy
, v
);
295 WRAP_BINARY(proxy_add
, PyNumber_Add
)
296 WRAP_BINARY(proxy_sub
, PyNumber_Subtract
)
297 WRAP_BINARY(proxy_mul
, PyNumber_Multiply
)
298 WRAP_BINARY(proxy_div
, PyNumber_Divide
)
299 WRAP_BINARY(proxy_mod
, PyNumber_Remainder
)
300 WRAP_BINARY(proxy_divmod
, PyNumber_Divmod
)
301 WRAP_TERNARY(proxy_pow
, PyNumber_Power
)
302 WRAP_UNARY(proxy_neg
, PyNumber_Negative
)
303 WRAP_UNARY(proxy_pos
, PyNumber_Positive
)
304 WRAP_UNARY(proxy_abs
, PyNumber_Absolute
)
305 WRAP_UNARY(proxy_invert
, PyNumber_Invert
)
306 WRAP_BINARY(proxy_lshift
, PyNumber_Lshift
)
307 WRAP_BINARY(proxy_rshift
, PyNumber_Rshift
)
308 WRAP_BINARY(proxy_and
, PyNumber_And
)
309 WRAP_BINARY(proxy_xor
, PyNumber_Xor
)
310 WRAP_BINARY(proxy_or
, PyNumber_Or
)
311 WRAP_UNARY(proxy_int
, PyNumber_Int
)
312 WRAP_UNARY(proxy_long
, PyNumber_Long
)
313 WRAP_UNARY(proxy_float
, PyNumber_Float
)
314 WRAP_BINARY(proxy_iadd
, PyNumber_InPlaceAdd
)
315 WRAP_BINARY(proxy_isub
, PyNumber_InPlaceSubtract
)
316 WRAP_BINARY(proxy_imul
, PyNumber_InPlaceMultiply
)
317 WRAP_BINARY(proxy_idiv
, PyNumber_InPlaceDivide
)
318 WRAP_BINARY(proxy_imod
, PyNumber_InPlaceRemainder
)
319 WRAP_TERNARY(proxy_ipow
, PyNumber_InPlacePower
)
320 WRAP_BINARY(proxy_ilshift
, PyNumber_InPlaceLshift
)
321 WRAP_BINARY(proxy_irshift
, PyNumber_InPlaceRshift
)
322 WRAP_BINARY(proxy_iand
, PyNumber_InPlaceAnd
)
323 WRAP_BINARY(proxy_ixor
, PyNumber_InPlaceXor
)
324 WRAP_BINARY(proxy_ior
, PyNumber_InPlaceOr
)
327 proxy_nonzero(PyWeakReference
*proxy
)
329 PyObject
*o
= PyWeakref_GET_OBJECT(proxy
);
330 if (!proxy_checkref(proxy
))
332 if (o
->ob_type
->tp_as_number
&&
333 o
->ob_type
->tp_as_number
->nb_nonzero
)
334 return (*o
->ob_type
->tp_as_number
->nb_nonzero
)(o
);
342 proxy_slice(PyWeakReference
*proxy
, int i
, int j
)
344 if (!proxy_checkref(proxy
))
346 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
);
350 proxy_ass_slice(PyWeakReference
*proxy
, int i
, int j
, PyObject
*value
)
352 if (!proxy_checkref(proxy
))
354 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy
), i
, j
, value
);
358 proxy_contains(PyWeakReference
*proxy
, PyObject
*value
)
360 if (!proxy_checkref(proxy
))
362 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy
), value
);
369 proxy_length(PyWeakReference
*proxy
)
371 if (!proxy_checkref(proxy
))
373 return PyObject_Length(PyWeakref_GET_OBJECT(proxy
));
376 WRAP_BINARY(proxy_getitem
, PyObject_GetItem
)
379 proxy_setitem(PyWeakReference
*proxy
, PyObject
*key
, PyObject
*value
)
381 if (!proxy_checkref(proxy
))
383 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy
), key
, value
);
387 static PyNumberMethods proxy_as_number
= {
388 (binaryfunc
)proxy_add
, /*nb_add*/
389 (binaryfunc
)proxy_sub
, /*nb_subtract*/
390 (binaryfunc
)proxy_mul
, /*nb_multiply*/
391 (binaryfunc
)proxy_div
, /*nb_divide*/
392 (binaryfunc
)proxy_mod
, /*nb_remainder*/
393 (binaryfunc
)proxy_divmod
, /*nb_divmod*/
394 (ternaryfunc
)proxy_pow
, /*nb_power*/
395 (unaryfunc
)proxy_neg
, /*nb_negative*/
396 (unaryfunc
)proxy_pos
, /*nb_positive*/
397 (unaryfunc
)proxy_abs
, /*nb_absolute*/
398 (inquiry
)proxy_nonzero
, /*nb_nonzero*/
399 (unaryfunc
)proxy_invert
, /*nb_invert*/
400 (binaryfunc
)proxy_lshift
, /*nb_lshift*/
401 (binaryfunc
)proxy_rshift
, /*nb_rshift*/
402 (binaryfunc
)proxy_and
, /*nb_and*/
403 (binaryfunc
)proxy_xor
, /*nb_xor*/
404 (binaryfunc
)proxy_or
, /*nb_or*/
405 (coercion
)0, /*nb_coerce*/
406 (unaryfunc
)proxy_int
, /*nb_int*/
407 (unaryfunc
)proxy_long
, /*nb_long*/
408 (unaryfunc
)proxy_float
, /*nb_float*/
409 (unaryfunc
)0, /*nb_oct*/
410 (unaryfunc
)0, /*nb_hex*/
411 (binaryfunc
)proxy_iadd
, /*nb_inplace_add*/
412 (binaryfunc
)proxy_isub
, /*nb_inplace_subtract*/
413 (binaryfunc
)proxy_imul
, /*nb_inplace_multiply*/
414 (binaryfunc
)proxy_idiv
, /*nb_inplace_divide*/
415 (binaryfunc
)proxy_imod
, /*nb_inplace_remainder*/
416 (ternaryfunc
)proxy_ipow
, /*nb_inplace_power*/
417 (binaryfunc
)proxy_ilshift
, /*nb_inplace_lshift*/
418 (binaryfunc
)proxy_irshift
, /*nb_inplace_rshift*/
419 (binaryfunc
)proxy_iand
, /*nb_inplace_and*/
420 (binaryfunc
)proxy_ixor
, /*nb_inplace_xor*/
421 (binaryfunc
)proxy_ior
, /*nb_inplace_or*/
424 static PySequenceMethods proxy_as_sequence
= {
425 (inquiry
)proxy_length
, /*sq_length*/
429 (intintargfunc
)proxy_slice
, /*sq_slice*/
431 (intintobjargproc
)proxy_ass_slice
, /*sq_ass_slice*/
432 (objobjproc
)proxy_contains
, /* sq_contains */
435 static PyMappingMethods proxy_as_mapping
= {
436 (inquiry
)proxy_length
, /*mp_length*/
437 (binaryfunc
)proxy_getitem
, /*mp_subscript*/
438 (objobjargproc
)proxy_setitem
, /*mp_ass_subscript*/
443 _PyWeakref_ProxyType
= {
444 PyObject_HEAD_INIT(&PyType_Type
)
447 sizeof(PyWeakReference
),
450 (destructor
)weakref_dealloc
,/*tp_dealloc*/
451 (printfunc
)proxy_print
, /*tp_print*/
454 proxy_compare
, /*tp_compare*/
455 (unaryfunc
)proxy_repr
, /*tp_repr*/
456 &proxy_as_number
, /*tp_as_number*/
457 &proxy_as_sequence
, /*tp_as_sequence*/
458 &proxy_as_mapping
, /*tp_as_mapping*/
460 (ternaryfunc
)0, /*tp_call*/
461 (unaryfunc
)proxy_str
, /*tp_str*/
462 (getattrofunc
)proxy_getattr
,/*tp_getattro*/
463 (setattrofunc
)proxy_setattr
,/*tp_setattro*/
465 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
466 |Py_TPFLAGS_CHECKTYPES
, /*tp_flags*/
468 (traverseproc
)gc_traverse
, /*tp_traverse*/
469 (inquiry
)gc_clear
, /*tp_clear*/
474 _PyWeakref_CallableProxyType
= {
475 PyObject_HEAD_INIT(&PyType_Type
)
478 sizeof(PyWeakReference
),
481 (destructor
)weakref_dealloc
,/*tp_dealloc*/
482 (printfunc
)proxy_print
, /*tp_print*/
485 proxy_compare
, /*tp_compare*/
486 (unaryfunc
)proxy_repr
, /*tp_repr*/
487 &proxy_as_number
, /*tp_as_number*/
488 &proxy_as_sequence
, /*tp_as_sequence*/
489 &proxy_as_mapping
, /*tp_as_mapping*/
491 (ternaryfunc
)proxy_call
, /*tp_call*/
492 (unaryfunc
)proxy_str
, /*tp_str*/
493 (getattrofunc
)proxy_getattr
,/*tp_getattro*/
494 (setattrofunc
)proxy_setattr
,/*tp_setattro*/
496 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
497 |Py_TPFLAGS_CHECKTYPES
, /*tp_flags*/
499 (traverseproc
)gc_traverse
, /*tp_traverse*/
500 (inquiry
)gc_clear
, /*tp_clear*/
504 /* Given the head of an object's list of weak references, extract the
505 * two callback-less refs (ref and proxy). Used to determine if the
506 * shared references exist and to determine the back link for newly
507 * inserted references.
510 get_basic_refs(PyWeakReference
*head
,
511 PyWeakReference
**refp
, PyWeakReference
**proxyp
)
516 if (head
!= NULL
&& head
->wr_callback
== NULL
) {
517 if (head
->ob_type
== &_PyWeakref_RefType
) {
519 head
= head
->wr_next
;
521 if (head
!= NULL
&& head
->wr_callback
== NULL
) {
523 head
= head
->wr_next
;
528 /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
530 insert_after(PyWeakReference
*newref
, PyWeakReference
*prev
)
532 newref
->wr_prev
= prev
;
533 newref
->wr_next
= prev
->wr_next
;
534 if (prev
->wr_next
!= NULL
)
535 prev
->wr_next
->wr_prev
= newref
;
536 prev
->wr_next
= newref
;
539 /* Insert 'newref' at the head of the list; 'list' points to the variable
540 * that stores the head.
543 insert_head(PyWeakReference
*newref
, PyWeakReference
**list
)
545 PyWeakReference
*next
= *list
;
547 newref
->wr_prev
= NULL
;
548 newref
->wr_next
= next
;
550 next
->wr_prev
= newref
;
556 PyWeakref_NewRef(PyObject
*ob
, PyObject
*callback
)
558 PyWeakReference
*result
= NULL
;
559 PyWeakReference
**list
;
560 PyWeakReference
*ref
, *proxy
;
562 if (!PyType_SUPPORTS_WEAKREFS(ob
->ob_type
)) {
563 PyErr_Format(PyExc_TypeError
,
564 "cannot create weak reference to '%s' object",
565 ob
->ob_type
->tp_name
);
568 list
= GET_WEAKREFS_LISTPTR(ob
);
569 get_basic_refs(*list
, &ref
, &proxy
);
570 if (callback
== NULL
|| callback
== Py_None
)
571 /* return existing weak reference if it exists */
576 result
= new_weakref(ob
, callback
);
577 if (result
!= NULL
) {
578 if (callback
== NULL
) {
579 insert_head(result
, list
);
582 PyWeakReference
*prev
= (proxy
== NULL
) ? ref
: proxy
;
585 insert_head(result
, list
);
587 insert_after(result
, prev
);
591 return (PyObject
*) result
;
596 PyWeakref_NewProxy(PyObject
*ob
, PyObject
*callback
)
598 PyWeakReference
*result
= NULL
;
599 PyWeakReference
**list
;
600 PyWeakReference
*ref
, *proxy
;
602 if (!PyType_SUPPORTS_WEAKREFS(ob
->ob_type
)) {
603 PyErr_Format(PyExc_TypeError
,
604 "cannot create weak reference to '%s' object",
605 ob
->ob_type
->tp_name
);
608 list
= GET_WEAKREFS_LISTPTR(ob
);
609 get_basic_refs(*list
, &ref
, &proxy
);
610 if (callback
== NULL
)
611 /* attempt to return an existing weak reference if it exists */
616 result
= new_weakref(ob
, callback
);
617 if (result
!= NULL
) {
618 PyWeakReference
*prev
;
620 if (PyCallable_Check(ob
))
621 result
->ob_type
= &_PyWeakref_CallableProxyType
;
623 result
->ob_type
= &_PyWeakref_ProxyType
;
624 if (callback
== NULL
)
627 prev
= (proxy
== NULL
) ? ref
: proxy
;
630 insert_head(result
, list
);
632 insert_after(result
, prev
);
635 return (PyObject
*) result
;
640 PyWeakref_GetObject(PyObject
*ref
)
642 if (ref
== NULL
|| !PyWeakref_Check(ref
)) {
643 PyErr_BadInternalCall();
646 return PyWeakref_GET_OBJECT(ref
);
651 handle_callback(PyWeakReference
*ref
, PyObject
*callback
)
653 PyObject
*cbresult
= PyObject_CallFunction(callback
, "O", ref
);
655 if (cbresult
== NULL
)
656 PyErr_WriteUnraisable(callback
);
661 /* This function is called by the tp_dealloc handler to clear weak references.
663 * This iterates through the weak references for 'object' and calls callbacks
664 * for those references which have one. It returns when all callbacks have
668 PyObject_ClearWeakRefs(PyObject
*object
)
670 PyWeakReference
**list
;
673 || !PyType_SUPPORTS_WEAKREFS(object
->ob_type
)
674 || object
->ob_refcnt
!= 0) {
675 PyErr_BadInternalCall();
678 list
= GET_WEAKREFS_LISTPTR(object
);
679 /* Remove the callback-less basic and proxy references */
680 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
) {
681 clear_weakref(*list
);
682 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
)
683 clear_weakref(*list
);
686 PyWeakReference
*current
= *list
;
687 int count
= _PyWeakref_GetWeakrefCount(current
);
688 int restore_error
= PyErr_Occurred() ? 1 : 0;
689 PyObject
*err_type
, *err_value
, *err_tb
;
692 PyErr_Fetch(&err_type
, &err_value
, &err_tb
);
694 PyObject
*callback
= current
->wr_callback
;
696 current
->wr_callback
= NULL
;
697 clear_weakref(current
);
698 handle_callback(current
, callback
);
702 PyObject
*tuple
= PyTuple_New(count
* 2);
705 for (i
= 0; i
< count
; ++i
) {
706 PyWeakReference
*next
= current
->wr_next
;
709 PyTuple_SET_ITEM(tuple
, i
* 2, (PyObject
*) current
);
710 PyTuple_SET_ITEM(tuple
, i
* 2 + 1, current
->wr_callback
);
711 current
->wr_callback
= NULL
;
712 clear_weakref(current
);
715 for (i
= 0; i
< count
; ++i
) {
716 PyObject
*current
= PyTuple_GET_ITEM(tuple
, i
* 2);
717 PyObject
*callback
= PyTuple_GET_ITEM(tuple
, i
* 2 + 1);
719 handle_callback((PyWeakReference
*)current
, callback
);
724 PyErr_Restore(err_type
, err_value
, err_tb
);