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