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