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 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(PyWeakReference
*proxy
, PyObject
*v
)
289 if (!proxy_checkref(proxy
))
291 return PyObject_Compare(PyWeakref_GET_OBJECT(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 (cmpfunc
)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 (cmpfunc
)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();
577 if (result
!= NULL
) {
578 Py_XINCREF(callback
);
579 result
->wr_callback
= callback
;
580 result
->wr_object
= ob
;
581 if (callback
== NULL
) {
582 insert_head(result
, list
);
585 PyWeakReference
*prev
= (proxy
== NULL
) ? ref
: proxy
;
588 insert_head(result
, list
);
590 insert_after(result
, prev
);
592 PyObject_GC_Track(result
);
595 return (PyObject
*) result
;
600 PyWeakref_NewProxy(PyObject
*ob
, PyObject
*callback
)
602 PyWeakReference
*result
= NULL
;
603 PyWeakReference
**list
;
604 PyWeakReference
*ref
, *proxy
;
606 if (!PyType_SUPPORTS_WEAKREFS(ob
->ob_type
)) {
607 PyErr_Format(PyExc_TypeError
,
608 "cannot create weak reference to '%s' object",
609 ob
->ob_type
->tp_name
);
612 list
= GET_WEAKREFS_LISTPTR(ob
);
613 get_basic_refs(*list
, &ref
, &proxy
);
614 if (callback
== NULL
)
615 /* attempt to return an existing weak reference if it exists */
620 result
= new_weakref();
621 if (result
!= NULL
) {
622 PyWeakReference
*prev
;
624 if (PyCallable_Check(ob
))
625 result
->ob_type
= &_PyWeakref_CallableProxyType
;
627 result
->ob_type
= &_PyWeakref_ProxyType
;
628 result
->wr_object
= ob
;
629 Py_XINCREF(callback
);
630 result
->wr_callback
= callback
;
631 if (callback
== NULL
)
634 prev
= (proxy
== NULL
) ? ref
: proxy
;
637 insert_head(result
, list
);
639 insert_after(result
, prev
);
640 PyObject_GC_Track(result
);
643 return (PyObject
*) result
;
648 PyWeakref_GetObject(PyObject
*ref
)
650 if (ref
== NULL
|| !PyWeakref_Check(ref
)) {
651 PyErr_BadInternalCall();
654 return PyWeakref_GET_OBJECT(ref
);
659 handle_callback(PyWeakReference
*ref
, PyObject
*callback
)
661 PyObject
*cbresult
= PyObject_CallFunction(callback
, "O", ref
);
663 if (cbresult
== NULL
)
664 PyErr_WriteUnraisable(callback
);
669 /* This function is called by the tp_dealloc handler to clear weak references.
671 * This iterates through the weak references for 'object' and calls callbacks
672 * for those references which have one. It returns when all callbacks have
676 PyObject_ClearWeakRefs(PyObject
*object
)
678 PyWeakReference
**list
;
681 || !PyType_SUPPORTS_WEAKREFS(object
->ob_type
)
682 || object
->ob_refcnt
!= 0) {
683 PyErr_BadInternalCall();
686 list
= GET_WEAKREFS_LISTPTR(object
);
687 /* Remove the callback-less basic and proxy references */
688 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
) {
689 clear_weakref(*list
);
690 if (*list
!= NULL
&& (*list
)->wr_callback
== NULL
)
691 clear_weakref(*list
);
694 PyWeakReference
*current
= *list
;
695 int count
= _PyWeakref_GetWeakrefCount(current
);
696 int restore_error
= PyErr_Occurred() ? 1 : 0;
697 PyObject
*err_type
, *err_value
, *err_tb
;
700 PyErr_Fetch(&err_type
, &err_value
, &err_tb
);
702 PyObject
*callback
= current
->wr_callback
;
704 current
->wr_callback
= NULL
;
705 clear_weakref(current
);
706 handle_callback(current
, callback
);
710 PyObject
*tuple
= PyTuple_New(count
* 2);
713 for (i
= 0; i
< count
; ++i
) {
714 PyWeakReference
*next
= current
->wr_next
;
717 PyTuple_SET_ITEM(tuple
, i
* 2, (PyObject
*) current
);
718 PyTuple_SET_ITEM(tuple
, i
* 2 + 1, current
->wr_callback
);
719 current
->wr_callback
= NULL
;
720 clear_weakref(current
);
723 for (i
= 0; i
< count
; ++i
) {
724 PyObject
*current
= PyTuple_GET_ITEM(tuple
, i
* 2);
725 PyObject
*callback
= PyTuple_GET_ITEM(tuple
, i
* 2 + 1);
727 handle_callback((PyWeakReference
*)current
, callback
);
732 PyErr_Restore(err_type
, err_value
, err_tb
);