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