blob: 56ecfb3a731b541b9db779d4b3275b08e4fd98b1 [file] [log] [blame]
Fred Drake8844d522001-10-05 21:52:26 +00001#include "Python.h"
2#include "structmember.h"
3
4
5#define GET_WEAKREFS_LISTPTR(o) \
6 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
7
8static PyWeakReference *
9free_list = NULL;
10
11
12long
13_PyWeakref_GetWeakrefCount(PyWeakReference *head)
14{
15 long count = 0;
16
17 while (head != NULL) {
18 ++count;
19 head = head->wr_next;
20 }
21 return count;
22}
23
24
25static PyWeakReference *
26new_weakref(void)
27{
28 PyWeakReference *result;
29
30 if (free_list != NULL) {
31 result = free_list;
32 free_list = result->wr_next;
33 result->ob_type = &_PyWeakref_RefType;
34 _Py_NewReference((PyObject *)result);
35 }
36 else {
37 result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
38 }
39 if (result)
40 result->hash = -1;
41 return result;
42}
43
44
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.
49 */
50static void
51clear_weakref(PyWeakReference *self)
52{
53 PyObject *callback = self->wr_callback;
54
55 if (PyWeakref_GET_OBJECT(self) != Py_None) {
56 PyWeakReference **list = GET_WEAKREFS_LISTPTR(
57 PyWeakref_GET_OBJECT(self));
58
59 if (*list == 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;
67 self->wr_prev = NULL;
68 self->wr_next = NULL;
69 Py_XDECREF(callback);
70 }
71}
72
73
74static void
75weakref_dealloc(PyWeakReference *self)
76{
77 PyObject_GC_UnTrack((PyObject *)self);
78 clear_weakref(self);
79 self->wr_next = free_list;
80 free_list = self;
81}
82
83
84static int
85gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
86{
87 if (self->wr_callback != NULL)
88 return visit(self->wr_callback, arg);
89 return 0;
90}
91
92
93static int
94gc_clear(PyWeakReference *self)
95{
96 clear_weakref(self);
97 return 0;
98}
99
100
101static PyObject *
102weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
103{
104 static char *argnames[] = {NULL};
105
106 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) {
107 PyObject *object = PyWeakref_GET_OBJECT(self);
108 Py_INCREF(object);
109 return (object);
110 }
111 return NULL;
112}
113
114
115static long
116weakref_hash(PyWeakReference *self)
117{
118 if (self->hash != -1)
119 return self->hash;
120 if (PyWeakref_GET_OBJECT(self) == Py_None) {
121 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
122 return -1;
123 }
124 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
125 return self->hash;
126}
127
128
129static PyObject *
130weakref_repr(PyWeakReference *self)
131{
132 char buffer[256];
133 if (PyWeakref_GET_OBJECT(self) == Py_None) {
134 sprintf(buffer, "<weakref at %lx; dead>",
135 (long)(self));
136 }
137 else {
138 sprintf(buffer, "<weakref at %#lx; to '%s' at %#lx>",
139 (long)(self), PyWeakref_GET_OBJECT(self)->ob_type->tp_name,
140 (long)(PyWeakref_GET_OBJECT(self)));
141 }
142 return PyString_FromString(buffer);
143}
144
145/* Weak references only support equality, not ordering. Two weak references
146 are equal if the underlying objects are equal. If the underlying object has
147 gone away, they are equal if they are identical. */
148
149static PyObject *
150weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
151{
152 if (op != Py_EQ || self->ob_type != other->ob_type) {
153 Py_INCREF(Py_NotImplemented);
154 return Py_NotImplemented;
155 }
156 if (PyWeakref_GET_OBJECT(self) == Py_None
157 || PyWeakref_GET_OBJECT(other) == Py_None) {
158 PyObject *res = self==other ? Py_True : Py_False;
159 Py_INCREF(res);
160 return res;
161 }
162 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
163 PyWeakref_GET_OBJECT(other), op);
164}
165
166
167PyTypeObject
168_PyWeakref_RefType = {
169 PyObject_HEAD_INIT(&PyType_Type)
170 0,
171 "weakref",
172 sizeof(PyWeakReference),
173 0,
174 (destructor)weakref_dealloc,/*tp_dealloc*/
175 0, /*tp_print*/
176 0, /*tp_getattr*/
177 0, /*tp_setattr*/
178 0, /*tp_compare*/
179 (reprfunc)weakref_repr, /*tp_repr*/
180 0, /*tp_as_number*/
181 0, /*tp_as_sequence*/
182 0, /*tp_as_mapping*/
183 (hashfunc)weakref_hash, /*tp_hash*/
184 (ternaryfunc)weakref_call, /*tp_call*/
185 0, /*tp_str*/
186 0, /*tp_getattro*/
187 0, /*tp_setattro*/
188 0, /*tp_as_buffer*/
189 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE,
190 0, /*tp_doc*/
191 (traverseproc)gc_traverse, /*tp_traverse*/
192 (inquiry)gc_clear, /*tp_clear*/
193 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
194 0, /*tp_weaklistoffset*/
195};
196
197
198static int
199proxy_checkref(PyWeakReference *proxy)
200{
201 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
202 PyErr_SetString(PyExc_ReferenceError,
203 "weakly-referenced object no longer exists");
204 return 0;
205 }
206 return 1;
207}
208
209
210#define WRAP_UNARY(method, generic) \
211 static PyObject * \
212 method(PyWeakReference *proxy) { \
213 if (!proxy_checkref(proxy)) { \
214 return NULL; \
215 } \
216 return generic(PyWeakref_GET_OBJECT(proxy)); \
217 }
218
219#define WRAP_BINARY(method, generic) \
220 static PyObject * \
221 method(PyWeakReference *proxy, PyObject *v) { \
222 if (!proxy_checkref(proxy)) { \
223 return NULL; \
224 } \
225 return generic(PyWeakref_GET_OBJECT(proxy), v); \
226 }
227
228#define WRAP_TERNARY(method, generic) \
229 static PyObject * \
230 method(PyWeakReference *proxy, PyObject *v, PyObject *w) { \
231 if (!proxy_checkref(proxy)) { \
232 return NULL; \
233 } \
234 return generic(PyWeakref_GET_OBJECT(proxy), v, w); \
235 }
236
237
238/* direct slots */
239
240WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
241WRAP_UNARY(proxy_str, PyObject_Str)
242WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
243
244static int
245proxy_print(PyWeakReference *proxy, FILE *fp, int flags)
246{
247 if (!proxy_checkref(proxy))
248 return -1;
249 return PyObject_Print(PyWeakref_GET_OBJECT(proxy), fp, flags);
250}
251
252static PyObject *
253proxy_repr(PyWeakReference *proxy)
254{
255 char buf[160];
256 sprintf(buf, "<weakref at %p to %.100s at %p>", proxy,
257 PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
258 PyWeakref_GET_OBJECT(proxy));
259 return PyString_FromString(buf);
260}
261
262
263static int
264proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
265{
266 if (!proxy_checkref(proxy))
267 return -1;
268 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
269}
270
271static int
272proxy_compare(PyWeakReference *proxy, PyObject *v)
273{
274 if (!proxy_checkref(proxy))
275 return -1;
276 return PyObject_Compare(PyWeakref_GET_OBJECT(proxy), v);
277}
278
279/* number slots */
280WRAP_BINARY(proxy_add, PyNumber_Add)
281WRAP_BINARY(proxy_sub, PyNumber_Subtract)
282WRAP_BINARY(proxy_mul, PyNumber_Multiply)
283WRAP_BINARY(proxy_div, PyNumber_Divide)
284WRAP_BINARY(proxy_mod, PyNumber_Remainder)
285WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
286WRAP_TERNARY(proxy_pow, PyNumber_Power)
287WRAP_UNARY(proxy_neg, PyNumber_Negative)
288WRAP_UNARY(proxy_pos, PyNumber_Positive)
289WRAP_UNARY(proxy_abs, PyNumber_Absolute)
290WRAP_UNARY(proxy_invert, PyNumber_Invert)
291WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
292WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
293WRAP_BINARY(proxy_and, PyNumber_And)
294WRAP_BINARY(proxy_xor, PyNumber_Xor)
295WRAP_BINARY(proxy_or, PyNumber_Or)
296WRAP_UNARY(proxy_int, PyNumber_Int)
297WRAP_UNARY(proxy_long, PyNumber_Long)
298WRAP_UNARY(proxy_float, PyNumber_Float)
299WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
300WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
301WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
302WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
303WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
304WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
305WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
306WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
307WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
308WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
309WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
310
311static int
312proxy_nonzero(PyWeakReference *proxy)
313{
314 PyObject *o = PyWeakref_GET_OBJECT(proxy);
315 if (!proxy_checkref(proxy))
316 return 1;
317 if (o->ob_type->tp_as_number &&
318 o->ob_type->tp_as_number->nb_nonzero)
319 return (*o->ob_type->tp_as_number->nb_nonzero)(o);
320 else
321 return 1;
322}
323
324/* sequence slots */
325
326static PyObject *
327proxy_slice(PyWeakReference *proxy, int i, int j)
328{
329 if (!proxy_checkref(proxy))
330 return NULL;
331 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
332}
333
334static int
335proxy_ass_slice(PyWeakReference *proxy, int i, int j, PyObject *value)
336{
337 if (!proxy_checkref(proxy))
338 return -1;
339 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
340}
341
342static int
343proxy_contains(PyWeakReference *proxy, PyObject *value)
344{
345 if (!proxy_checkref(proxy))
346 return -1;
347 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
348}
349
350
351/* mapping slots */
352
353static int
354proxy_length(PyWeakReference *proxy)
355{
356 if (!proxy_checkref(proxy))
357 return -1;
358 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
359}
360
361WRAP_BINARY(proxy_getitem, PyObject_GetItem)
362
363static int
364proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
365{
366 if (!proxy_checkref(proxy))
367 return -1;
368 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
369}
370
371
372static PyNumberMethods proxy_as_number = {
373 (binaryfunc)proxy_add, /*nb_add*/
374 (binaryfunc)proxy_sub, /*nb_subtract*/
375 (binaryfunc)proxy_mul, /*nb_multiply*/
376 (binaryfunc)proxy_div, /*nb_divide*/
377 (binaryfunc)proxy_mod, /*nb_remainder*/
378 (binaryfunc)proxy_divmod, /*nb_divmod*/
379 (ternaryfunc)proxy_pow, /*nb_power*/
380 (unaryfunc)proxy_neg, /*nb_negative*/
381 (unaryfunc)proxy_pos, /*nb_positive*/
382 (unaryfunc)proxy_abs, /*nb_absolute*/
383 (inquiry)proxy_nonzero, /*nb_nonzero*/
384 (unaryfunc)proxy_invert, /*nb_invert*/
385 (binaryfunc)proxy_lshift, /*nb_lshift*/
386 (binaryfunc)proxy_rshift, /*nb_rshift*/
387 (binaryfunc)proxy_and, /*nb_and*/
388 (binaryfunc)proxy_xor, /*nb_xor*/
389 (binaryfunc)proxy_or, /*nb_or*/
390 (coercion)0, /*nb_coerce*/
391 (unaryfunc)proxy_int, /*nb_int*/
392 (unaryfunc)proxy_long, /*nb_long*/
393 (unaryfunc)proxy_float, /*nb_float*/
394 (unaryfunc)0, /*nb_oct*/
395 (unaryfunc)0, /*nb_hex*/
396 (binaryfunc)proxy_iadd, /*nb_inplace_add*/
397 (binaryfunc)proxy_isub, /*nb_inplace_subtract*/
398 (binaryfunc)proxy_imul, /*nb_inplace_multiply*/
399 (binaryfunc)proxy_idiv, /*nb_inplace_divide*/
400 (binaryfunc)proxy_imod, /*nb_inplace_remainder*/
401 (ternaryfunc)proxy_ipow, /*nb_inplace_power*/
402 (binaryfunc)proxy_ilshift, /*nb_inplace_lshift*/
403 (binaryfunc)proxy_irshift, /*nb_inplace_rshift*/
404 (binaryfunc)proxy_iand, /*nb_inplace_and*/
405 (binaryfunc)proxy_ixor, /*nb_inplace_xor*/
406 (binaryfunc)proxy_ior, /*nb_inplace_or*/
407};
408
409static PySequenceMethods proxy_as_sequence = {
410 (inquiry)proxy_length, /*sq_length*/
411 0, /*sq_concat*/
412 0, /*sq_repeat*/
413 0, /*sq_item*/
414 (intintargfunc)proxy_slice, /*sq_slice*/
415 0, /*sq_ass_item*/
416 (intintobjargproc)proxy_ass_slice, /*sq_ass_slice*/
417 (objobjproc)proxy_contains, /* sq_contains */
418};
419
420static PyMappingMethods proxy_as_mapping = {
421 (inquiry)proxy_length, /*mp_length*/
422 (binaryfunc)proxy_getitem, /*mp_subscript*/
423 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
424};
425
426
427PyTypeObject
428_PyWeakref_ProxyType = {
429 PyObject_HEAD_INIT(&PyType_Type)
430 0,
431 "weakproxy",
432 sizeof(PyWeakReference),
433 0,
434 /* methods */
435 (destructor)weakref_dealloc,/*tp_dealloc*/
436 (printfunc)proxy_print, /*tp_print*/
437 0, /*tp_getattr*/
438 0, /*tp_setattr*/
439 (cmpfunc)proxy_compare, /*tp_compare*/
440 (unaryfunc)proxy_repr, /*tp_repr*/
441 &proxy_as_number, /*tp_as_number*/
442 &proxy_as_sequence, /*tp_as_sequence*/
443 &proxy_as_mapping, /*tp_as_mapping*/
444 0, /*tp_hash*/
445 (ternaryfunc)0, /*tp_call*/
446 (unaryfunc)proxy_str, /*tp_str*/
447 (getattrofunc)proxy_getattr,/*tp_getattro*/
448 (setattrofunc)proxy_setattr,/*tp_setattro*/
449 0, /*tp_as_buffer*/
450 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
451 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
452 0, /*tp_doc*/
453 (traverseproc)gc_traverse, /*tp_traverse*/
454 (inquiry)gc_clear, /*tp_clear*/
455};
456
457
458PyTypeObject
459_PyWeakref_CallableProxyType = {
460 PyObject_HEAD_INIT(&PyType_Type)
461 0,
462 "weakcallableproxy",
463 sizeof(PyWeakReference),
464 0,
465 /* methods */
466 (destructor)weakref_dealloc,/*tp_dealloc*/
467 (printfunc)proxy_print, /*tp_print*/
468 0, /*tp_getattr*/
469 0, /*tp_setattr*/
470 (cmpfunc)proxy_compare, /*tp_compare*/
471 (unaryfunc)proxy_repr, /*tp_repr*/
472 &proxy_as_number, /*tp_as_number*/
473 &proxy_as_sequence, /*tp_as_sequence*/
474 &proxy_as_mapping, /*tp_as_mapping*/
475 0, /*tp_hash*/
476 (ternaryfunc)proxy_call, /*tp_call*/
477 (unaryfunc)proxy_str, /*tp_str*/
478 (getattrofunc)proxy_getattr,/*tp_getattro*/
479 (setattrofunc)proxy_setattr,/*tp_setattro*/
480 0, /*tp_as_buffer*/
481 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
482 |Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
483 0, /*tp_doc*/
484 (traverseproc)gc_traverse, /*tp_traverse*/
485 (inquiry)gc_clear, /*tp_clear*/
486};
487
488
489/* Given the head of an object's list of weak references, extract the
490 * two callback-less refs (ref and proxy). Used to determine if the
491 * shared references exist and to determine the back link for newly
492 * inserted references.
493 */
494static void
495get_basic_refs(PyWeakReference *head,
496 PyWeakReference **refp, PyWeakReference **proxyp)
497{
498 *refp = NULL;
499 *proxyp = NULL;
500
501 if (head != NULL && head->wr_callback == NULL) {
502 if (head->ob_type == &_PyWeakref_RefType) {
503 *refp = head;
504 head = head->wr_next;
505 }
506 if (head != NULL && head->wr_callback == NULL) {
507 *proxyp = head;
508 head = head->wr_next;
509 }
510 }
511}
512
513/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
514static void
515insert_after(PyWeakReference *newref, PyWeakReference *prev)
516{
517 newref->wr_prev = prev;
518 newref->wr_next = prev->wr_next;
519 if (prev->wr_next != NULL)
520 prev->wr_next->wr_prev = newref;
521 prev->wr_next = newref;
522}
523
524/* Insert 'newref' at the head of the list; 'list' points to the variable
525 * that stores the head.
526 */
527static void
528insert_head(PyWeakReference *newref, PyWeakReference **list)
529{
530 PyWeakReference *next = *list;
531
532 newref->wr_prev = NULL;
533 newref->wr_next = next;
534 if (next != NULL)
535 next->wr_prev = newref;
536 *list = newref;
537}
538
539
540PyObject *
541PyWeakref_NewRef(PyObject *ob, PyObject *callback)
542{
543 PyWeakReference *result = NULL;
544 PyWeakReference **list;
545 PyWeakReference *ref, *proxy;
546
547 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
548 PyErr_Format(PyExc_TypeError,
549 "'%s' objects are not weakly referencable",
550 ob->ob_type->tp_name);
551 return NULL;
552 }
553 list = GET_WEAKREFS_LISTPTR(ob);
554 get_basic_refs(*list, &ref, &proxy);
555 if (callback == NULL || callback == Py_None)
556 /* return existing weak reference if it exists */
557 result = ref;
558 if (result != NULL)
559 Py_XINCREF(result);
560 else {
561 result = new_weakref();
562 if (result != NULL) {
563 Py_XINCREF(callback);
564 result->wr_callback = callback;
565 result->wr_object = ob;
566 if (callback == NULL) {
567 insert_head(result, list);
568 }
569 else {
570 PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
571
572 if (prev == NULL)
573 insert_head(result, list);
574 else
575 insert_after(result, prev);
576 }
577 PyObject_GC_Track(result);
578 }
579 }
580 return (PyObject *) result;
581}
582
583
584PyObject *
585PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
586{
587 PyWeakReference *result = NULL;
588 PyWeakReference **list;
589 PyWeakReference *ref, *proxy;
590
591 if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
592 PyErr_Format(PyExc_TypeError,
593 "'%s' objects are not weakly referencable",
594 ob->ob_type->tp_name);
595 return NULL;
596 }
597 list = GET_WEAKREFS_LISTPTR(ob);
598 get_basic_refs(*list, &ref, &proxy);
599 if (callback == NULL)
600 /* attempt to return an existing weak reference if it exists */
601 result = proxy;
602 if (result != NULL)
603 Py_XINCREF(result);
604 else {
605 result = new_weakref();
606 if (result != NULL) {
607 PyWeakReference *prev;
608
609 if (PyCallable_Check(ob))
610 result->ob_type = &_PyWeakref_CallableProxyType;
611 else
612 result->ob_type = &_PyWeakref_ProxyType;
613 result->wr_object = ob;
614 Py_XINCREF(callback);
615 result->wr_callback = callback;
616 if (callback == NULL)
617 prev = ref;
618 else
619 prev = (proxy == NULL) ? ref : proxy;
620
621 if (prev == NULL)
622 insert_head(result, list);
623 else
624 insert_after(result, prev);
625 PyObject_GC_Track(result);
626 }
627 }
628 return (PyObject *) result;
629}
630
631
632PyObject *
633PyWeakref_GetObject(PyObject *ref)
634{
635 if (ref == NULL || !PyWeakref_Check(ref)) {
636 PyErr_BadInternalCall();
637 return NULL;
638 }
639 return PyWeakref_GET_OBJECT(ref);
640}
641
642
643/* This is the implementation of the PyObject_ClearWeakRefs() function; it
644 * is installed in the init_weakref() function. It is called by the
645 * tp_dealloc handler to clear weak references.
646 *
647 * This iterates through the weak references for 'object' and calls callbacks
648 * for those references which have one. It returns when all callbacks have
649 * been attempted.
650 */
651void
652PyObject_ClearWeakRefs(PyObject *object)
653{
654 PyWeakReference **list;
655
656 if (object == NULL
657 || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
658 || object->ob_refcnt != 0) {
659 PyErr_BadInternalCall();
660 return;
661 }
662 list = GET_WEAKREFS_LISTPTR(object);
663 /* Remove the callback-less basic and proxy references */
664 if (*list != NULL && (*list)->wr_callback == NULL) {
665 clear_weakref(*list);
666 if (*list != NULL && (*list)->wr_callback == NULL)
667 clear_weakref(*list);
668 }
669 if (*list != NULL) {
670 int count = _PyWeakref_GetWeakrefCount(*list);
671
672 if (count == 1) {
673 PyWeakReference *current = *list;
674 PyObject *callback = current->wr_callback;
675 PyObject *cbresult;
676
677 Py_INCREF(callback);
678 clear_weakref(current);
679 cbresult = PyObject_CallFunction(callback, "O", current);
680 if (cbresult == NULL)
681 PyErr_WriteUnraisable(callback);
682 else
683 Py_DECREF(cbresult);
684 Py_DECREF(callback);
685 }
686 else {
687 PyObject *tuple = PyTuple_New(count * 2);
688 PyWeakReference *current = *list;
689 int i = 0;
690
691 for (i = 0; i < count; ++i) {
692 PyWeakReference *next = current->wr_next;
693
694 Py_INCREF(current);
695 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
696 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
697 current->wr_callback = NULL;
698 next = current->wr_next;
699 clear_weakref(current);
700 current = next;
701 }
702 for (i = 0; i < count; ++i) {
703 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
704 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
705 PyObject *cbresult = PyObject_CallFunction(callback, "O",
706 current);
707 if (cbresult == NULL)
708 PyErr_WriteUnraisable(callback);
709 else
710 Py_DECREF(cbresult);
711 }
712 Py_DECREF(tuple);
713 }
714 }
715}