• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "Python.h"
2 #include "pycore_object.h"   // _PyObject_GET_WEAKREFS_LISTPTR
3 
4 
5 #define GET_WEAKREFS_LISTPTR(o) \
6         ((PyWeakReference **) _PyObject_GET_WEAKREFS_LISTPTR(o))
7 
8 /*[clinic input]
9 module _weakref
10 [clinic start generated code]*/
11 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ffec73b85846596d]*/
12 
13 #include "clinic/_weakref.c.h"
14 
15 /*[clinic input]
16 
17 _weakref.getweakrefcount -> Py_ssize_t
18 
19   object: object
20   /
21 
22 Return the number of weak references to 'object'.
23 [clinic start generated code]*/
24 
25 static Py_ssize_t
_weakref_getweakrefcount_impl(PyObject * module,PyObject * object)26 _weakref_getweakrefcount_impl(PyObject *module, PyObject *object)
27 /*[clinic end generated code: output=301806d59558ff3e input=cedb69711b6a2507]*/
28 {
29     PyWeakReference **list;
30 
31     if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(object)))
32         return 0;
33 
34     list = GET_WEAKREFS_LISTPTR(object);
35     return _PyWeakref_GetWeakrefCount(*list);
36 }
37 
38 
39 static int
is_dead_weakref(PyObject * value)40 is_dead_weakref(PyObject *value)
41 {
42     if (!PyWeakref_Check(value)) {
43         PyErr_SetString(PyExc_TypeError, "not a weakref");
44         return -1;
45     }
46     return PyWeakref_GET_OBJECT(value) == Py_None;
47 }
48 
49 /*[clinic input]
50 
51 _weakref._remove_dead_weakref -> object
52 
53   dct: object(subclass_of='&PyDict_Type')
54   key: object
55   /
56 
57 Atomically remove key from dict if it points to a dead weakref.
58 [clinic start generated code]*/
59 
60 static PyObject *
_weakref__remove_dead_weakref_impl(PyObject * module,PyObject * dct,PyObject * key)61 _weakref__remove_dead_weakref_impl(PyObject *module, PyObject *dct,
62                                    PyObject *key)
63 /*[clinic end generated code: output=d9ff53061fcb875c input=19fc91f257f96a1d]*/
64 {
65     if (_PyDict_DelItemIf(dct, key, is_dead_weakref) < 0) {
66         if (PyErr_ExceptionMatches(PyExc_KeyError))
67             /* This function is meant to allow safe weak-value dicts
68                with GC in another thread (see issue #28427), so it's
69                ok if the key doesn't exist anymore.
70                */
71             PyErr_Clear();
72         else
73             return NULL;
74     }
75     Py_RETURN_NONE;
76 }
77 
78 
79 PyDoc_STRVAR(weakref_getweakrefs__doc__,
80 "getweakrefs(object) -- return a list of all weak reference objects\n"
81 "that point to 'object'.");
82 
83 static PyObject *
weakref_getweakrefs(PyObject * self,PyObject * object)84 weakref_getweakrefs(PyObject *self, PyObject *object)
85 {
86     PyObject *result = NULL;
87 
88     if (PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) {
89         PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
90         Py_ssize_t count = _PyWeakref_GetWeakrefCount(*list);
91 
92         result = PyList_New(count);
93         if (result != NULL) {
94             PyWeakReference *current = *list;
95             Py_ssize_t i;
96             for (i = 0; i < count; ++i) {
97                 PyList_SET_ITEM(result, i, (PyObject *) current);
98                 Py_INCREF(current);
99                 current = current->wr_next;
100             }
101         }
102     }
103     else {
104         result = PyList_New(0);
105     }
106     return result;
107 }
108 
109 
110 PyDoc_STRVAR(weakref_proxy__doc__,
111 "proxy(object[, callback]) -- create a proxy object that weakly\n"
112 "references 'object'.  'callback', if given, is called with a\n"
113 "reference to the proxy when 'object' is about to be finalized.");
114 
115 static PyObject *
weakref_proxy(PyObject * self,PyObject * args)116 weakref_proxy(PyObject *self, PyObject *args)
117 {
118     PyObject *object;
119     PyObject *callback = NULL;
120     PyObject *result = NULL;
121 
122     if (PyArg_UnpackTuple(args, "proxy", 1, 2, &object, &callback)) {
123         result = PyWeakref_NewProxy(object, callback);
124     }
125     return result;
126 }
127 
128 
129 static PyMethodDef
130 weakref_functions[] =  {
131     _WEAKREF_GETWEAKREFCOUNT_METHODDEF
132     _WEAKREF__REMOVE_DEAD_WEAKREF_METHODDEF
133     {"getweakrefs",     weakref_getweakrefs,            METH_O,
134      weakref_getweakrefs__doc__},
135     {"proxy",           weakref_proxy,                  METH_VARARGS,
136      weakref_proxy__doc__},
137     {NULL, NULL, 0, NULL}
138 };
139 
140 static int
weakref_exec(PyObject * module)141 weakref_exec(PyObject *module)
142 {
143     Py_INCREF(&_PyWeakref_RefType);
144     if (PyModule_AddObject(module, "ref", (PyObject *) &_PyWeakref_RefType) < 0) {
145         Py_DECREF(&_PyWeakref_RefType);
146         return -1;
147     }
148     Py_INCREF(&_PyWeakref_RefType);
149     if (PyModule_AddObject(module, "ReferenceType",
150                            (PyObject *) &_PyWeakref_RefType) < 0) {
151         Py_DECREF(&_PyWeakref_RefType);
152         return -1;
153     }
154     Py_INCREF(&_PyWeakref_ProxyType);
155     if (PyModule_AddObject(module, "ProxyType",
156                            (PyObject *) &_PyWeakref_ProxyType) < 0) {
157         Py_DECREF(&_PyWeakref_ProxyType);
158         return -1;
159     }
160     Py_INCREF(&_PyWeakref_CallableProxyType);
161     if (PyModule_AddObject(module, "CallableProxyType",
162                            (PyObject *) &_PyWeakref_CallableProxyType) < 0) {
163         Py_DECREF(&_PyWeakref_CallableProxyType);
164         return -1;
165     }
166 
167     return 0;
168 }
169 
170 static struct PyModuleDef_Slot weakref_slots[] = {
171     {Py_mod_exec, weakref_exec},
172     {0, NULL}
173 };
174 
175 static struct PyModuleDef weakrefmodule = {
176     PyModuleDef_HEAD_INIT,
177     "_weakref",
178     "Weak-reference support module.",
179     0,
180     weakref_functions,
181     weakref_slots,
182     NULL,
183     NULL,
184     NULL
185 };
186 
187 PyMODINIT_FUNC
PyInit__weakref(void)188 PyInit__weakref(void)
189 {
190     return PyModuleDef_Init(&weakrefmodule);
191 }
192