blob: c3d3ff092d6816e59e60cf0a74833c3d52278487 [file] [log] [blame]
Fred Drake8844d522001-10-05 21:52:26 +00001#include "Python.h"
2#include "structmember.h"
3
4
5#define GET_WEAKREFS_LISTPTR(o) \
6 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
7
Fred Drake8844d522001-10-05 21:52:26 +00008
Thomas Wouters0e3f5912006-08-11 14:57:12 +00009Py_ssize_t
Fred Drake8844d522001-10-05 21:52:26 +000010_PyWeakref_GetWeakrefCount(PyWeakReference *head)
11{
Thomas Wouters0e3f5912006-08-11 14:57:12 +000012 Py_ssize_t count = 0;
Fred Drake8844d522001-10-05 21:52:26 +000013
14 while (head != NULL) {
15 ++count;
16 head = head->wr_next;
17 }
18 return count;
19}
20
21
Fred Drake0a4dd392004-07-02 18:57:45 +000022static void
23init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
24{
25 self->hash = -1;
26 self->wr_object = ob;
27 Py_XINCREF(callback);
28 self->wr_callback = callback;
29}
30
Fred Drake8844d522001-10-05 21:52:26 +000031static PyWeakReference *
Neil Schemenauer38a89162002-03-27 15:18:21 +000032new_weakref(PyObject *ob, PyObject *callback)
Fred Drake8844d522001-10-05 21:52:26 +000033{
34 PyWeakReference *result;
35
Neil Schemenauer38a89162002-03-27 15:18:21 +000036 result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
37 if (result) {
Fred Drake0a4dd392004-07-02 18:57:45 +000038 init_weakref(result, ob, callback);
Neil Schemenauer38a89162002-03-27 15:18:21 +000039 PyObject_GC_Track(result);
40 }
Fred Drake8844d522001-10-05 21:52:26 +000041 return result;
42}
43
44
45/* This function clears the passed-in reference and removes it from the
46 * list of weak references for the referent. This is the only code that
47 * removes an item from the doubly-linked list of weak references for an
48 * object; it is also responsible for clearing the callback slot.
49 */
50static void
51clear_weakref(PyWeakReference *self)
52{
53 PyObject *callback = self->wr_callback;
54
55 if (PyWeakref_GET_OBJECT(self) != Py_None) {
56 PyWeakReference **list = GET_WEAKREFS_LISTPTR(
57 PyWeakref_GET_OBJECT(self));
58
59 if (*list == self)
Thomas Woutersb2137042007-02-01 18:02:27 +000060 /* 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. */
Fred Drake8844d522001-10-05 21:52:26 +000063 *list = self->wr_next;
64 self->wr_object = Py_None;
Fred Drake8844d522001-10-05 21:52:26 +000065 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;
Tim Peters403a2032003-11-20 21:21:46 +000071 }
72 if (callback != NULL) {
73 Py_DECREF(callback);
74 self->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +000075 }
76}
77
Tim Peters403a2032003-11-20 21:21:46 +000078/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
79 * the callback intact and uncalled. It must be possible to call self's
80 * tp_dealloc() after calling this, so self has to be left in a sane enough
81 * state for that to work. We expect tp_dealloc to decref the callback
82 * then. The reason for not letting clear_weakref() decref the callback
83 * right now is that if the callback goes away, that may in turn trigger
84 * another callback (if a weak reference to the callback exists) -- running
85 * arbitrary Python code in the middle of gc is a disaster. The convolution
86 * here allows gc to delay triggering such callbacks until the world is in
87 * a sane state again.
88 */
89void
90_PyWeakref_ClearRef(PyWeakReference *self)
91{
92 PyObject *callback;
93
94 assert(self != NULL);
95 assert(PyWeakref_Check(self));
96 /* Preserve and restore the callback around clear_weakref. */
97 callback = self->wr_callback;
98 self->wr_callback = NULL;
99 clear_weakref(self);
100 self->wr_callback = callback;
101}
Fred Drake8844d522001-10-05 21:52:26 +0000102
103static void
Fred Drake0a4dd392004-07-02 18:57:45 +0000104weakref_dealloc(PyObject *self)
Fred Drake8844d522001-10-05 21:52:26 +0000105{
Fred Drake0a4dd392004-07-02 18:57:45 +0000106 PyObject_GC_UnTrack(self);
107 clear_weakref((PyWeakReference *) self);
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000108 Py_Type(self)->tp_free(self);
Fred Drake8844d522001-10-05 21:52:26 +0000109}
110
111
112static int
113gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
114{
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000115 Py_VISIT(self->wr_callback);
Fred Drake8844d522001-10-05 21:52:26 +0000116 return 0;
117}
118
119
120static int
121gc_clear(PyWeakReference *self)
122{
123 clear_weakref(self);
124 return 0;
125}
126
127
128static PyObject *
129weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
130{
Martin v. Löwis15e62742006-02-27 16:46:16 +0000131 static char *kwlist[] = {NULL};
Fred Drake8844d522001-10-05 21:52:26 +0000132
Martin v. Löwis15e62742006-02-27 16:46:16 +0000133 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
Fred Drake8844d522001-10-05 21:52:26 +0000134 PyObject *object = PyWeakref_GET_OBJECT(self);
135 Py_INCREF(object);
136 return (object);
137 }
138 return NULL;
139}
140
141
142static long
143weakref_hash(PyWeakReference *self)
144{
145 if (self->hash != -1)
146 return self->hash;
147 if (PyWeakref_GET_OBJECT(self) == Py_None) {
148 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
149 return -1;
150 }
151 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
152 return self->hash;
153}
Tim Peters403a2032003-11-20 21:21:46 +0000154
Fred Drake8844d522001-10-05 21:52:26 +0000155
156static PyObject *
157weakref_repr(PyWeakReference *self)
158{
159 char buffer[256];
160 if (PyWeakref_GET_OBJECT(self) == Py_None) {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000161 PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self);
Fred Drake8844d522001-10-05 21:52:26 +0000162 }
163 else {
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000164 char *name = NULL;
165 PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self),
166 "__name__");
167 if (nameobj == NULL)
168 PyErr_Clear();
Neal Norwitzf616b222007-08-25 08:13:40 +0000169 else if (PyUnicode_Check(nameobj))
170 name = PyUnicode_AsString(nameobj);
Barry Warsawd5867562001-11-28 21:01:56 +0000171 PyOS_snprintf(buffer, sizeof(buffer),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000172 name ? "<weakref at %p; to '%.50s' at %p (%s)>"
173 : "<weakref at %p; to '%.50s' at %p>",
174 self,
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000175 Py_Type(PyWeakref_GET_OBJECT(self))->tp_name,
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000176 PyWeakref_GET_OBJECT(self),
177 name);
178 Py_XDECREF(nameobj);
Fred Drake8844d522001-10-05 21:52:26 +0000179 }
Walter Dörwald1ab83302007-05-18 17:15:44 +0000180 return PyUnicode_FromString(buffer);
Fred Drake8844d522001-10-05 21:52:26 +0000181}
182
183/* Weak references only support equality, not ordering. Two weak references
184 are equal if the underlying objects are equal. If the underlying object has
185 gone away, they are equal if they are identical. */
186
187static PyObject *
188weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
189{
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000190 if ((op != Py_EQ && op != Py_NE) ||
191 !PyWeakref_Check(self) ||
192 !PyWeakref_Check(other)) {
Fred Drake8844d522001-10-05 21:52:26 +0000193 Py_INCREF(Py_NotImplemented);
194 return Py_NotImplemented;
195 }
196 if (PyWeakref_GET_OBJECT(self) == Py_None
197 || PyWeakref_GET_OBJECT(other) == Py_None) {
198 PyObject *res = self==other ? Py_True : Py_False;
199 Py_INCREF(res);
200 return res;
201 }
202 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
203 PyWeakref_GET_OBJECT(other), op);
204}
205
Fred Drake0a4dd392004-07-02 18:57:45 +0000206/* Given the head of an object's list of weak references, extract the
207 * two callback-less refs (ref and proxy). Used to determine if the
208 * shared references exist and to determine the back link for newly
209 * inserted references.
210 */
211static void
212get_basic_refs(PyWeakReference *head,
213 PyWeakReference **refp, PyWeakReference **proxyp)
214{
215 *refp = NULL;
216 *proxyp = NULL;
217
218 if (head != NULL && head->wr_callback == NULL) {
219 /* We need to be careful that the "basic refs" aren't
220 subclasses of the main types. That complicates this a
221 little. */
222 if (PyWeakref_CheckRefExact(head)) {
223 *refp = head;
224 head = head->wr_next;
225 }
226 if (head != NULL
227 && head->wr_callback == NULL
228 && PyWeakref_CheckProxy(head)) {
229 *proxyp = head;
230 /* head = head->wr_next; */
231 }
232 }
233}
234
235/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
236static void
237insert_after(PyWeakReference *newref, PyWeakReference *prev)
238{
239 newref->wr_prev = prev;
240 newref->wr_next = prev->wr_next;
241 if (prev->wr_next != NULL)
242 prev->wr_next->wr_prev = newref;
243 prev->wr_next = newref;
244}
245
246/* Insert 'newref' at the head of the list; 'list' points to the variable
247 * that stores the head.
248 */
249static void
250insert_head(PyWeakReference *newref, PyWeakReference **list)
251{
252 PyWeakReference *next = *list;
253
254 newref->wr_prev = NULL;
255 newref->wr_next = next;
256 if (next != NULL)
257 next->wr_prev = newref;
258 *list = newref;
259}
260
261static int
262parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs,
263 PyObject **obp, PyObject **callbackp)
264{
265 /* XXX Should check that kwargs == NULL or is empty. */
266 return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
267}
268
269static PyObject *
270weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
271{
272 PyWeakReference *self = NULL;
273 PyObject *ob, *callback = NULL;
274
275 if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
276 PyWeakReference *ref, *proxy;
277 PyWeakReference **list;
278
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000279 if (!PyType_SUPPORTS_WEAKREFS(Py_Type(ob))) {
Fred Drake0a4dd392004-07-02 18:57:45 +0000280 PyErr_Format(PyExc_TypeError,
281 "cannot create weak reference to '%s' object",
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000282 Py_Type(ob)->tp_name);
Fred Drake0a4dd392004-07-02 18:57:45 +0000283 return NULL;
284 }
285 if (callback == Py_None)
286 callback = NULL;
287 list = GET_WEAKREFS_LISTPTR(ob);
288 get_basic_refs(*list, &ref, &proxy);
289 if (callback == NULL && type == &_PyWeakref_RefType) {
290 if (ref != NULL) {
291 /* We can re-use an existing reference. */
292 Py_INCREF(ref);
293 return (PyObject *)ref;
294 }
295 }
296 /* We have to create a new reference. */
297 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
298 list on ob can be mutated. This means that the ref and
299 proxy pointers we got back earlier may have been collected,
300 so we need to compute these values again before we use
301 them. */
302 self = (PyWeakReference *) (type->tp_alloc(type, 0));
303 if (self != NULL) {
304 init_weakref(self, ob, callback);
305 if (callback == NULL && type == &_PyWeakref_RefType) {
306 insert_head(self, list);
307 }
308 else {
309 PyWeakReference *prev;
310
311 get_basic_refs(*list, &ref, &proxy);
312 prev = (proxy == NULL) ? ref : proxy;
313 if (prev == NULL)
314 insert_head(self, list);
315 else
316 insert_after(self, prev);
317 }
318 }
319 }
320 return (PyObject *)self;
321}
322
323static int
324weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
325{
326 PyObject *tmp;
327
328 if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
329 return 0;
330 else
331 return 1;
332}
333
Fred Drake8844d522001-10-05 21:52:26 +0000334
335PyTypeObject
336_PyWeakref_RefType = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000337 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000338 "weakref",
339 sizeof(PyWeakReference),
340 0,
Fred Drake0a4dd392004-07-02 18:57:45 +0000341 weakref_dealloc, /*tp_dealloc*/
Fred Drake8844d522001-10-05 21:52:26 +0000342 0, /*tp_print*/
343 0, /*tp_getattr*/
344 0, /*tp_setattr*/
345 0, /*tp_compare*/
346 (reprfunc)weakref_repr, /*tp_repr*/
347 0, /*tp_as_number*/
348 0, /*tp_as_sequence*/
349 0, /*tp_as_mapping*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000350 (hashfunc)weakref_hash, /*tp_hash*/
Fred Drake8844d522001-10-05 21:52:26 +0000351 (ternaryfunc)weakref_call, /*tp_call*/
352 0, /*tp_str*/
353 0, /*tp_getattro*/
354 0, /*tp_setattro*/
355 0, /*tp_as_buffer*/
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000356 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drake0a4dd392004-07-02 18:57:45 +0000357 | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Fred Drake8844d522001-10-05 21:52:26 +0000358 0, /*tp_doc*/
359 (traverseproc)gc_traverse, /*tp_traverse*/
360 (inquiry)gc_clear, /*tp_clear*/
361 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000362 0, /*tp_weaklistoffset*/
363 0, /*tp_iter*/
364 0, /*tp_iternext*/
365 0, /*tp_methods*/
366 0, /*tp_members*/
367 0, /*tp_getset*/
368 0, /*tp_base*/
369 0, /*tp_dict*/
370 0, /*tp_descr_get*/
371 0, /*tp_descr_set*/
372 0, /*tp_dictoffset*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000373 weakref___init__, /*tp_init*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000374 PyType_GenericAlloc, /*tp_alloc*/
375 weakref___new__, /*tp_new*/
376 PyObject_GC_Del, /*tp_free*/
Fred Drake8844d522001-10-05 21:52:26 +0000377};
378
379
380static int
381proxy_checkref(PyWeakReference *proxy)
382{
383 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
384 PyErr_SetString(PyExc_ReferenceError,
385 "weakly-referenced object no longer exists");
386 return 0;
387 }
388 return 1;
389}
390
391
Fred Drake73006d02001-10-18 18:04:18 +0000392/* If a parameter is a proxy, check that it is still "live" and wrap it,
393 * replacing the original value with the raw object. Raises ReferenceError
394 * if the param is a dead proxy.
395 */
396#define UNWRAP(o) \
397 if (PyWeakref_CheckProxy(o)) { \
398 if (!proxy_checkref((PyWeakReference *)o)) \
399 return NULL; \
400 o = PyWeakref_GET_OBJECT(o); \
401 }
402
Fred Drake2a908f62001-12-19 16:44:30 +0000403#define UNWRAP_I(o) \
404 if (PyWeakref_CheckProxy(o)) { \
405 if (!proxy_checkref((PyWeakReference *)o)) \
406 return -1; \
407 o = PyWeakref_GET_OBJECT(o); \
408 }
409
Fred Drake8844d522001-10-05 21:52:26 +0000410#define WRAP_UNARY(method, generic) \
411 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000412 method(PyObject *proxy) { \
413 UNWRAP(proxy); \
414 return generic(proxy); \
Fred Drake8844d522001-10-05 21:52:26 +0000415 }
416
417#define WRAP_BINARY(method, generic) \
418 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000419 method(PyObject *x, PyObject *y) { \
420 UNWRAP(x); \
421 UNWRAP(y); \
422 return generic(x, y); \
Fred Drake8844d522001-10-05 21:52:26 +0000423 }
424
Fred Drake31f4d1f2001-10-18 19:21:46 +0000425/* Note that the third arg needs to be checked for NULL since the tp_call
426 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000427 */
Fred Drake8844d522001-10-05 21:52:26 +0000428#define WRAP_TERNARY(method, generic) \
429 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000430 method(PyObject *proxy, PyObject *v, PyObject *w) { \
431 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000432 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000433 if (w != NULL) \
434 UNWRAP(w); \
435 return generic(proxy, v, w); \
Fred Drake8844d522001-10-05 21:52:26 +0000436 }
437
438
439/* direct slots */
440
441WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
442WRAP_UNARY(proxy_str, PyObject_Str)
443WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
444
Fred Drake8844d522001-10-05 21:52:26 +0000445static PyObject *
446proxy_repr(PyWeakReference *proxy)
447{
448 char buf[160];
Barry Warsawd5867562001-11-28 21:01:56 +0000449 PyOS_snprintf(buf, sizeof(buf),
Guido van Rossumc1f6e8c2003-04-16 21:13:23 +0000450 "<weakproxy at %p to %.100s at %p>", proxy,
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000451 Py_Type(PyWeakref_GET_OBJECT(proxy))->tp_name,
Barry Warsawd5867562001-11-28 21:01:56 +0000452 PyWeakref_GET_OBJECT(proxy));
Walter Dörwald1ab83302007-05-18 17:15:44 +0000453 return PyUnicode_FromString(buf);
Fred Drake8844d522001-10-05 21:52:26 +0000454}
455
456
457static int
458proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
459{
460 if (!proxy_checkref(proxy))
461 return -1;
462 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
463}
464
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000465static PyObject *
466proxy_richcompare(PyObject *proxy, PyObject *v, int op)
Fred Drake8844d522001-10-05 21:52:26 +0000467{
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000468 UNWRAP(proxy);
469 UNWRAP(v);
470 return PyObject_RichCompare(proxy, v, op);
Fred Drake8844d522001-10-05 21:52:26 +0000471}
472
473/* number slots */
474WRAP_BINARY(proxy_add, PyNumber_Add)
475WRAP_BINARY(proxy_sub, PyNumber_Subtract)
476WRAP_BINARY(proxy_mul, PyNumber_Multiply)
Fred Drake8844d522001-10-05 21:52:26 +0000477WRAP_BINARY(proxy_mod, PyNumber_Remainder)
478WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
479WRAP_TERNARY(proxy_pow, PyNumber_Power)
480WRAP_UNARY(proxy_neg, PyNumber_Negative)
481WRAP_UNARY(proxy_pos, PyNumber_Positive)
482WRAP_UNARY(proxy_abs, PyNumber_Absolute)
483WRAP_UNARY(proxy_invert, PyNumber_Invert)
484WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
485WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
486WRAP_BINARY(proxy_and, PyNumber_And)
487WRAP_BINARY(proxy_xor, PyNumber_Xor)
488WRAP_BINARY(proxy_or, PyNumber_Or)
489WRAP_UNARY(proxy_int, PyNumber_Int)
490WRAP_UNARY(proxy_long, PyNumber_Long)
491WRAP_UNARY(proxy_float, PyNumber_Float)
492WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
493WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
494WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
Fred Drake8844d522001-10-05 21:52:26 +0000495WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
496WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
497WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
498WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
499WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
500WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
501WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
502
Tim Peters403a2032003-11-20 21:21:46 +0000503static int
Jack Diederich4dafcc42006-11-28 19:15:13 +0000504proxy_bool(PyWeakReference *proxy)
Fred Drake8844d522001-10-05 21:52:26 +0000505{
506 PyObject *o = PyWeakref_GET_OBJECT(proxy);
507 if (!proxy_checkref(proxy))
Neal Norwitzbdcb9412004-07-08 01:22:31 +0000508 return -1;
Raymond Hettingere6c470f2005-03-27 03:04:54 +0000509 return PyObject_IsTrue(o);
Fred Drake8844d522001-10-05 21:52:26 +0000510}
511
Fred Drake0a4dd392004-07-02 18:57:45 +0000512static void
513proxy_dealloc(PyWeakReference *self)
514{
515 if (self->wr_callback != NULL)
516 PyObject_GC_UnTrack((PyObject *)self);
517 clear_weakref(self);
518 PyObject_GC_Del(self);
519}
520
Fred Drake8844d522001-10-05 21:52:26 +0000521/* sequence slots */
522
Fred Drake8844d522001-10-05 21:52:26 +0000523static int
524proxy_contains(PyWeakReference *proxy, PyObject *value)
525{
526 if (!proxy_checkref(proxy))
527 return -1;
528 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
529}
530
531
532/* mapping slots */
533
Martin v. Löwis18e16552006-02-15 17:27:45 +0000534static Py_ssize_t
Fred Drake8844d522001-10-05 21:52:26 +0000535proxy_length(PyWeakReference *proxy)
536{
537 if (!proxy_checkref(proxy))
538 return -1;
539 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
540}
541
542WRAP_BINARY(proxy_getitem, PyObject_GetItem)
543
544static int
545proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
546{
547 if (!proxy_checkref(proxy))
548 return -1;
Raymond Hettingerd693a812003-06-30 04:18:48 +0000549
550 if (value == NULL)
551 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
552 else
553 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
Fred Drake8844d522001-10-05 21:52:26 +0000554}
555
Fred Drakef16c3dc2002-08-09 18:34:16 +0000556/* iterator slots */
557
558static PyObject *
559proxy_iter(PyWeakReference *proxy)
560{
561 if (!proxy_checkref(proxy))
562 return NULL;
563 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
564}
565
566static PyObject *
567proxy_iternext(PyWeakReference *proxy)
568{
569 if (!proxy_checkref(proxy))
570 return NULL;
571 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
572}
573
Fred Drake8844d522001-10-05 21:52:26 +0000574
575static PyNumberMethods proxy_as_number = {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000576 proxy_add, /*nb_add*/
577 proxy_sub, /*nb_subtract*/
578 proxy_mul, /*nb_multiply*/
579 proxy_mod, /*nb_remainder*/
580 proxy_divmod, /*nb_divmod*/
581 proxy_pow, /*nb_power*/
582 proxy_neg, /*nb_negative*/
583 proxy_pos, /*nb_positive*/
584 proxy_abs, /*nb_absolute*/
Jack Diederich4dafcc42006-11-28 19:15:13 +0000585 (inquiry)proxy_bool, /*nb_bool*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000586 proxy_invert, /*nb_invert*/
587 proxy_lshift, /*nb_lshift*/
588 proxy_rshift, /*nb_rshift*/
589 proxy_and, /*nb_and*/
590 proxy_xor, /*nb_xor*/
591 proxy_or, /*nb_or*/
592 0, /*nb_coerce*/
593 proxy_int, /*nb_int*/
594 proxy_long, /*nb_long*/
595 proxy_float, /*nb_float*/
596 0, /*nb_oct*/
597 0, /*nb_hex*/
598 proxy_iadd, /*nb_inplace_add*/
599 proxy_isub, /*nb_inplace_subtract*/
600 proxy_imul, /*nb_inplace_multiply*/
601 proxy_imod, /*nb_inplace_remainder*/
602 proxy_ipow, /*nb_inplace_power*/
603 proxy_ilshift, /*nb_inplace_lshift*/
604 proxy_irshift, /*nb_inplace_rshift*/
605 proxy_iand, /*nb_inplace_and*/
606 proxy_ixor, /*nb_inplace_xor*/
607 proxy_ior, /*nb_inplace_or*/
Fred Drake8844d522001-10-05 21:52:26 +0000608};
609
610static PySequenceMethods proxy_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000611 (lenfunc)proxy_length, /*sq_length*/
Fred Drake8844d522001-10-05 21:52:26 +0000612 0, /*sq_concat*/
613 0, /*sq_repeat*/
614 0, /*sq_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000615 0, /*sq_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000616 0, /*sq_ass_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000617 0, /*sq_ass_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000618 (objobjproc)proxy_contains, /* sq_contains */
619};
620
621static PyMappingMethods proxy_as_mapping = {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000622 (lenfunc)proxy_length, /*mp_length*/
623 proxy_getitem, /*mp_subscript*/
Fred Drake8844d522001-10-05 21:52:26 +0000624 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
625};
626
627
628PyTypeObject
629_PyWeakref_ProxyType = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000630 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000631 "weakproxy",
632 sizeof(PyWeakReference),
633 0,
634 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000635 (destructor)proxy_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000636 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000637 0, /* tp_getattr */
638 0, /* tp_setattr */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000639 0, /* tp_compare */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000640 (reprfunc)proxy_repr, /* tp_repr */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000641 &proxy_as_number, /* tp_as_number */
642 &proxy_as_sequence, /* tp_as_sequence */
643 &proxy_as_mapping, /* tp_as_mapping */
644 0, /* tp_hash */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000645 0, /* tp_call */
646 proxy_str, /* tp_str */
647 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000648 (setattrofunc)proxy_setattr, /* tp_setattro */
649 0, /* tp_as_buffer */
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000650 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000651 0, /* tp_doc */
652 (traverseproc)gc_traverse, /* tp_traverse */
653 (inquiry)gc_clear, /* tp_clear */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000654 proxy_richcompare, /* tp_richcompare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000655 0, /* tp_weaklistoffset */
656 (getiterfunc)proxy_iter, /* tp_iter */
657 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000658};
659
660
661PyTypeObject
662_PyWeakref_CallableProxyType = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000663 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000664 "weakcallableproxy",
665 sizeof(PyWeakReference),
666 0,
667 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000668 (destructor)proxy_dealloc, /* tp_dealloc */
Fred Drakefe89cc12003-07-14 21:46:23 +0000669 0, /* tp_print */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000670 0, /* tp_getattr */
671 0, /* tp_setattr */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000672 0, /* tp_compare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000673 (unaryfunc)proxy_repr, /* tp_repr */
674 &proxy_as_number, /* tp_as_number */
675 &proxy_as_sequence, /* tp_as_sequence */
676 &proxy_as_mapping, /* tp_as_mapping */
677 0, /* tp_hash */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000678 proxy_call, /* tp_call */
679 proxy_str, /* tp_str */
680 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000681 (setattrofunc)proxy_setattr, /* tp_setattro */
682 0, /* tp_as_buffer */
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000683 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000684 0, /* tp_doc */
685 (traverseproc)gc_traverse, /* tp_traverse */
686 (inquiry)gc_clear, /* tp_clear */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000687 proxy_richcompare, /* tp_richcompare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000688 0, /* tp_weaklistoffset */
689 (getiterfunc)proxy_iter, /* tp_iter */
690 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000691};
692
693
Fred Drake8844d522001-10-05 21:52:26 +0000694
695PyObject *
696PyWeakref_NewRef(PyObject *ob, PyObject *callback)
697{
698 PyWeakReference *result = NULL;
699 PyWeakReference **list;
700 PyWeakReference *ref, *proxy;
701
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000702 if (!PyType_SUPPORTS_WEAKREFS(Py_Type(ob))) {
Fred Drake8844d522001-10-05 21:52:26 +0000703 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000704 "cannot create weak reference to '%s' object",
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000705 Py_Type(ob)->tp_name);
Fred Drake8844d522001-10-05 21:52:26 +0000706 return NULL;
707 }
708 list = GET_WEAKREFS_LISTPTR(ob);
709 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000710 if (callback == Py_None)
711 callback = NULL;
712 if (callback == NULL)
Fred Drake8844d522001-10-05 21:52:26 +0000713 /* return existing weak reference if it exists */
714 result = ref;
715 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000716 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000717 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000718 /* Note: new_weakref() can trigger cyclic GC, so the weakref
719 list on ob can be mutated. This means that the ref and
720 proxy pointers we got back earlier may have been collected,
721 so we need to compute these values again before we use
722 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000723 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000724 if (result != NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000725 get_basic_refs(*list, &ref, &proxy);
Fred Drake8844d522001-10-05 21:52:26 +0000726 if (callback == NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000727 if (ref == NULL)
728 insert_head(result, list);
729 else {
730 /* Someone else added a ref without a callback
731 during GC. Return that one instead of this one
732 to avoid violating the invariants of the list
733 of weakrefs for ob. */
734 Py_DECREF(result);
735 Py_INCREF(ref);
736 result = ref;
737 }
Fred Drake8844d522001-10-05 21:52:26 +0000738 }
739 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000740 PyWeakReference *prev;
Fred Drake8844d522001-10-05 21:52:26 +0000741
Fred Drakebc875f52004-02-04 23:14:14 +0000742 prev = (proxy == NULL) ? ref : proxy;
Fred Drake8844d522001-10-05 21:52:26 +0000743 if (prev == NULL)
744 insert_head(result, list);
745 else
746 insert_after(result, prev);
747 }
Fred Drake8844d522001-10-05 21:52:26 +0000748 }
749 }
750 return (PyObject *) result;
751}
752
753
754PyObject *
755PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
756{
757 PyWeakReference *result = NULL;
758 PyWeakReference **list;
759 PyWeakReference *ref, *proxy;
760
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000761 if (!PyType_SUPPORTS_WEAKREFS(Py_Type(ob))) {
Fred Drake8844d522001-10-05 21:52:26 +0000762 PyErr_Format(PyExc_TypeError,
Jeremy Hylton996fad32001-10-22 16:31:40 +0000763 "cannot create weak reference to '%s' object",
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000764 Py_Type(ob)->tp_name);
Fred Drake8844d522001-10-05 21:52:26 +0000765 return NULL;
766 }
767 list = GET_WEAKREFS_LISTPTR(ob);
768 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000769 if (callback == Py_None)
770 callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000771 if (callback == NULL)
772 /* attempt to return an existing weak reference if it exists */
773 result = proxy;
774 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000775 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000776 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000777 /* Note: new_weakref() can trigger cyclic GC, so the weakref
778 list on ob can be mutated. This means that the ref and
779 proxy pointers we got back earlier may have been collected,
780 so we need to compute these values again before we use
781 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000782 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000783 if (result != NULL) {
784 PyWeakReference *prev;
785
786 if (PyCallable_Check(ob))
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000787 Py_Type(result) = &_PyWeakref_CallableProxyType;
Fred Drake8844d522001-10-05 21:52:26 +0000788 else
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000789 Py_Type(result) = &_PyWeakref_ProxyType;
Fred Drakebc875f52004-02-04 23:14:14 +0000790 get_basic_refs(*list, &ref, &proxy);
Fred Drake6d3265d2004-08-03 14:47:25 +0000791 if (callback == NULL) {
792 if (proxy != NULL) {
793 /* Someone else added a proxy without a callback
794 during GC. Return that one instead of this one
795 to avoid violating the invariants of the list
796 of weakrefs for ob. */
797 Py_DECREF(result);
798 Py_INCREF(result = proxy);
799 goto skip_insert;
800 }
Fred Drake8844d522001-10-05 21:52:26 +0000801 prev = ref;
Fred Drake6d3265d2004-08-03 14:47:25 +0000802 }
Fred Drake8844d522001-10-05 21:52:26 +0000803 else
804 prev = (proxy == NULL) ? ref : proxy;
805
806 if (prev == NULL)
807 insert_head(result, list);
808 else
809 insert_after(result, prev);
Fred Drake6d3265d2004-08-03 14:47:25 +0000810 skip_insert:
811 ;
Fred Drake8844d522001-10-05 21:52:26 +0000812 }
813 }
814 return (PyObject *) result;
815}
816
817
818PyObject *
819PyWeakref_GetObject(PyObject *ref)
820{
821 if (ref == NULL || !PyWeakref_Check(ref)) {
822 PyErr_BadInternalCall();
823 return NULL;
824 }
825 return PyWeakref_GET_OBJECT(ref);
826}
827
Tim Petersead8b7a2004-10-30 23:09:22 +0000828/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
829 * handle_weakrefs().
830 */
Fred Drakeef8ebd12001-12-10 23:44:54 +0000831static void
832handle_callback(PyWeakReference *ref, PyObject *callback)
833{
Thomas Wouters477c8d52006-05-27 19:21:47 +0000834 PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000835
836 if (cbresult == NULL)
837 PyErr_WriteUnraisable(callback);
838 else
839 Py_DECREF(cbresult);
840}
841
842/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000843 *
844 * This iterates through the weak references for 'object' and calls callbacks
845 * for those references which have one. It returns when all callbacks have
846 * been attempted.
847 */
848void
849PyObject_ClearWeakRefs(PyObject *object)
850{
851 PyWeakReference **list;
852
853 if (object == NULL
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000854 || !PyType_SUPPORTS_WEAKREFS(Py_Type(object))
Fred Drake8844d522001-10-05 21:52:26 +0000855 || object->ob_refcnt != 0) {
856 PyErr_BadInternalCall();
857 return;
858 }
859 list = GET_WEAKREFS_LISTPTR(object);
860 /* Remove the callback-less basic and proxy references */
861 if (*list != NULL && (*list)->wr_callback == NULL) {
862 clear_weakref(*list);
863 if (*list != NULL && (*list)->wr_callback == NULL)
864 clear_weakref(*list);
865 }
866 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000867 PyWeakReference *current = *list;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000868 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000869 int restore_error = PyErr_Occurred() ? 1 : 0;
870 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000871
Fred Drakeef8ebd12001-12-10 23:44:54 +0000872 if (restore_error)
873 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000874 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000875 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000876
Fred Drakeef8ebd12001-12-10 23:44:54 +0000877 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000878 clear_weakref(current);
Fred Drake0a4dd392004-07-02 18:57:45 +0000879 if (callback != NULL) {
880 handle_callback(current, callback);
881 Py_DECREF(callback);
882 }
Fred Drake8844d522001-10-05 21:52:26 +0000883 }
884 else {
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000885 PyObject *tuple;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000886 Py_ssize_t i = 0;
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +0000887
888 tuple = PyTuple_New(count * 2);
889 if (tuple == NULL) {
890 if (restore_error)
891 PyErr_Fetch(&err_type, &err_value, &err_tb);
892 return;
893 }
Fred Drake8844d522001-10-05 21:52:26 +0000894
895 for (i = 0; i < count; ++i) {
896 PyWeakReference *next = current->wr_next;
897
898 Py_INCREF(current);
899 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
900 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
901 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000902 clear_weakref(current);
903 current = next;
904 }
905 for (i = 0; i < count; ++i) {
Fred Drake8844d522001-10-05 21:52:26 +0000906 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000907
Fred Drake0a4dd392004-07-02 18:57:45 +0000908 if (callback != NULL) {
Neal Norwitz0c6e2f12006-01-08 06:13:44 +0000909 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
910 handle_callback((PyWeakReference *)item, callback);
Fred Drake0a4dd392004-07-02 18:57:45 +0000911 }
Fred Drake8844d522001-10-05 21:52:26 +0000912 }
913 Py_DECREF(tuple);
914 }
Fred Drakeef8ebd12001-12-10 23:44:54 +0000915 if (restore_error)
916 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000917 }
918}