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