Bump version number to 2.4.2 to pick up the latest minor bug fixes.
[python/dscho.git] / Objects / weakrefobject.c
blobb059080ab42ab78fe74f3b71f5d2394a40ed10d5
1 #include "Python.h"
2 #include "structmember.h"
5 #define GET_WEAKREFS_LISTPTR(o) \
6 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
9 long
10 _PyWeakref_GetWeakrefCount(PyWeakReference *head)
12 long count = 0;
14 while (head != NULL) {
15 ++count;
16 head = head->wr_next;
18 return count;
22 static PyWeakReference *
23 new_weakref(PyObject *ob, PyObject *callback)
25 PyWeakReference *result;
27 result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
28 if (result) {
29 result->hash = -1;
30 result->wr_object = ob;
31 Py_XINCREF(callback);
32 result->wr_callback = callback;
33 PyObject_GC_Track(result);
35 return 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.
44 static void
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));
53 if (*list == 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;
61 self->wr_prev = NULL;
62 self->wr_next = NULL;
63 Py_XDECREF(callback);
68 static void
69 weakref_dealloc(PyWeakReference *self)
71 PyObject_GC_UnTrack((PyObject *)self);
72 clear_weakref(self);
73 PyObject_GC_Del(self);
77 static int
78 gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
80 if (self->wr_callback != NULL)
81 return visit(self->wr_callback, arg);
82 return 0;
86 static int
87 gc_clear(PyWeakReference *self)
89 clear_weakref(self);
90 return 0;
94 static PyObject *
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);
101 Py_INCREF(object);
102 return (object);
104 return NULL;
108 static long
109 weakref_hash(PyWeakReference *self)
111 if (self->hash != -1)
112 return self->hash;
113 if (PyWeakref_GET_OBJECT(self) == Py_None) {
114 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
115 return -1;
117 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
118 return self->hash;
122 static PyObject *
123 weakref_repr(PyWeakReference *self)
125 char buffer[256];
126 if (PyWeakref_GET_OBJECT(self) == Py_None) {
127 PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %lx; dead>",
128 (long)(self));
130 else {
131 PyOS_snprintf(buffer, sizeof(buffer),
132 "<weakref at %#lx; to '%.50s' at %#lx>",
133 (long)(self),
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. */
144 static PyObject *
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;
154 Py_INCREF(res);
155 return res;
157 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
158 PyWeakref_GET_OBJECT(other), op);
162 PyTypeObject
163 _PyWeakref_RefType = {
164 PyObject_HEAD_INIT(&PyType_Type)
166 "weakref",
167 sizeof(PyWeakReference),
169 (destructor)weakref_dealloc,/*tp_dealloc*/
170 0, /*tp_print*/
171 0, /*tp_getattr*/
172 0, /*tp_setattr*/
173 0, /*tp_compare*/
174 (reprfunc)weakref_repr, /*tp_repr*/
175 0, /*tp_as_number*/
176 0, /*tp_as_sequence*/
177 0, /*tp_as_mapping*/
178 (hashfunc)weakref_hash, /*tp_hash*/
179 (ternaryfunc)weakref_call, /*tp_call*/
180 0, /*tp_str*/
181 0, /*tp_getattro*/
182 0, /*tp_setattro*/
183 0, /*tp_as_buffer*/
184 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE,
185 0, /*tp_doc*/
186 (traverseproc)gc_traverse, /*tp_traverse*/
187 (inquiry)gc_clear, /*tp_clear*/
188 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
189 0, /*tp_weaklistoffset*/
193 static int
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");
199 return 0;
201 return 1;
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.
209 #define UNWRAP(o) \
210 if (PyWeakref_CheckProxy(o)) { \
211 if (!proxy_checkref((PyWeakReference *)o)) \
212 return NULL; \
213 o = PyWeakref_GET_OBJECT(o); \
216 #define UNWRAP_I(o) \
217 if (PyWeakref_CheckProxy(o)) { \
218 if (!proxy_checkref((PyWeakReference *)o)) \
219 return -1; \
220 o = PyWeakref_GET_OBJECT(o); \
223 #define WRAP_UNARY(method, generic) \
224 static PyObject * \
225 method(PyObject *proxy) { \
226 UNWRAP(proxy); \
227 return generic(proxy); \
230 #define WRAP_BINARY(method, generic) \
231 static PyObject * \
232 method(PyObject *x, PyObject *y) { \
233 UNWRAP(x); \
234 UNWRAP(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) \
242 static PyObject * \
243 method(PyObject *proxy, PyObject *v, PyObject *w) { \
244 UNWRAP(proxy); \
245 UNWRAP(v); \
246 if (w != NULL) \
247 UNWRAP(w); \
248 return generic(proxy, v, w); \
252 /* direct slots */
254 WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
255 WRAP_UNARY(proxy_str, PyObject_Str)
256 WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
258 static int
259 proxy_print(PyWeakReference *proxy, FILE *fp, int flags)
261 if (!proxy_checkref(proxy))
262 return -1;
263 return PyObject_Print(PyWeakref_GET_OBJECT(proxy), fp, flags);
266 static PyObject *
267 proxy_repr(PyWeakReference *proxy)
269 char buf[160];
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);
278 static int
279 proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
281 if (!proxy_checkref(proxy))
282 return -1;
283 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
286 static int
287 proxy_compare(PyObject *proxy, PyObject *v)
289 UNWRAP_I(proxy);
290 UNWRAP_I(v);
291 return PyObject_Compare(proxy, v);
294 /* number slots */
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)
326 static int
327 proxy_nonzero(PyWeakReference *proxy)
329 PyObject *o = PyWeakref_GET_OBJECT(proxy);
330 if (!proxy_checkref(proxy))
331 return 1;
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);
335 else
336 return 1;
339 /* sequence slots */
341 static PyObject *
342 proxy_slice(PyWeakReference *proxy, int i, int j)
344 if (!proxy_checkref(proxy))
345 return NULL;
346 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
349 static int
350 proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
352 if (!proxy_checkref(proxy))
353 return -1;
354 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
357 static int
358 proxy_contains(PyWeakReference *proxy, PyObject *value)
360 if (!proxy_checkref(proxy))
361 return -1;
362 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
366 /* mapping slots */
368 static int
369 proxy_length(PyWeakReference *proxy)
371 if (!proxy_checkref(proxy))
372 return -1;
373 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
376 WRAP_BINARY(proxy_getitem, PyObject_GetItem)
378 static int
379 proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
381 if (!proxy_checkref(proxy))
382 return -1;
383 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
386 /* iterator slots */
388 static PyObject *
389 proxy_iter(PyWeakReference *proxy)
391 if (!proxy_checkref(proxy))
392 return NULL;
393 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
396 static PyObject *
397 proxy_iternext(PyWeakReference *proxy)
399 if (!proxy_checkref(proxy))
400 return NULL;
401 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
405 static PyNumberMethods proxy_as_number = {
406 (binaryfunc)proxy_add, /*nb_add*/
407 (binaryfunc)proxy_sub, /*nb_subtract*/
408 (binaryfunc)proxy_mul, /*nb_multiply*/
409 (binaryfunc)proxy_div, /*nb_divide*/
410 (binaryfunc)proxy_mod, /*nb_remainder*/
411 (binaryfunc)proxy_divmod, /*nb_divmod*/
412 (ternaryfunc)proxy_pow, /*nb_power*/
413 (unaryfunc)proxy_neg, /*nb_negative*/
414 (unaryfunc)proxy_pos, /*nb_positive*/
415 (unaryfunc)proxy_abs, /*nb_absolute*/
416 (inquiry)proxy_nonzero, /*nb_nonzero*/
417 (unaryfunc)proxy_invert, /*nb_invert*/
418 (binaryfunc)proxy_lshift, /*nb_lshift*/
419 (binaryfunc)proxy_rshift, /*nb_rshift*/
420 (binaryfunc)proxy_and, /*nb_and*/
421 (binaryfunc)proxy_xor, /*nb_xor*/
422 (binaryfunc)proxy_or, /*nb_or*/
423 (coercion)0, /*nb_coerce*/
424 (unaryfunc)proxy_int, /*nb_int*/
425 (unaryfunc)proxy_long, /*nb_long*/
426 (unaryfunc)proxy_float, /*nb_float*/
427 (unaryfunc)0, /*nb_oct*/
428 (unaryfunc)0, /*nb_hex*/
429 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
430 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
431 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
432 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
433 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
434 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
435 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
436 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
437 (binaryfunc)proxy_iand, /*nb_inplace_and*/
438 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
439 (binaryfunc)proxy_ior, /*nb_inplace_or*/
442 static PySequenceMethods proxy_as_sequence = {
443 (inquiry)proxy_length, /*sq_length*/
444 0, /*sq_concat*/
445 0, /*sq_repeat*/
446 0, /*sq_item*/
447 (intintargfunc)proxy_slice, /*sq_slice*/
448 0, /*sq_ass_item*/
449 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
450 (objobjproc)proxy_contains, /* sq_contains */
453 static PyMappingMethods proxy_as_mapping = {
454 (inquiry)proxy_length, /*mp_length*/
455 (binaryfunc)proxy_getitem, /*mp_subscript*/
456 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
460 PyTypeObject
461 _PyWeakref_ProxyType = {
462 PyObject_HEAD_INIT(&PyType_Type)
464 "weakproxy",
465 sizeof(PyWeakReference),
467 /* methods */
468 (destructor)weakref_dealloc, /* tp_dealloc */
469 (printfunc)proxy_print, /* tp_print */
470 0, /* tp_getattr */
471 0, /* tp_setattr */
472 proxy_compare, /* tp_compare */
473 (unaryfunc)proxy_repr, /* tp_repr */
474 &proxy_as_number, /* tp_as_number */
475 &proxy_as_sequence, /* tp_as_sequence */
476 &proxy_as_mapping, /* tp_as_mapping */
477 0, /* tp_hash */
478 (ternaryfunc)0, /* tp_call */
479 (unaryfunc)proxy_str, /* tp_str */
480 (getattrofunc)proxy_getattr, /* tp_getattro */
481 (setattrofunc)proxy_setattr, /* tp_setattro */
482 0, /* tp_as_buffer */
483 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
484 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
485 0, /* tp_doc */
486 (traverseproc)gc_traverse, /* tp_traverse */
487 (inquiry)gc_clear, /* tp_clear */
488 0, /* tp_richcompare */
489 0, /* tp_weaklistoffset */
490 (getiterfunc)proxy_iter, /* tp_iter */
491 (iternextfunc)proxy_iternext, /* tp_iternext */
495 PyTypeObject
496 _PyWeakref_CallableProxyType = {
497 PyObject_HEAD_INIT(&PyType_Type)
499 "weakcallableproxy",
500 sizeof(PyWeakReference),
502 /* methods */
503 (destructor)weakref_dealloc, /* tp_dealloc */
504 (printfunc)proxy_print, /* tp_print */
505 0, /* tp_getattr */
506 0, /* tp_setattr */
507 proxy_compare, /* tp_compare */
508 (unaryfunc)proxy_repr, /* tp_repr */
509 &proxy_as_number, /* tp_as_number */
510 &proxy_as_sequence, /* tp_as_sequence */
511 &proxy_as_mapping, /* tp_as_mapping */
512 0, /* tp_hash */
513 (ternaryfunc)proxy_call, /* tp_call */
514 (unaryfunc)proxy_str, /* tp_str */
515 (getattrofunc)proxy_getattr, /* tp_getattro */
516 (setattrofunc)proxy_setattr, /* tp_setattro */
517 0, /* tp_as_buffer */
518 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
519 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
520 0, /* tp_doc */
521 (traverseproc)gc_traverse, /* tp_traverse */
522 (inquiry)gc_clear, /* tp_clear */
523 0, /* tp_richcompare */
524 0, /* tp_weaklistoffset */
525 (getiterfunc)proxy_iter, /* tp_iter */
526 (iternextfunc)proxy_iternext, /* tp_iternext */
530 /* Given the head of an object's list of weak references, extract the
531 * two callback-less refs (ref and proxy). Used to determine if the
532 * shared references exist and to determine the back link for newly
533 * inserted references.
535 static void
536 get_basic_refs(PyWeakReference *head,
537 PyWeakReference **refp, PyWeakReference **proxyp)
539 *refp = NULL;
540 *proxyp = NULL;
542 if (head != NULL && head->wr_callback == NULL) {
543 if (head->ob_type == &_PyWeakref_RefType) {
544 *refp = head;
545 head = head->wr_next;
547 if (head != NULL && head->wr_callback == NULL) {
548 *proxyp = head;
549 head = head->wr_next;
554 /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
555 static void
556 insert_after(PyWeakReference *newref, PyWeakReference *prev)
558 newref->wr_prev = prev;
559 newref->wr_next = prev->wr_next;
560 if (prev->wr_next != NULL)
561 prev->wr_next->wr_prev = newref;
562 prev->wr_next = newref;
565 /* Insert 'newref' at the head of the list; 'list' points to the variable
566 * that stores the head.
568 static void
569 insert_head(PyWeakReference *newref, PyWeakReference **list)
571 PyWeakReference *next = *list;
573 newref->wr_prev = NULL;
574 newref->wr_next = next;
575 if (next != NULL)
576 next->wr_prev = newref;
577 *list = newref;
581 PyObject *
582 PyWeakref_NewRef(PyObject *ob, PyObject *callback)
584 PyWeakReference *result = NULL;
585 PyWeakReference **list;
586 PyWeakReference *ref, *proxy;
588 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
589 PyErr_Format(PyExc_TypeError,
590 "cannot create weak reference to '%s' object",
591 ob->ob_type->tp_name);
592 return NULL;
594 list = GET_WEAKREFS_LISTPTR(ob);
595 get_basic_refs(*list, &ref, &proxy);
596 if (callback == NULL || callback == Py_None)
597 /* return existing weak reference if it exists */
598 result = ref;
599 if (result != NULL)
600 Py_XINCREF(result);
601 else {
602 result = new_weakref(ob, callback);
603 if (result != NULL) {
604 if (callback == NULL) {
605 insert_head(result, list);
607 else {
608 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
610 if (prev == NULL)
611 insert_head(result, list);
612 else
613 insert_after(result, prev);
617 return (PyObject *) result;
621 PyObject *
622 PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
624 PyWeakReference *result = NULL;
625 PyWeakReference **list;
626 PyWeakReference *ref, *proxy;
628 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
629 PyErr_Format(PyExc_TypeError,
630 "cannot create weak reference to '%s' object",
631 ob->ob_type->tp_name);
632 return NULL;
634 list = GET_WEAKREFS_LISTPTR(ob);
635 get_basic_refs(*list, &ref, &proxy);
636 if (callback == NULL)
637 /* attempt to return an existing weak reference if it exists */
638 result = proxy;
639 if (result != NULL)
640 Py_XINCREF(result);
641 else {
642 result = new_weakref(ob, callback);
643 if (result != NULL) {
644 PyWeakReference *prev;
646 if (PyCallable_Check(ob))
647 result->ob_type = &_PyWeakref_CallableProxyType;
648 else
649 result->ob_type = &_PyWeakref_ProxyType;
650 if (callback == NULL)
651 prev = ref;
652 else
653 prev = (proxy == NULL) ? ref : proxy;
655 if (prev == NULL)
656 insert_head(result, list);
657 else
658 insert_after(result, prev);
661 return (PyObject *) result;
665 PyObject *
666 PyWeakref_GetObject(PyObject *ref)
668 if (ref == NULL || !PyWeakref_Check(ref)) {
669 PyErr_BadInternalCall();
670 return NULL;
672 return PyWeakref_GET_OBJECT(ref);
676 static void
677 handle_callback(PyWeakReference *ref, PyObject *callback)
679 PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
681 if (cbresult == NULL)
682 PyErr_WriteUnraisable(callback);
683 else
684 Py_DECREF(cbresult);
687 /* This function is called by the tp_dealloc handler to clear weak references.
689 * This iterates through the weak references for 'object' and calls callbacks
690 * for those references which have one. It returns when all callbacks have
691 * been attempted.
693 void
694 PyObject_ClearWeakRefs(PyObject *object)
696 PyWeakReference **list;
698 if (object == NULL
699 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
700 || object->ob_refcnt != 0) {
701 PyErr_BadInternalCall();
702 return;
704 list = GET_WEAKREFS_LISTPTR(object);
705 /* Remove the callback-less basic and proxy references */
706 if (*list != NULL && (*list)->wr_callback == NULL) {
707 clear_weakref(*list);
708 if (*list != NULL && (*list)->wr_callback == NULL)
709 clear_weakref(*list);
711 if (*list != NULL) {
712 PyWeakReference *current = *list;
713 int count = _PyWeakref_GetWeakrefCount(current);
714 int restore_error = PyErr_Occurred() ? 1 : 0;
715 PyObject *err_type, *err_value, *err_tb;
717 if (restore_error)
718 PyErr_Fetch(&err_type, &err_value, &err_tb);
719 if (count == 1) {
720 PyObject *callback = current->wr_callback;
722 current->wr_callback = NULL;
723 clear_weakref(current);
724 handle_callback(current, callback);
725 Py_DECREF(callback);
727 else {
728 PyObject *tuple = PyTuple_New(count * 2);
729 int i = 0;
731 for (i = 0; i < count; ++i) {
732 PyWeakReference *next = current->wr_next;
734 Py_INCREF(current);
735 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
736 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
737 current->wr_callback = NULL;
738 clear_weakref(current);
739 current = next;
741 for (i = 0; i < count; ++i) {
742 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
743 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
745 handle_callback((PyWeakReference *)current, callback);
747 Py_DECREF(tuple);
749 if (restore_error)
750 PyErr_Restore(err_type, err_value, err_tb);