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