History

add hg and python

cinap_lenrek committed 15 years ago

Commit 4bb9e221 parent 987265c3706 files · +1228772 −-233Browse files

Showing the changes to sys/src/cmd/python/Objects/weakrefobject.c (1 of 3706 files). Show all

Unified · Split

sys/src/cmd/python/Objects/weakrefobject.c+941−0
@@ -0,0 +1,941 @@
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+ Py_XINCREF(callback);
28+ self->wr_callback = callback;
29+}
30+
31+static PyWeakReference *
32+new_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+ */
50+static void
51+clear_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+ */
89+void
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+
103+static void
104+weakref_dealloc(PyObject *self)
105+{
106+ PyObject_GC_UnTrack(self);
107+ clear_weakref((PyWeakReference *) self);
108+ self->ob_type->tp_free(self);
109+}
110+
111+
112+static int
113+gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
114+{
115+ Py_VISIT(self->wr_callback);
116+ return 0;
117+}
118+
119+
120+static int
121+gc_clear(PyWeakReference *self)
122+{
123+ clear_weakref(self);
124+ return 0;
125+}
126+
127+
128+static PyObject *
129+weakref_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+
142+static long
143+weakref_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+
156+static PyObject *
157+weakref_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+ PyWeakref_GET_OBJECT(self)->ob_type->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+
187+static PyObject *
188+weakref_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+ */
209+static void
210+get_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. */
234+static void
235+insert_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+ */
247+static void
248+insert_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+
259+static int
260+parse_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+
267+static PyObject *
268+weakref___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(ob->ob_type)) {
278+ PyErr_Format(PyExc_TypeError,
279+ "cannot create weak reference to '%s' object",
280+ ob->ob_type->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+
321+static int
322+weakref___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+
333+PyTypeObject
334+_PyWeakref_RefType = {
335+ PyObject_HEAD_INIT(&PyType_Type)
336+ 0,
337+ "weakref",
338+ sizeof(PyWeakReference),
339+ 0,
340+ weakref_dealloc, /*tp_dealloc*/
341+ 0, /*tp_print*/
342+ 0, /*tp_getattr*/
343+ 0, /*tp_setattr*/
344+ 0, /*tp_compare*/
345+ (reprfunc)weakref_repr, /*tp_repr*/
346+ 0, /*tp_as_number*/
347+ 0, /*tp_as_sequence*/
348+ 0, /*tp_as_mapping*/
349+ (hashfunc)weakref_hash, /*tp_hash*/
350+ (ternaryfunc)weakref_call, /*tp_call*/
351+ 0, /*tp_str*/
352+ 0, /*tp_getattro*/
353+ 0, /*tp_setattro*/
354+ 0, /*tp_as_buffer*/
355+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE
356+ | Py_TPFLAGS_BASETYPE, /*tp_flags*/
357+ 0, /*tp_doc*/
358+ (traverseproc)gc_traverse, /*tp_traverse*/
359+ (inquiry)gc_clear, /*tp_clear*/
360+ (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
361+ 0, /*tp_weaklistoffset*/
362+ 0, /*tp_iter*/
363+ 0, /*tp_iternext*/
364+ 0, /*tp_methods*/
365+ 0, /*tp_members*/
366+ 0, /*tp_getset*/
367+ 0, /*tp_base*/
368+ 0, /*tp_dict*/
369+ 0, /*tp_descr_get*/
370+ 0, /*tp_descr_set*/
371+ 0, /*tp_dictoffset*/
372+ weakref___init__, /*tp_init*/
373+ PyType_GenericAlloc, /*tp_alloc*/
374+ weakref___new__, /*tp_new*/
375+ PyObject_GC_Del, /*tp_free*/
376+};
377+
378+
379+static int
380+proxy_checkref(PyWeakReference *proxy)
381+{
382+ if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
383+ PyErr_SetString(PyExc_ReferenceError,
384+ "weakly-referenced object no longer exists");
385+ return 0;
386+ }
387+ return 1;
388+}
389+
390+
391+/* If a parameter is a proxy, check that it is still "live" and wrap it,
392+ * replacing the original value with the raw object. Raises ReferenceError
393+ * if the param is a dead proxy.
394+ */
395+#define UNWRAP(o) \
396+ if (PyWeakref_CheckProxy(o)) { \
397+ if (!proxy_checkref((PyWeakReference *)o)) \
398+ return NULL; \
399+ o = PyWeakref_GET_OBJECT(o); \
400+ }
401+
402+#define UNWRAP_I(o) \
403+ if (PyWeakref_CheckProxy(o)) { \
404+ if (!proxy_checkref((PyWeakReference *)o)) \
405+ return -1; \
406+ o = PyWeakref_GET_OBJECT(o); \
407+ }
408+
409+#define WRAP_UNARY(method, generic) \
410+ static PyObject * \
411+ method(PyObject *proxy) { \
412+ UNWRAP(proxy); \
413+ return generic(proxy); \
414+ }
415+
416+#define WRAP_BINARY(method, generic) \
417+ static PyObject * \
418+ method(PyObject *x, PyObject *y) { \
419+ UNWRAP(x); \
420+ UNWRAP(y); \
421+ return generic(x, y); \
422+ }
423+
424+/* Note that the third arg needs to be checked for NULL since the tp_call
425+ * slot can receive NULL for this arg.
426+ */
427+#define WRAP_TERNARY(method, generic) \
428+ static PyObject * \
429+ method(PyObject *proxy, PyObject *v, PyObject *w) { \
430+ UNWRAP(proxy); \
431+ UNWRAP(v); \
432+ if (w != NULL) \
433+ UNWRAP(w); \
434+ return generic(proxy, v, w); \
435+ }
436+
437+
438+/* direct slots */
439+
440+WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
441+WRAP_UNARY(proxy_str, PyObject_Str)
442+WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
443+
444+static PyObject *
445+proxy_repr(PyWeakReference *proxy)
446+{
447+ char buf[160];
448+ PyOS_snprintf(buf, sizeof(buf),
449+ "<weakproxy at %p to %.100s at %p>", proxy,
450+ PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name,
451+ PyWeakref_GET_OBJECT(proxy));
452+ return PyString_FromString(buf);
453+}
454+
455+
456+static int
457+proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
458+{
459+ if (!proxy_checkref(proxy))
460+ return -1;
461+ return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
462+}
463+
464+static int
465+proxy_compare(PyObject *proxy, PyObject *v)
466+{
467+ UNWRAP_I(proxy);
468+ UNWRAP_I(v);
469+ return PyObject_Compare(proxy, v);
470+}
471+
472+/* number slots */
473+WRAP_BINARY(proxy_add, PyNumber_Add)
474+WRAP_BINARY(proxy_sub, PyNumber_Subtract)
475+WRAP_BINARY(proxy_mul, PyNumber_Multiply)
476+WRAP_BINARY(proxy_div, PyNumber_Divide)
477+WRAP_BINARY(proxy_mod, PyNumber_Remainder)
478+WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
479+WRAP_TERNARY(proxy_pow, PyNumber_Power)
480+WRAP_UNARY(proxy_neg, PyNumber_Negative)
481+WRAP_UNARY(proxy_pos, PyNumber_Positive)
482+WRAP_UNARY(proxy_abs, PyNumber_Absolute)
483+WRAP_UNARY(proxy_invert, PyNumber_Invert)
484+WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
485+WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
486+WRAP_BINARY(proxy_and, PyNumber_And)
487+WRAP_BINARY(proxy_xor, PyNumber_Xor)
488+WRAP_BINARY(proxy_or, PyNumber_Or)
489+WRAP_UNARY(proxy_int, PyNumber_Int)
490+WRAP_UNARY(proxy_long, PyNumber_Long)
491+WRAP_UNARY(proxy_float, PyNumber_Float)
492+WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
493+WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
494+WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
495+WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)
496+WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
497+WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
498+WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
499+WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
500+WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
501+WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
502+WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
503+
504+static int
505+proxy_nonzero(PyWeakReference *proxy)
506+{
507+ PyObject *o = PyWeakref_GET_OBJECT(proxy);
508+ if (!proxy_checkref(proxy))
509+ return -1;
510+ return PyObject_IsTrue(o);
511+}
512+
513+static void
514+proxy_dealloc(PyWeakReference *self)
515+{
516+ if (self->wr_callback != NULL)
517+ PyObject_GC_UnTrack((PyObject *)self);
518+ clear_weakref(self);
519+ PyObject_GC_Del(self);
520+}
521+
522+/* sequence slots */
523+
524+static PyObject *
525+proxy_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j)
526+{
527+ if (!proxy_checkref(proxy))
528+ return NULL;
529+ return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);
530+}
531+
532+static int
533+proxy_ass_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j, PyObject *value)
534+{
535+ if (!proxy_checkref(proxy))
536+ return -1;
537+ return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);
538+}
539+
540+static int
541+proxy_contains(PyWeakReference *proxy, PyObject *value)
542+{
543+ if (!proxy_checkref(proxy))
544+ return -1;
545+ return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
546+}
547+
548+
549+/* mapping slots */
550+
551+static Py_ssize_t
552+proxy_length(PyWeakReference *proxy)
553+{
554+ if (!proxy_checkref(proxy))
555+ return -1;
556+ return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
557+}
558+
559+WRAP_BINARY(proxy_getitem, PyObject_GetItem)
560+
561+static int
562+proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
563+{
564+ if (!proxy_checkref(proxy))
565+ return -1;
566+
567+ if (value == NULL)
568+ return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
569+ else
570+ return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
571+}
572+
573+/* iterator slots */
574+
575+static PyObject *
576+proxy_iter(PyWeakReference *proxy)
577+{
578+ if (!proxy_checkref(proxy))
579+ return NULL;
580+ return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
581+}
582+
583+static PyObject *
584+proxy_iternext(PyWeakReference *proxy)
585+{
586+ if (!proxy_checkref(proxy))
587+ return NULL;
588+ return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
589+}
590+
591+
592+static PyNumberMethods proxy_as_number = {
593+ proxy_add, /*nb_add*/
594+ proxy_sub, /*nb_subtract*/
595+ proxy_mul, /*nb_multiply*/
596+ proxy_div, /*nb_divide*/
597+ proxy_mod, /*nb_remainder*/
598+ proxy_divmod, /*nb_divmod*/
599+ proxy_pow, /*nb_power*/
600+ proxy_neg, /*nb_negative*/
601+ proxy_pos, /*nb_positive*/
602+ proxy_abs, /*nb_absolute*/
603+ (inquiry)proxy_nonzero, /*nb_nonzero*/
604+ proxy_invert, /*nb_invert*/
605+ proxy_lshift, /*nb_lshift*/
606+ proxy_rshift, /*nb_rshift*/
607+ proxy_and, /*nb_and*/
608+ proxy_xor, /*nb_xor*/
609+ proxy_or, /*nb_or*/
610+ 0, /*nb_coerce*/
611+ proxy_int, /*nb_int*/
612+ proxy_long, /*nb_long*/
613+ proxy_float, /*nb_float*/
614+ 0, /*nb_oct*/
615+ 0, /*nb_hex*/
616+ proxy_iadd, /*nb_inplace_add*/
617+ proxy_isub, /*nb_inplace_subtract*/
618+ proxy_imul, /*nb_inplace_multiply*/
619+ proxy_idiv, /*nb_inplace_divide*/
620+ proxy_imod, /*nb_inplace_remainder*/
621+ proxy_ipow, /*nb_inplace_power*/
622+ proxy_ilshift, /*nb_inplace_lshift*/
623+ proxy_irshift, /*nb_inplace_rshift*/
624+ proxy_iand, /*nb_inplace_and*/
625+ proxy_ixor, /*nb_inplace_xor*/
626+ proxy_ior, /*nb_inplace_or*/
627+};
628+
629+static PySequenceMethods proxy_as_sequence = {
630+ (lenfunc)proxy_length, /*sq_length*/
631+ 0, /*sq_concat*/
632+ 0, /*sq_repeat*/
633+ 0, /*sq_item*/
634+ (ssizessizeargfunc)proxy_slice, /*sq_slice*/
635+ 0, /*sq_ass_item*/
636+ (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/
637+ (objobjproc)proxy_contains, /* sq_contains */
638+};
639+
640+static PyMappingMethods proxy_as_mapping = {
641+ (lenfunc)proxy_length, /*mp_length*/
642+ proxy_getitem, /*mp_subscript*/
643+ (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
644+};
645+
646+
647+PyTypeObject
648+_PyWeakref_ProxyType = {
649+ PyObject_HEAD_INIT(&PyType_Type)
650+ 0,
651+ "weakproxy",
652+ sizeof(PyWeakReference),
653+ 0,
654+ /* methods */
655+ (destructor)proxy_dealloc, /* tp_dealloc */
656+ 0, /* tp_print */
657+ 0, /* tp_getattr */
658+ 0, /* tp_setattr */
659+ proxy_compare, /* tp_compare */
660+ (reprfunc)proxy_repr, /* tp_repr */
661+ &proxy_as_number, /* tp_as_number */
662+ &proxy_as_sequence, /* tp_as_sequence */
663+ &proxy_as_mapping, /* tp_as_mapping */
664+ 0, /* tp_hash */
665+ 0, /* tp_call */
666+ proxy_str, /* tp_str */
667+ proxy_getattr, /* tp_getattro */
668+ (setattrofunc)proxy_setattr, /* tp_setattro */
669+ 0, /* tp_as_buffer */
670+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
671+ | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
672+ 0, /* tp_doc */
673+ (traverseproc)gc_traverse, /* tp_traverse */
674+ (inquiry)gc_clear, /* tp_clear */
675+ 0, /* tp_richcompare */
676+ 0, /* tp_weaklistoffset */
677+ (getiterfunc)proxy_iter, /* tp_iter */
678+ (iternextfunc)proxy_iternext, /* tp_iternext */
679+};
680+
681+
682+PyTypeObject
683+_PyWeakref_CallableProxyType = {
684+ PyObject_HEAD_INIT(&PyType_Type)
685+ 0,
686+ "weakcallableproxy",
687+ sizeof(PyWeakReference),
688+ 0,
689+ /* methods */
690+ (destructor)proxy_dealloc, /* tp_dealloc */
691+ 0, /* tp_print */
692+ 0, /* tp_getattr */
693+ 0, /* tp_setattr */
694+ proxy_compare, /* tp_compare */
695+ (unaryfunc)proxy_repr, /* tp_repr */
696+ &proxy_as_number, /* tp_as_number */
697+ &proxy_as_sequence, /* tp_as_sequence */
698+ &proxy_as_mapping, /* tp_as_mapping */
699+ 0, /* tp_hash */
700+ proxy_call, /* tp_call */
701+ proxy_str, /* tp_str */
702+ proxy_getattr, /* tp_getattro */
703+ (setattrofunc)proxy_setattr, /* tp_setattro */
704+ 0, /* tp_as_buffer */
705+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
706+ | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
707+ 0, /* tp_doc */
708+ (traverseproc)gc_traverse, /* tp_traverse */
709+ (inquiry)gc_clear, /* tp_clear */
710+ 0, /* tp_richcompare */
711+ 0, /* tp_weaklistoffset */
712+ (getiterfunc)proxy_iter, /* tp_iter */
713+ (iternextfunc)proxy_iternext, /* tp_iternext */
714+};
715+
716+
717+
718+PyObject *
719+PyWeakref_NewRef(PyObject *ob, PyObject *callback)
720+{
721+ PyWeakReference *result = NULL;
722+ PyWeakReference **list;
723+ PyWeakReference *ref, *proxy;
724+
725+ if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
726+ PyErr_Format(PyExc_TypeError,
727+ "cannot create weak reference to '%s' object",
728+ ob->ob_type->tp_name);
729+ return NULL;
730+ }
731+ list = GET_WEAKREFS_LISTPTR(ob);
732+ get_basic_refs(*list, &ref, &proxy);
733+ if (callback == Py_None)
734+ callback = NULL;
735+ if (callback == NULL)
736+ /* return existing weak reference if it exists */
737+ result = ref;
738+ if (result != NULL)
739+ Py_INCREF(result);
740+ else {
741+ /* Note: new_weakref() can trigger cyclic GC, so the weakref
742+ list on ob can be mutated. This means that the ref and
743+ proxy pointers we got back earlier may have been collected,
744+ so we need to compute these values again before we use
745+ them. */
746+ result = new_weakref(ob, callback);
747+ if (result != NULL) {
748+ get_basic_refs(*list, &ref, &proxy);
749+ if (callback == NULL) {
750+ if (ref == NULL)
751+ insert_head(result, list);
752+ else {
753+ /* Someone else added a ref without a callback
754+ during GC. Return that one instead of this one
755+ to avoid violating the invariants of the list
756+ of weakrefs for ob. */
757+ Py_DECREF(result);
758+ Py_INCREF(ref);
759+ result = ref;
760+ }
761+ }
762+ else {
763+ PyWeakReference *prev;
764+
765+ prev = (proxy == NULL) ? ref : proxy;
766+ if (prev == NULL)
767+ insert_head(result, list);
768+ else
769+ insert_after(result, prev);
770+ }
771+ }
772+ }
773+ return (PyObject *) result;
774+}
775+
776+
777+PyObject *
778+PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
779+{
780+ PyWeakReference *result = NULL;
781+ PyWeakReference **list;
782+ PyWeakReference *ref, *proxy;
783+
784+ if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
785+ PyErr_Format(PyExc_TypeError,
786+ "cannot create weak reference to '%s' object",
787+ ob->ob_type->tp_name);
788+ return NULL;
789+ }
790+ list = GET_WEAKREFS_LISTPTR(ob);
791+ get_basic_refs(*list, &ref, &proxy);
792+ if (callback == Py_None)
793+ callback = NULL;
794+ if (callback == NULL)
795+ /* attempt to return an existing weak reference if it exists */
796+ result = proxy;
797+ if (result != NULL)
798+ Py_INCREF(result);
799+ else {
800+ /* Note: new_weakref() can trigger cyclic GC, so the weakref
801+ list on ob can be mutated. This means that the ref and
802+ proxy pointers we got back earlier may have been collected,
803+ so we need to compute these values again before we use
804+ them. */
805+ result = new_weakref(ob, callback);
806+ if (result != NULL) {
807+ PyWeakReference *prev;
808+
809+ if (PyCallable_Check(ob))
810+ result->ob_type = &_PyWeakref_CallableProxyType;
811+ else
812+ result->ob_type = &_PyWeakref_ProxyType;
813+ get_basic_refs(*list, &ref, &proxy);
814+ if (callback == NULL) {
815+ if (proxy != NULL) {
816+ /* Someone else added a proxy without a callback
817+ during GC. Return that one instead of this one
818+ to avoid violating the invariants of the list
819+ of weakrefs for ob. */
820+ Py_DECREF(result);
821+ Py_INCREF(result = proxy);
822+ goto skip_insert;
823+ }
824+ prev = ref;
825+ }
826+ else
827+ prev = (proxy == NULL) ? ref : proxy;
828+
829+ if (prev == NULL)
830+ insert_head(result, list);
831+ else
832+ insert_after(result, prev);
833+ skip_insert:
834+ ;
835+ }
836+ }
837+ return (PyObject *) result;
838+}
839+
840+
841+PyObject *
842+PyWeakref_GetObject(PyObject *ref)
843+{
844+ if (ref == NULL || !PyWeakref_Check(ref)) {
845+ PyErr_BadInternalCall();
846+ return NULL;
847+ }
848+ return PyWeakref_GET_OBJECT(ref);
849+}
850+
851+/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
852+ * handle_weakrefs().
853+ */
854+static void
855+handle_callback(PyWeakReference *ref, PyObject *callback)
856+{
857+ PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);
858+
859+ if (cbresult == NULL)
860+ PyErr_WriteUnraisable(callback);
861+ else
862+ Py_DECREF(cbresult);
863+}
864+
865+/* This function is called by the tp_dealloc handler to clear weak references.
866+ *
867+ * This iterates through the weak references for 'object' and calls callbacks
868+ * for those references which have one. It returns when all callbacks have
869+ * been attempted.
870+ */
871+void
872+PyObject_ClearWeakRefs(PyObject *object)
873+{
874+ PyWeakReference **list;
875+
876+ if (object == NULL
877+ || !PyType_SUPPORTS_WEAKREFS(object->ob_type)
878+ || object->ob_refcnt != 0) {
879+ PyErr_BadInternalCall();
880+ return;
881+ }
882+ list = GET_WEAKREFS_LISTPTR(object);
883+ /* Remove the callback-less basic and proxy references */
884+ if (*list != NULL && (*list)->wr_callback == NULL) {
885+ clear_weakref(*list);
886+ if (*list != NULL && (*list)->wr_callback == NULL)
887+ clear_weakref(*list);
888+ }
889+ if (*list != NULL) {
890+ PyWeakReference *current = *list;
891+ Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
892+ int restore_error = PyErr_Occurred() ? 1 : 0;
893+ PyObject *err_type, *err_value, *err_tb;
894+
895+ if (restore_error)
896+ PyErr_Fetch(&err_type, &err_value, &err_tb);
897+ if (count == 1) {
898+ PyObject *callback = current->wr_callback;
899+
900+ current->wr_callback = NULL;
901+ clear_weakref(current);
902+ if (callback != NULL) {
903+ handle_callback(current, callback);
904+ Py_DECREF(callback);
905+ }
906+ }
907+ else {
908+ PyObject *tuple;
909+ Py_ssize_t i = 0;
910+
911+ tuple = PyTuple_New(count * 2);
912+ if (tuple == NULL) {
913+ if (restore_error)
914+ PyErr_Fetch(&err_type, &err_value, &err_tb);
915+ return;
916+ }
917+
918+ for (i = 0; i < count; ++i) {
919+ PyWeakReference *next = current->wr_next;
920+
921+ Py_INCREF(current);
922+ PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
923+ PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
924+ current->wr_callback = NULL;
925+ clear_weakref(current);
926+ current = next;
927+ }
928+ for (i = 0; i < count; ++i) {
929+ PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
930+
931+ if (callback != NULL) {
932+ PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
933+ handle_callback((PyWeakReference *)item, callback);
934+ }
935+ }
936+ Py_DECREF(tuple);
937+ }
938+ if (restore_error)
939+ PyErr_Restore(err_type, err_value, err_tb);
940+ }
941+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t