/src/Python-3.8.3/Objects/weakrefobject.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "Python.h" |
2 | | #include "structmember.h" |
3 | | |
4 | | |
5 | | #define GET_WEAKREFS_LISTPTR(o) \ |
6 | 9.75k | ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o)) |
7 | | |
8 | | |
9 | | Py_ssize_t |
10 | | _PyWeakref_GetWeakrefCount(PyWeakReference *head) |
11 | 362 | { |
12 | 362 | Py_ssize_t count = 0; |
13 | | |
14 | 724 | while (head != NULL) { |
15 | 362 | ++count; |
16 | 362 | head = head->wr_next; |
17 | 362 | } |
18 | 362 | return count; |
19 | 362 | } |
20 | | |
21 | | |
22 | | static void |
23 | | init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback) |
24 | 6.18k | { |
25 | 6.18k | self->hash = -1; |
26 | 6.18k | self->wr_object = ob; |
27 | 6.18k | self->wr_prev = NULL; |
28 | 6.18k | self->wr_next = NULL; |
29 | 6.18k | Py_XINCREF(callback); |
30 | 6.18k | self->wr_callback = callback; |
31 | 6.18k | } |
32 | | |
33 | | static PyWeakReference * |
34 | | new_weakref(PyObject *ob, PyObject *callback) |
35 | 5.81k | { |
36 | 5.81k | PyWeakReference *result; |
37 | | |
38 | 5.81k | result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType); |
39 | 5.81k | if (result) { |
40 | 5.81k | init_weakref(result, ob, callback); |
41 | 5.81k | PyObject_GC_Track(result); |
42 | 5.81k | } |
43 | 5.81k | return result; |
44 | 5.81k | } |
45 | | |
46 | | |
47 | | /* This function clears the passed-in reference and removes it from the |
48 | | * list of weak references for the referent. This is the only code that |
49 | | * removes an item from the doubly-linked list of weak references for an |
50 | | * object; it is also responsible for clearing the callback slot. |
51 | | */ |
52 | | static void |
53 | | clear_weakref(PyWeakReference *self) |
54 | 1.14k | { |
55 | 1.14k | PyObject *callback = self->wr_callback; |
56 | | |
57 | 1.14k | if (self->wr_object != Py_None) { |
58 | 780 | PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object); |
59 | | |
60 | 780 | if (*list == self) |
61 | | /* If 'self' is the end of the list (and thus self->wr_next == NULL) |
62 | | then the weakref list itself (and thus the value of *list) will |
63 | | end up being set to NULL. */ |
64 | 637 | *list = self->wr_next; |
65 | 780 | self->wr_object = Py_None; |
66 | 780 | if (self->wr_prev != NULL) |
67 | 143 | self->wr_prev->wr_next = self->wr_next; |
68 | 780 | if (self->wr_next != NULL) |
69 | 1 | self->wr_next->wr_prev = self->wr_prev; |
70 | 780 | self->wr_prev = NULL; |
71 | 780 | self->wr_next = NULL; |
72 | 780 | } |
73 | 1.14k | if (callback != NULL) { |
74 | 143 | Py_DECREF(callback); |
75 | 143 | self->wr_callback = NULL; |
76 | 143 | } |
77 | 1.14k | } |
78 | | |
79 | | /* Cyclic gc uses this to *just* clear the passed-in reference, leaving |
80 | | * the callback intact and uncalled. It must be possible to call self's |
81 | | * tp_dealloc() after calling this, so self has to be left in a sane enough |
82 | | * state for that to work. We expect tp_dealloc to decref the callback |
83 | | * then. The reason for not letting clear_weakref() decref the callback |
84 | | * right now is that if the callback goes away, that may in turn trigger |
85 | | * another callback (if a weak reference to the callback exists) -- running |
86 | | * arbitrary Python code in the middle of gc is a disaster. The convolution |
87 | | * here allows gc to delay triggering such callbacks until the world is in |
88 | | * a sane state again. |
89 | | */ |
90 | | void |
91 | | _PyWeakref_ClearRef(PyWeakReference *self) |
92 | 6 | { |
93 | 6 | PyObject *callback; |
94 | | |
95 | 6 | assert(self != NULL); |
96 | 6 | assert(PyWeakref_Check(self)); |
97 | | /* Preserve and restore the callback around clear_weakref. */ |
98 | 6 | callback = self->wr_callback; |
99 | 6 | self->wr_callback = NULL; |
100 | 6 | clear_weakref(self); |
101 | 6 | self->wr_callback = callback; |
102 | 6 | } |
103 | | |
104 | | static void |
105 | | weakref_dealloc(PyObject *self) |
106 | 780 | { |
107 | 780 | PyObject_GC_UnTrack(self); |
108 | 780 | clear_weakref((PyWeakReference *) self); |
109 | 780 | Py_TYPE(self)->tp_free(self); |
110 | 780 | } |
111 | | |
112 | | |
113 | | static int |
114 | | gc_traverse(PyWeakReference *self, visitproc visit, void *arg) |
115 | 11.0k | { |
116 | 11.0k | Py_VISIT(self->wr_callback); |
117 | 11.0k | return 0; |
118 | 11.0k | } |
119 | | |
120 | | |
121 | | static int |
122 | | gc_clear(PyWeakReference *self) |
123 | 0 | { |
124 | 0 | clear_weakref(self); |
125 | 0 | return 0; |
126 | 0 | } |
127 | | |
128 | | |
129 | | static PyObject * |
130 | | weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw) |
131 | 56 | { |
132 | 56 | static char *kwlist[] = {NULL}; |
133 | | |
134 | 56 | if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) { |
135 | 56 | PyObject *object = PyWeakref_GET_OBJECT(self); |
136 | 56 | Py_INCREF(object); |
137 | 56 | return (object); |
138 | 56 | } |
139 | 0 | return NULL; |
140 | 56 | } |
141 | | |
142 | | |
143 | | static Py_hash_t |
144 | | weakref_hash(PyWeakReference *self) |
145 | 1.20k | { |
146 | 1.20k | if (self->hash != -1) |
147 | 29 | return self->hash; |
148 | 1.17k | PyObject* obj = PyWeakref_GET_OBJECT(self); |
149 | 1.17k | if (obj == Py_None) { |
150 | 0 | PyErr_SetString(PyExc_TypeError, "weak object has gone away"); |
151 | 0 | return -1; |
152 | 0 | } |
153 | 1.17k | Py_INCREF(obj); |
154 | 1.17k | self->hash = PyObject_Hash(obj); |
155 | 1.17k | Py_DECREF(obj); |
156 | 1.17k | return self->hash; |
157 | 1.17k | } |
158 | | |
159 | | |
160 | | static PyObject * |
161 | | weakref_repr(PyWeakReference *self) |
162 | 0 | { |
163 | 0 | PyObject *name, *repr; |
164 | 0 | _Py_IDENTIFIER(__name__); |
165 | 0 | PyObject* obj = PyWeakref_GET_OBJECT(self); |
166 | |
|
167 | 0 | if (obj == Py_None) { |
168 | 0 | return PyUnicode_FromFormat("<weakref at %p; dead>", self); |
169 | 0 | } |
170 | | |
171 | 0 | Py_INCREF(obj); |
172 | 0 | if (_PyObject_LookupAttrId(obj, &PyId___name__, &name) < 0) { |
173 | 0 | Py_DECREF(obj); |
174 | 0 | return NULL; |
175 | 0 | } |
176 | 0 | if (name == NULL || !PyUnicode_Check(name)) { |
177 | 0 | repr = PyUnicode_FromFormat( |
178 | 0 | "<weakref at %p; to '%s' at %p>", |
179 | 0 | self, |
180 | 0 | Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name, |
181 | 0 | obj); |
182 | 0 | } |
183 | 0 | else { |
184 | 0 | repr = PyUnicode_FromFormat( |
185 | 0 | "<weakref at %p; to '%s' at %p (%U)>", |
186 | 0 | self, |
187 | 0 | Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name, |
188 | 0 | obj, |
189 | 0 | name); |
190 | 0 | } |
191 | 0 | Py_DECREF(obj); |
192 | 0 | Py_XDECREF(name); |
193 | 0 | return repr; |
194 | 0 | } |
195 | | |
196 | | /* Weak references only support equality, not ordering. Two weak references |
197 | | are equal if the underlying objects are equal. If the underlying object has |
198 | | gone away, they are equal if they are identical. */ |
199 | | |
200 | | static PyObject * |
201 | | weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op) |
202 | 13 | { |
203 | 13 | if ((op != Py_EQ && op != Py_NE) || |
204 | 13 | !PyWeakref_Check(self) || |
205 | 13 | !PyWeakref_Check(other)) { |
206 | 0 | Py_RETURN_NOTIMPLEMENTED; |
207 | 0 | } |
208 | 13 | if (PyWeakref_GET_OBJECT(self) == Py_None |
209 | 13 | || PyWeakref_GET_OBJECT(other) == Py_None) { |
210 | 0 | int res = (self == other); |
211 | 0 | if (op == Py_NE) |
212 | 0 | res = !res; |
213 | 0 | if (res) |
214 | 0 | Py_RETURN_TRUE; |
215 | 0 | else |
216 | 0 | Py_RETURN_FALSE; |
217 | 0 | } |
218 | 13 | PyObject* obj = PyWeakref_GET_OBJECT(self); |
219 | 13 | PyObject* other_obj = PyWeakref_GET_OBJECT(other); |
220 | 13 | Py_INCREF(obj); |
221 | 13 | Py_INCREF(other_obj); |
222 | 13 | PyObject* res = PyObject_RichCompare(obj, other_obj, op); |
223 | 13 | Py_DECREF(obj); |
224 | 13 | Py_DECREF(other_obj); |
225 | 13 | return res; |
226 | 13 | } |
227 | | |
228 | | /* Given the head of an object's list of weak references, extract the |
229 | | * two callback-less refs (ref and proxy). Used to determine if the |
230 | | * shared references exist and to determine the back link for newly |
231 | | * inserted references. |
232 | | */ |
233 | | static void |
234 | | get_basic_refs(PyWeakReference *head, |
235 | | PyWeakReference **refp, PyWeakReference **proxyp) |
236 | 13.1k | { |
237 | 13.1k | *refp = NULL; |
238 | 13.1k | *proxyp = NULL; |
239 | | |
240 | 13.1k | if (head != NULL && head->wr_callback == NULL) { |
241 | | /* We need to be careful that the "basic refs" aren't |
242 | | subclasses of the main types. That complicates this a |
243 | | little. */ |
244 | 2.54k | if (PyWeakref_CheckRefExact(head)) { |
245 | 2.54k | *refp = head; |
246 | 2.54k | head = head->wr_next; |
247 | 2.54k | } |
248 | 2.54k | if (head != NULL |
249 | 2.54k | && head->wr_callback == NULL |
250 | 2.54k | && PyWeakref_CheckProxy(head)) { |
251 | 0 | *proxyp = head; |
252 | | /* head = head->wr_next; */ |
253 | 0 | } |
254 | 2.54k | } |
255 | 13.1k | } |
256 | | |
257 | | /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */ |
258 | | static void |
259 | | insert_after(PyWeakReference *newref, PyWeakReference *prev) |
260 | 877 | { |
261 | 877 | newref->wr_prev = prev; |
262 | 877 | newref->wr_next = prev->wr_next; |
263 | 877 | if (prev->wr_next != NULL) |
264 | 344 | prev->wr_next->wr_prev = newref; |
265 | 877 | prev->wr_next = newref; |
266 | 877 | } |
267 | | |
268 | | /* Insert 'newref' at the head of the list; 'list' points to the variable |
269 | | * that stores the head. |
270 | | */ |
271 | | static void |
272 | | insert_head(PyWeakReference *newref, PyWeakReference **list) |
273 | 5.30k | { |
274 | 5.30k | PyWeakReference *next = *list; |
275 | | |
276 | 5.30k | newref->wr_prev = NULL; |
277 | 5.30k | newref->wr_next = next; |
278 | 5.30k | if (next != NULL) |
279 | 2 | next->wr_prev = newref; |
280 | 5.30k | *list = newref; |
281 | 5.30k | } |
282 | | |
283 | | static int |
284 | | parse_weakref_init_args(const char *funcname, PyObject *args, PyObject *kwargs, |
285 | | PyObject **obp, PyObject **callbackp) |
286 | 740 | { |
287 | 740 | return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp); |
288 | 740 | } |
289 | | |
290 | | static PyObject * |
291 | | weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) |
292 | 370 | { |
293 | 370 | PyWeakReference *self = NULL; |
294 | 370 | PyObject *ob, *callback = NULL; |
295 | | |
296 | 370 | if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) { |
297 | 370 | PyWeakReference *ref, *proxy; |
298 | 370 | PyWeakReference **list; |
299 | | |
300 | 370 | if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) { |
301 | 0 | PyErr_Format(PyExc_TypeError, |
302 | 0 | "cannot create weak reference to '%s' object", |
303 | 0 | Py_TYPE(ob)->tp_name); |
304 | 0 | return NULL; |
305 | 0 | } |
306 | 370 | if (callback == Py_None) |
307 | 0 | callback = NULL; |
308 | 370 | list = GET_WEAKREFS_LISTPTR(ob); |
309 | 370 | get_basic_refs(*list, &ref, &proxy); |
310 | 370 | if (callback == NULL && type == &_PyWeakref_RefType) { |
311 | 3 | if (ref != NULL) { |
312 | | /* We can re-use an existing reference. */ |
313 | 0 | Py_INCREF(ref); |
314 | 0 | return (PyObject *)ref; |
315 | 0 | } |
316 | 3 | } |
317 | | /* We have to create a new reference. */ |
318 | | /* Note: the tp_alloc() can trigger cyclic GC, so the weakref |
319 | | list on ob can be mutated. This means that the ref and |
320 | | proxy pointers we got back earlier may have been collected, |
321 | | so we need to compute these values again before we use |
322 | | them. */ |
323 | 370 | self = (PyWeakReference *) (type->tp_alloc(type, 0)); |
324 | 370 | if (self != NULL) { |
325 | 370 | init_weakref(self, ob, callback); |
326 | 370 | if (callback == NULL && type == &_PyWeakref_RefType) { |
327 | 3 | insert_head(self, list); |
328 | 3 | } |
329 | 367 | else { |
330 | 367 | PyWeakReference *prev; |
331 | | |
332 | 367 | get_basic_refs(*list, &ref, &proxy); |
333 | 367 | prev = (proxy == NULL) ? ref : proxy; |
334 | 367 | if (prev == NULL) |
335 | 367 | insert_head(self, list); |
336 | 0 | else |
337 | 0 | insert_after(self, prev); |
338 | 367 | } |
339 | 370 | } |
340 | 370 | } |
341 | 370 | return (PyObject *)self; |
342 | 370 | } |
343 | | |
344 | | static int |
345 | | weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs) |
346 | 370 | { |
347 | 370 | PyObject *tmp; |
348 | | |
349 | 370 | if (!_PyArg_NoKeywords("ref", kwargs)) |
350 | 0 | return -1; |
351 | | |
352 | 370 | if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp)) |
353 | 370 | return 0; |
354 | 0 | else |
355 | 0 | return -1; |
356 | 370 | } |
357 | | |
358 | | |
359 | | static PyMemberDef weakref_members[] = { |
360 | | {"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY}, |
361 | | {NULL} /* Sentinel */ |
362 | | }; |
363 | | |
364 | | PyTypeObject |
365 | | _PyWeakref_RefType = { |
366 | | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
367 | | "weakref", |
368 | | sizeof(PyWeakReference), |
369 | | 0, |
370 | | weakref_dealloc, /*tp_dealloc*/ |
371 | | 0, /*tp_vectorcall_offset*/ |
372 | | 0, /*tp_getattr*/ |
373 | | 0, /*tp_setattr*/ |
374 | | 0, /*tp_as_async*/ |
375 | | (reprfunc)weakref_repr, /*tp_repr*/ |
376 | | 0, /*tp_as_number*/ |
377 | | 0, /*tp_as_sequence*/ |
378 | | 0, /*tp_as_mapping*/ |
379 | | (hashfunc)weakref_hash, /*tp_hash*/ |
380 | | (ternaryfunc)weakref_call, /*tp_call*/ |
381 | | 0, /*tp_str*/ |
382 | | 0, /*tp_getattro*/ |
383 | | 0, /*tp_setattro*/ |
384 | | 0, /*tp_as_buffer*/ |
385 | | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
386 | | | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
387 | | 0, /*tp_doc*/ |
388 | | (traverseproc)gc_traverse, /*tp_traverse*/ |
389 | | (inquiry)gc_clear, /*tp_clear*/ |
390 | | (richcmpfunc)weakref_richcompare, /*tp_richcompare*/ |
391 | | 0, /*tp_weaklistoffset*/ |
392 | | 0, /*tp_iter*/ |
393 | | 0, /*tp_iternext*/ |
394 | | 0, /*tp_methods*/ |
395 | | weakref_members, /*tp_members*/ |
396 | | 0, /*tp_getset*/ |
397 | | 0, /*tp_base*/ |
398 | | 0, /*tp_dict*/ |
399 | | 0, /*tp_descr_get*/ |
400 | | 0, /*tp_descr_set*/ |
401 | | 0, /*tp_dictoffset*/ |
402 | | weakref___init__, /*tp_init*/ |
403 | | PyType_GenericAlloc, /*tp_alloc*/ |
404 | | weakref___new__, /*tp_new*/ |
405 | | PyObject_GC_Del, /*tp_free*/ |
406 | | }; |
407 | | |
408 | | |
409 | | static int |
410 | | proxy_checkref(PyWeakReference *proxy) |
411 | 0 | { |
412 | 0 | if (PyWeakref_GET_OBJECT(proxy) == Py_None) { |
413 | 0 | PyErr_SetString(PyExc_ReferenceError, |
414 | 0 | "weakly-referenced object no longer exists"); |
415 | 0 | return 0; |
416 | 0 | } |
417 | 0 | return 1; |
418 | 0 | } |
419 | | |
420 | | |
421 | | /* If a parameter is a proxy, check that it is still "live" and wrap it, |
422 | | * replacing the original value with the raw object. Raises ReferenceError |
423 | | * if the param is a dead proxy. |
424 | | */ |
425 | | #define UNWRAP(o) \ |
426 | 0 | if (PyWeakref_CheckProxy(o)) { \ |
427 | 0 | if (!proxy_checkref((PyWeakReference *)o)) \ |
428 | 0 | return NULL; \ |
429 | 0 | o = PyWeakref_GET_OBJECT(o); \ |
430 | 0 | } |
431 | | |
432 | | #define WRAP_UNARY(method, generic) \ |
433 | | static PyObject * \ |
434 | 0 | method(PyObject *proxy) { \ |
435 | 0 | UNWRAP(proxy); \ |
436 | 0 | Py_INCREF(proxy); \ |
437 | 0 | PyObject* res = generic(proxy); \ |
438 | 0 | Py_DECREF(proxy); \ |
439 | 0 | return res; \ |
440 | 0 | } Unexecuted instantiation: weakrefobject.c:proxy_neg Unexecuted instantiation: weakrefobject.c:proxy_pos Unexecuted instantiation: weakrefobject.c:proxy_abs Unexecuted instantiation: weakrefobject.c:proxy_invert Unexecuted instantiation: weakrefobject.c:proxy_int Unexecuted instantiation: weakrefobject.c:proxy_float Unexecuted instantiation: weakrefobject.c:proxy_index Unexecuted instantiation: weakrefobject.c:proxy_str |
441 | | |
442 | | #define WRAP_BINARY(method, generic) \ |
443 | | static PyObject * \ |
444 | 0 | method(PyObject *x, PyObject *y) { \ |
445 | 0 | UNWRAP(x); \ |
446 | 0 | UNWRAP(y); \ |
447 | 0 | Py_INCREF(x); \ |
448 | 0 | Py_INCREF(y); \ |
449 | 0 | PyObject* res = generic(x, y); \ |
450 | 0 | Py_DECREF(x); \ |
451 | 0 | Py_DECREF(y); \ |
452 | 0 | return res; \ |
453 | 0 | } Unexecuted instantiation: weakrefobject.c:proxy_add Unexecuted instantiation: weakrefobject.c:proxy_sub Unexecuted instantiation: weakrefobject.c:proxy_mul Unexecuted instantiation: weakrefobject.c:proxy_mod Unexecuted instantiation: weakrefobject.c:proxy_divmod Unexecuted instantiation: weakrefobject.c:proxy_lshift Unexecuted instantiation: weakrefobject.c:proxy_rshift Unexecuted instantiation: weakrefobject.c:proxy_and Unexecuted instantiation: weakrefobject.c:proxy_xor Unexecuted instantiation: weakrefobject.c:proxy_or Unexecuted instantiation: weakrefobject.c:proxy_iadd Unexecuted instantiation: weakrefobject.c:proxy_isub Unexecuted instantiation: weakrefobject.c:proxy_imul Unexecuted instantiation: weakrefobject.c:proxy_imod Unexecuted instantiation: weakrefobject.c:proxy_ilshift Unexecuted instantiation: weakrefobject.c:proxy_irshift Unexecuted instantiation: weakrefobject.c:proxy_iand Unexecuted instantiation: weakrefobject.c:proxy_ixor Unexecuted instantiation: weakrefobject.c:proxy_ior Unexecuted instantiation: weakrefobject.c:proxy_floor_div Unexecuted instantiation: weakrefobject.c:proxy_true_div Unexecuted instantiation: weakrefobject.c:proxy_ifloor_div Unexecuted instantiation: weakrefobject.c:proxy_itrue_div Unexecuted instantiation: weakrefobject.c:proxy_matmul Unexecuted instantiation: weakrefobject.c:proxy_imatmul Unexecuted instantiation: weakrefobject.c:proxy_getitem Unexecuted instantiation: weakrefobject.c:proxy_getattr |
454 | | |
455 | | /* Note that the third arg needs to be checked for NULL since the tp_call |
456 | | * slot can receive NULL for this arg. |
457 | | */ |
458 | | #define WRAP_TERNARY(method, generic) \ |
459 | | static PyObject * \ |
460 | 0 | method(PyObject *proxy, PyObject *v, PyObject *w) { \ |
461 | 0 | UNWRAP(proxy); \ |
462 | 0 | UNWRAP(v); \ |
463 | 0 | if (w != NULL) \ |
464 | 0 | UNWRAP(w); \ |
465 | 0 | Py_INCREF(proxy); \ |
466 | 0 | Py_INCREF(v); \ |
467 | 0 | Py_XINCREF(w); \ |
468 | 0 | PyObject* res = generic(proxy, v, w); \ |
469 | 0 | Py_DECREF(proxy); \ |
470 | 0 | Py_DECREF(v); \ |
471 | 0 | Py_XDECREF(w); \ |
472 | 0 | return res; \ |
473 | 0 | } Unexecuted instantiation: weakrefobject.c:proxy_pow Unexecuted instantiation: weakrefobject.c:proxy_ipow Unexecuted instantiation: weakrefobject.c:proxy_call |
474 | | |
475 | | #define WRAP_METHOD(method, special) \ |
476 | | static PyObject * \ |
477 | 0 | method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \ |
478 | 0 | _Py_IDENTIFIER(special); \ |
479 | 0 | UNWRAP(proxy); \ |
480 | 0 | Py_INCREF(proxy); \ |
481 | 0 | PyObject* res = _PyObject_CallMethodId(proxy, &PyId_##special, NULL); \ |
482 | 0 | Py_DECREF(proxy); \ |
483 | 0 | return res; \ |
484 | 0 | } |
485 | | |
486 | | |
487 | | /* direct slots */ |
488 | | |
489 | | WRAP_BINARY(proxy_getattr, PyObject_GetAttr) |
490 | | WRAP_UNARY(proxy_str, PyObject_Str) |
491 | | WRAP_TERNARY(proxy_call, PyObject_Call) |
492 | | |
493 | | static PyObject * |
494 | | proxy_repr(PyWeakReference *proxy) |
495 | 0 | { |
496 | 0 | return PyUnicode_FromFormat( |
497 | 0 | "<weakproxy at %p to %s at %p>", |
498 | 0 | proxy, |
499 | 0 | Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name, |
500 | 0 | PyWeakref_GET_OBJECT(proxy)); |
501 | 0 | } |
502 | | |
503 | | |
504 | | static int |
505 | | proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value) |
506 | 0 | { |
507 | 0 | if (!proxy_checkref(proxy)) |
508 | 0 | return -1; |
509 | 0 | PyObject *obj = PyWeakref_GET_OBJECT(proxy); |
510 | 0 | Py_INCREF(obj); |
511 | 0 | int res = PyObject_SetAttr(obj, name, value); |
512 | 0 | Py_DECREF(obj); |
513 | 0 | return res; |
514 | 0 | } |
515 | | |
516 | | static PyObject * |
517 | | proxy_richcompare(PyObject *proxy, PyObject *v, int op) |
518 | 0 | { |
519 | 0 | UNWRAP(proxy); |
520 | 0 | UNWRAP(v); |
521 | 0 | return PyObject_RichCompare(proxy, v, op); |
522 | 0 | } |
523 | | |
524 | | /* number slots */ |
525 | | WRAP_BINARY(proxy_add, PyNumber_Add) |
526 | | WRAP_BINARY(proxy_sub, PyNumber_Subtract) |
527 | | WRAP_BINARY(proxy_mul, PyNumber_Multiply) |
528 | | WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide) |
529 | | WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide) |
530 | | WRAP_BINARY(proxy_mod, PyNumber_Remainder) |
531 | | WRAP_BINARY(proxy_divmod, PyNumber_Divmod) |
532 | | WRAP_TERNARY(proxy_pow, PyNumber_Power) |
533 | | WRAP_UNARY(proxy_neg, PyNumber_Negative) |
534 | | WRAP_UNARY(proxy_pos, PyNumber_Positive) |
535 | | WRAP_UNARY(proxy_abs, PyNumber_Absolute) |
536 | | WRAP_UNARY(proxy_invert, PyNumber_Invert) |
537 | | WRAP_BINARY(proxy_lshift, PyNumber_Lshift) |
538 | | WRAP_BINARY(proxy_rshift, PyNumber_Rshift) |
539 | | WRAP_BINARY(proxy_and, PyNumber_And) |
540 | | WRAP_BINARY(proxy_xor, PyNumber_Xor) |
541 | | WRAP_BINARY(proxy_or, PyNumber_Or) |
542 | | WRAP_UNARY(proxy_int, PyNumber_Long) |
543 | | WRAP_UNARY(proxy_float, PyNumber_Float) |
544 | | WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd) |
545 | | WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract) |
546 | | WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply) |
547 | | WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide) |
548 | | WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide) |
549 | | WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder) |
550 | | WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower) |
551 | | WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift) |
552 | | WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift) |
553 | | WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd) |
554 | | WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor) |
555 | | WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr) |
556 | | WRAP_UNARY(proxy_index, PyNumber_Index) |
557 | | WRAP_BINARY(proxy_matmul, PyNumber_MatrixMultiply) |
558 | | WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply) |
559 | | |
560 | | static int |
561 | | proxy_bool(PyWeakReference *proxy) |
562 | 0 | { |
563 | 0 | PyObject *o = PyWeakref_GET_OBJECT(proxy); |
564 | 0 | if (!proxy_checkref(proxy)) { |
565 | 0 | return -1; |
566 | 0 | } |
567 | 0 | Py_INCREF(o); |
568 | 0 | int res = PyObject_IsTrue(o); |
569 | 0 | Py_DECREF(o); |
570 | 0 | return res; |
571 | 0 | } |
572 | | |
573 | | static void |
574 | | proxy_dealloc(PyWeakReference *self) |
575 | 0 | { |
576 | 0 | if (self->wr_callback != NULL) |
577 | 0 | PyObject_GC_UnTrack((PyObject *)self); |
578 | 0 | clear_weakref(self); |
579 | 0 | PyObject_GC_Del(self); |
580 | 0 | } |
581 | | |
582 | | /* sequence slots */ |
583 | | |
584 | | static int |
585 | | proxy_contains(PyWeakReference *proxy, PyObject *value) |
586 | 0 | { |
587 | 0 | if (!proxy_checkref(proxy)) |
588 | 0 | return -1; |
589 | | |
590 | 0 | PyObject *obj = PyWeakref_GET_OBJECT(proxy); |
591 | 0 | Py_INCREF(obj); |
592 | 0 | int res = PySequence_Contains(obj, value); |
593 | 0 | Py_DECREF(obj); |
594 | 0 | return res; |
595 | 0 | } |
596 | | |
597 | | /* mapping slots */ |
598 | | |
599 | | static Py_ssize_t |
600 | | proxy_length(PyWeakReference *proxy) |
601 | 0 | { |
602 | 0 | if (!proxy_checkref(proxy)) |
603 | 0 | return -1; |
604 | | |
605 | 0 | PyObject *obj = PyWeakref_GET_OBJECT(proxy); |
606 | 0 | Py_INCREF(obj); |
607 | 0 | Py_ssize_t res = PyObject_Length(obj); |
608 | 0 | Py_DECREF(obj); |
609 | 0 | return res; |
610 | 0 | } |
611 | | |
612 | | WRAP_BINARY(proxy_getitem, PyObject_GetItem) |
613 | | |
614 | | static int |
615 | | proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value) |
616 | 0 | { |
617 | 0 | if (!proxy_checkref(proxy)) |
618 | 0 | return -1; |
619 | | |
620 | 0 | PyObject *obj = PyWeakref_GET_OBJECT(proxy); |
621 | 0 | Py_INCREF(obj); |
622 | 0 | int res; |
623 | 0 | if (value == NULL) { |
624 | 0 | res = PyObject_DelItem(obj, key); |
625 | 0 | } else { |
626 | 0 | res = PyObject_SetItem(obj, key, value); |
627 | 0 | } |
628 | 0 | Py_DECREF(obj); |
629 | 0 | return res; |
630 | 0 | } |
631 | | |
632 | | /* iterator slots */ |
633 | | |
634 | | static PyObject * |
635 | | proxy_iter(PyWeakReference *proxy) |
636 | 0 | { |
637 | 0 | if (!proxy_checkref(proxy)) |
638 | 0 | return NULL; |
639 | 0 | PyObject *obj = PyWeakref_GET_OBJECT(proxy); |
640 | 0 | Py_INCREF(obj); |
641 | 0 | PyObject* res = PyObject_GetIter(obj); |
642 | 0 | Py_DECREF(obj); |
643 | 0 | return res; |
644 | 0 | } |
645 | | |
646 | | static PyObject * |
647 | | proxy_iternext(PyWeakReference *proxy) |
648 | 0 | { |
649 | 0 | if (!proxy_checkref(proxy)) |
650 | 0 | return NULL; |
651 | | |
652 | 0 | PyObject *obj = PyWeakref_GET_OBJECT(proxy); |
653 | 0 | Py_INCREF(obj); |
654 | 0 | PyObject* res = PyIter_Next(obj); |
655 | 0 | Py_DECREF(obj); |
656 | 0 | return res; |
657 | 0 | } |
658 | | |
659 | | |
660 | | WRAP_METHOD(proxy_bytes, __bytes__) |
661 | | |
662 | | |
663 | | static PyMethodDef proxy_methods[] = { |
664 | | {"__bytes__", proxy_bytes, METH_NOARGS}, |
665 | | {NULL, NULL} |
666 | | }; |
667 | | |
668 | | |
669 | | static PyNumberMethods proxy_as_number = { |
670 | | proxy_add, /*nb_add*/ |
671 | | proxy_sub, /*nb_subtract*/ |
672 | | proxy_mul, /*nb_multiply*/ |
673 | | proxy_mod, /*nb_remainder*/ |
674 | | proxy_divmod, /*nb_divmod*/ |
675 | | proxy_pow, /*nb_power*/ |
676 | | proxy_neg, /*nb_negative*/ |
677 | | proxy_pos, /*nb_positive*/ |
678 | | proxy_abs, /*nb_absolute*/ |
679 | | (inquiry)proxy_bool, /*nb_bool*/ |
680 | | proxy_invert, /*nb_invert*/ |
681 | | proxy_lshift, /*nb_lshift*/ |
682 | | proxy_rshift, /*nb_rshift*/ |
683 | | proxy_and, /*nb_and*/ |
684 | | proxy_xor, /*nb_xor*/ |
685 | | proxy_or, /*nb_or*/ |
686 | | proxy_int, /*nb_int*/ |
687 | | 0, /*nb_reserved*/ |
688 | | proxy_float, /*nb_float*/ |
689 | | proxy_iadd, /*nb_inplace_add*/ |
690 | | proxy_isub, /*nb_inplace_subtract*/ |
691 | | proxy_imul, /*nb_inplace_multiply*/ |
692 | | proxy_imod, /*nb_inplace_remainder*/ |
693 | | proxy_ipow, /*nb_inplace_power*/ |
694 | | proxy_ilshift, /*nb_inplace_lshift*/ |
695 | | proxy_irshift, /*nb_inplace_rshift*/ |
696 | | proxy_iand, /*nb_inplace_and*/ |
697 | | proxy_ixor, /*nb_inplace_xor*/ |
698 | | proxy_ior, /*nb_inplace_or*/ |
699 | | proxy_floor_div, /*nb_floor_divide*/ |
700 | | proxy_true_div, /*nb_true_divide*/ |
701 | | proxy_ifloor_div, /*nb_inplace_floor_divide*/ |
702 | | proxy_itrue_div, /*nb_inplace_true_divide*/ |
703 | | proxy_index, /*nb_index*/ |
704 | | proxy_matmul, /*nb_matrix_multiply*/ |
705 | | proxy_imatmul, /*nb_inplace_matrix_multiply*/ |
706 | | }; |
707 | | |
708 | | static PySequenceMethods proxy_as_sequence = { |
709 | | (lenfunc)proxy_length, /*sq_length*/ |
710 | | 0, /*sq_concat*/ |
711 | | 0, /*sq_repeat*/ |
712 | | 0, /*sq_item*/ |
713 | | 0, /*sq_slice*/ |
714 | | 0, /*sq_ass_item*/ |
715 | | 0, /*sq_ass_slice*/ |
716 | | (objobjproc)proxy_contains, /* sq_contains */ |
717 | | }; |
718 | | |
719 | | static PyMappingMethods proxy_as_mapping = { |
720 | | (lenfunc)proxy_length, /*mp_length*/ |
721 | | proxy_getitem, /*mp_subscript*/ |
722 | | (objobjargproc)proxy_setitem, /*mp_ass_subscript*/ |
723 | | }; |
724 | | |
725 | | |
726 | | PyTypeObject |
727 | | _PyWeakref_ProxyType = { |
728 | | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
729 | | "weakproxy", |
730 | | sizeof(PyWeakReference), |
731 | | 0, |
732 | | /* methods */ |
733 | | (destructor)proxy_dealloc, /* tp_dealloc */ |
734 | | 0, /* tp_vectorcall_offset */ |
735 | | 0, /* tp_getattr */ |
736 | | 0, /* tp_setattr */ |
737 | | 0, /* tp_as_async */ |
738 | | (reprfunc)proxy_repr, /* tp_repr */ |
739 | | &proxy_as_number, /* tp_as_number */ |
740 | | &proxy_as_sequence, /* tp_as_sequence */ |
741 | | &proxy_as_mapping, /* tp_as_mapping */ |
742 | | 0, /* tp_hash */ |
743 | | 0, /* tp_call */ |
744 | | proxy_str, /* tp_str */ |
745 | | proxy_getattr, /* tp_getattro */ |
746 | | (setattrofunc)proxy_setattr, /* tp_setattro */ |
747 | | 0, /* tp_as_buffer */ |
748 | | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
749 | | 0, /* tp_doc */ |
750 | | (traverseproc)gc_traverse, /* tp_traverse */ |
751 | | (inquiry)gc_clear, /* tp_clear */ |
752 | | proxy_richcompare, /* tp_richcompare */ |
753 | | 0, /* tp_weaklistoffset */ |
754 | | (getiterfunc)proxy_iter, /* tp_iter */ |
755 | | (iternextfunc)proxy_iternext, /* tp_iternext */ |
756 | | proxy_methods, /* tp_methods */ |
757 | | }; |
758 | | |
759 | | |
760 | | PyTypeObject |
761 | | _PyWeakref_CallableProxyType = { |
762 | | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
763 | | "weakcallableproxy", |
764 | | sizeof(PyWeakReference), |
765 | | 0, |
766 | | /* methods */ |
767 | | (destructor)proxy_dealloc, /* tp_dealloc */ |
768 | | 0, /* tp_vectorcall_offset */ |
769 | | 0, /* tp_getattr */ |
770 | | 0, /* tp_setattr */ |
771 | | 0, /* tp_as_async */ |
772 | | (unaryfunc)proxy_repr, /* tp_repr */ |
773 | | &proxy_as_number, /* tp_as_number */ |
774 | | &proxy_as_sequence, /* tp_as_sequence */ |
775 | | &proxy_as_mapping, /* tp_as_mapping */ |
776 | | 0, /* tp_hash */ |
777 | | proxy_call, /* tp_call */ |
778 | | proxy_str, /* tp_str */ |
779 | | proxy_getattr, /* tp_getattro */ |
780 | | (setattrofunc)proxy_setattr, /* tp_setattro */ |
781 | | 0, /* tp_as_buffer */ |
782 | | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
783 | | 0, /* tp_doc */ |
784 | | (traverseproc)gc_traverse, /* tp_traverse */ |
785 | | (inquiry)gc_clear, /* tp_clear */ |
786 | | proxy_richcompare, /* tp_richcompare */ |
787 | | 0, /* tp_weaklistoffset */ |
788 | | (getiterfunc)proxy_iter, /* tp_iter */ |
789 | | (iternextfunc)proxy_iternext, /* tp_iternext */ |
790 | | }; |
791 | | |
792 | | |
793 | | |
794 | | PyObject * |
795 | | PyWeakref_NewRef(PyObject *ob, PyObject *callback) |
796 | 6.60k | { |
797 | 6.60k | PyWeakReference *result = NULL; |
798 | 6.60k | PyWeakReference **list; |
799 | 6.60k | PyWeakReference *ref, *proxy; |
800 | | |
801 | 6.60k | if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) { |
802 | 0 | PyErr_Format(PyExc_TypeError, |
803 | 0 | "cannot create weak reference to '%s' object", |
804 | 0 | Py_TYPE(ob)->tp_name); |
805 | 0 | return NULL; |
806 | 0 | } |
807 | 6.60k | list = GET_WEAKREFS_LISTPTR(ob); |
808 | 6.60k | get_basic_refs(*list, &ref, &proxy); |
809 | 6.60k | if (callback == Py_None) |
810 | 0 | callback = NULL; |
811 | 6.60k | if (callback == NULL) |
812 | | /* return existing weak reference if it exists */ |
813 | 5.72k | result = ref; |
814 | 6.60k | if (result != NULL) |
815 | 789 | Py_INCREF(result); |
816 | 5.81k | else { |
817 | | /* Note: new_weakref() can trigger cyclic GC, so the weakref |
818 | | list on ob can be mutated. This means that the ref and |
819 | | proxy pointers we got back earlier may have been collected, |
820 | | so we need to compute these values again before we use |
821 | | them. */ |
822 | 5.81k | result = new_weakref(ob, callback); |
823 | 5.81k | if (result != NULL) { |
824 | 5.81k | get_basic_refs(*list, &ref, &proxy); |
825 | 5.81k | if (callback == NULL) { |
826 | 4.93k | if (ref == NULL) |
827 | 4.93k | insert_head(result, list); |
828 | 0 | else { |
829 | | /* Someone else added a ref without a callback |
830 | | during GC. Return that one instead of this one |
831 | | to avoid violating the invariants of the list |
832 | | of weakrefs for ob. */ |
833 | 0 | Py_DECREF(result); |
834 | 0 | Py_INCREF(ref); |
835 | 0 | result = ref; |
836 | 0 | } |
837 | 4.93k | } |
838 | 877 | else { |
839 | 877 | PyWeakReference *prev; |
840 | | |
841 | 877 | prev = (proxy == NULL) ? ref : proxy; |
842 | 877 | if (prev == NULL) |
843 | 0 | insert_head(result, list); |
844 | 877 | else |
845 | 877 | insert_after(result, prev); |
846 | 877 | } |
847 | 5.81k | } |
848 | 5.81k | } |
849 | 6.60k | return (PyObject *) result; |
850 | 6.60k | } |
851 | | |
852 | | |
853 | | PyObject * |
854 | | PyWeakref_NewProxy(PyObject *ob, PyObject *callback) |
855 | 0 | { |
856 | 0 | PyWeakReference *result = NULL; |
857 | 0 | PyWeakReference **list; |
858 | 0 | PyWeakReference *ref, *proxy; |
859 | |
|
860 | 0 | if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) { |
861 | 0 | PyErr_Format(PyExc_TypeError, |
862 | 0 | "cannot create weak reference to '%s' object", |
863 | 0 | Py_TYPE(ob)->tp_name); |
864 | 0 | return NULL; |
865 | 0 | } |
866 | 0 | list = GET_WEAKREFS_LISTPTR(ob); |
867 | 0 | get_basic_refs(*list, &ref, &proxy); |
868 | 0 | if (callback == Py_None) |
869 | 0 | callback = NULL; |
870 | 0 | if (callback == NULL) |
871 | | /* attempt to return an existing weak reference if it exists */ |
872 | 0 | result = proxy; |
873 | 0 | if (result != NULL) |
874 | 0 | Py_INCREF(result); |
875 | 0 | else { |
876 | | /* Note: new_weakref() can trigger cyclic GC, so the weakref |
877 | | list on ob can be mutated. This means that the ref and |
878 | | proxy pointers we got back earlier may have been collected, |
879 | | so we need to compute these values again before we use |
880 | | them. */ |
881 | 0 | result = new_weakref(ob, callback); |
882 | 0 | if (result != NULL) { |
883 | 0 | PyWeakReference *prev; |
884 | |
|
885 | 0 | if (PyCallable_Check(ob)) |
886 | 0 | Py_TYPE(result) = &_PyWeakref_CallableProxyType; |
887 | 0 | else |
888 | 0 | Py_TYPE(result) = &_PyWeakref_ProxyType; |
889 | 0 | get_basic_refs(*list, &ref, &proxy); |
890 | 0 | if (callback == NULL) { |
891 | 0 | if (proxy != NULL) { |
892 | | /* Someone else added a proxy without a callback |
893 | | during GC. Return that one instead of this one |
894 | | to avoid violating the invariants of the list |
895 | | of weakrefs for ob. */ |
896 | 0 | Py_DECREF(result); |
897 | 0 | result = proxy; |
898 | 0 | Py_INCREF(result); |
899 | 0 | goto skip_insert; |
900 | 0 | } |
901 | 0 | prev = ref; |
902 | 0 | } |
903 | 0 | else |
904 | 0 | prev = (proxy == NULL) ? ref : proxy; |
905 | | |
906 | 0 | if (prev == NULL) |
907 | 0 | insert_head(result, list); |
908 | 0 | else |
909 | 0 | insert_after(result, prev); |
910 | 0 | skip_insert: |
911 | 0 | ; |
912 | 0 | } |
913 | 0 | } |
914 | 0 | return (PyObject *) result; |
915 | 0 | } |
916 | | |
917 | | |
918 | | PyObject * |
919 | | PyWeakref_GetObject(PyObject *ref) |
920 | 270 | { |
921 | 270 | if (ref == NULL || !PyWeakref_Check(ref)) { |
922 | 0 | PyErr_BadInternalCall(); |
923 | 0 | return NULL; |
924 | 0 | } |
925 | 270 | return PyWeakref_GET_OBJECT(ref); |
926 | 270 | } |
927 | | |
928 | | /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's |
929 | | * handle_weakrefs(). |
930 | | */ |
931 | | static void |
932 | | handle_callback(PyWeakReference *ref, PyObject *callback) |
933 | 362 | { |
934 | 362 | PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL); |
935 | | |
936 | 362 | if (cbresult == NULL) |
937 | 0 | PyErr_WriteUnraisable(callback); |
938 | 362 | else |
939 | 362 | Py_DECREF(cbresult); |
940 | 362 | } |
941 | | |
942 | | /* This function is called by the tp_dealloc handler to clear weak references. |
943 | | * |
944 | | * This iterates through the weak references for 'object' and calls callbacks |
945 | | * for those references which have one. It returns when all callbacks have |
946 | | * been attempted. |
947 | | */ |
948 | | void |
949 | | PyObject_ClearWeakRefs(PyObject *object) |
950 | 2.00k | { |
951 | 2.00k | PyWeakReference **list; |
952 | | |
953 | 2.00k | if (object == NULL |
954 | 2.00k | || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object)) |
955 | 2.00k | || object->ob_refcnt != 0) { |
956 | 0 | PyErr_BadInternalCall(); |
957 | 0 | return; |
958 | 0 | } |
959 | 2.00k | list = GET_WEAKREFS_LISTPTR(object); |
960 | | /* Remove the callback-less basic and proxy references */ |
961 | 2.00k | if (*list != NULL && (*list)->wr_callback == NULL) { |
962 | 0 | clear_weakref(*list); |
963 | 0 | if (*list != NULL && (*list)->wr_callback == NULL) |
964 | 0 | clear_weakref(*list); |
965 | 0 | } |
966 | 2.00k | if (*list != NULL) { |
967 | 362 | PyWeakReference *current = *list; |
968 | 362 | Py_ssize_t count = _PyWeakref_GetWeakrefCount(current); |
969 | 362 | PyObject *err_type, *err_value, *err_tb; |
970 | | |
971 | 362 | PyErr_Fetch(&err_type, &err_value, &err_tb); |
972 | 362 | if (count == 1) { |
973 | 362 | PyObject *callback = current->wr_callback; |
974 | | |
975 | 362 | current->wr_callback = NULL; |
976 | 362 | clear_weakref(current); |
977 | 362 | if (callback != NULL) { |
978 | 362 | if (((PyObject *)current)->ob_refcnt > 0) |
979 | 362 | handle_callback(current, callback); |
980 | 362 | Py_DECREF(callback); |
981 | 362 | } |
982 | 362 | } |
983 | 0 | else { |
984 | 0 | PyObject *tuple; |
985 | 0 | Py_ssize_t i = 0; |
986 | |
|
987 | 0 | tuple = PyTuple_New(count * 2); |
988 | 0 | if (tuple == NULL) { |
989 | 0 | _PyErr_ChainExceptions(err_type, err_value, err_tb); |
990 | 0 | return; |
991 | 0 | } |
992 | | |
993 | 0 | for (i = 0; i < count; ++i) { |
994 | 0 | PyWeakReference *next = current->wr_next; |
995 | |
|
996 | 0 | if (((PyObject *)current)->ob_refcnt > 0) |
997 | 0 | { |
998 | 0 | Py_INCREF(current); |
999 | 0 | PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current); |
1000 | 0 | PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback); |
1001 | 0 | } |
1002 | 0 | else { |
1003 | 0 | Py_DECREF(current->wr_callback); |
1004 | 0 | } |
1005 | 0 | current->wr_callback = NULL; |
1006 | 0 | clear_weakref(current); |
1007 | 0 | current = next; |
1008 | 0 | } |
1009 | 0 | for (i = 0; i < count; ++i) { |
1010 | 0 | PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1); |
1011 | | |
1012 | | /* The tuple may have slots left to NULL */ |
1013 | 0 | if (callback != NULL) { |
1014 | 0 | PyObject *item = PyTuple_GET_ITEM(tuple, i * 2); |
1015 | 0 | handle_callback((PyWeakReference *)item, callback); |
1016 | 0 | } |
1017 | 0 | } |
1018 | 0 | Py_DECREF(tuple); |
1019 | 0 | } |
1020 | 362 | assert(!PyErr_Occurred()); |
1021 | 362 | PyErr_Restore(err_type, err_value, err_tb); |
1022 | 362 | } |
1023 | 2.00k | } |