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