1 #include "Python.h"
2 #include "pycore_dict.h" // _PyDict_DelItemIf()
3 #include "pycore_object.h" // _PyObject_GET_WEAKREFS_LISTPTR()
4 #include "pycore_weakref.h" // _PyWeakref_IS_DEAD()
5
6 #define GET_WEAKREFS_LISTPTR(o) \
7 ((PyWeakReference **) _PyObject_GET_WEAKREFS_LISTPTR(o))
8
9 /*[clinic input]
10 module _weakref
11 [clinic start generated code]*/
12 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ffec73b85846596d]*/
13
14 #include "clinic/_weakref.c.h"
15
16 /*[clinic input]
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=7d4d04fcaccf64d5]*/
28 {
29 return _PyWeakref_GetWeakrefCount(object);
30 }
31
32
33 static int
is_dead_weakref(PyObject * value,void * unused)34 is_dead_weakref(PyObject *value, void *unused)
35 {
36 if (!PyWeakref_Check(value)) {
37 PyErr_SetString(PyExc_TypeError, "not a weakref");
38 return -1;
39 }
40 return _PyWeakref_IS_DEAD(value);
41 }
42
43 /*[clinic input]
44
45 _weakref._remove_dead_weakref -> object
46
47 dct: object(subclass_of='&PyDict_Type')
48 key: object
49 /
50
51 Atomically remove key from dict if it points to a dead weakref.
52 [clinic start generated code]*/
53
54 static PyObject *
_weakref__remove_dead_weakref_impl(PyObject * module,PyObject * dct,PyObject * key)55 _weakref__remove_dead_weakref_impl(PyObject *module, PyObject *dct,
56 PyObject *key)
57 /*[clinic end generated code: output=d9ff53061fcb875c input=19fc91f257f96a1d]*/
58 {
59 if (_PyDict_DelItemIf(dct, key, is_dead_weakref, NULL) < 0) {
60 return NULL;
61 }
62 Py_RETURN_NONE;
63 }
64
65
66 /*[clinic input]
67 _weakref.getweakrefs
68 object: object
69 /
70
71 Return a list of all weak reference objects pointing to 'object'.
72 [clinic start generated code]*/
73
74 static PyObject *
_weakref_getweakrefs(PyObject * module,PyObject * object)75 _weakref_getweakrefs(PyObject *module, PyObject *object)
76 /*[clinic end generated code: output=25c7731d8e011824 input=00c6d0e5d3206693]*/
77 {
78 if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) {
79 return PyList_New(0);
80 }
81
82 PyObject *result = PyList_New(0);
83 if (result == NULL) {
84 return NULL;
85 }
86
87 LOCK_WEAKREFS(object);
88 PyWeakReference *current = *GET_WEAKREFS_LISTPTR(object);
89 while (current != NULL) {
90 PyObject *curobj = (PyObject *) current;
91 if (_Py_TryIncref(curobj)) {
92 if (PyList_Append(result, curobj)) {
93 UNLOCK_WEAKREFS(object);
94 Py_DECREF(curobj);
95 Py_DECREF(result);
96 return NULL;
97 }
98 else {
99 // Undo our _Py_TryIncref. This is safe to do with the lock
100 // held in free-threaded builds; the list holds a reference to
101 // curobj so we're guaranteed not to invoke the destructor.
102 Py_DECREF(curobj);
103 }
104 }
105 current = current->wr_next;
106 }
107 UNLOCK_WEAKREFS(object);
108 return result;
109 }
110
111
112 /*[clinic input]
113
114 _weakref.proxy
115 object: object
116 callback: object(c_default="NULL") = None
117 /
118
119 Create a proxy object that weakly references 'object'.
120
121 'callback', if given, is called with a reference to the
122 proxy when 'object' is about to be finalized.
123 [clinic start generated code]*/
124
125 static PyObject *
_weakref_proxy_impl(PyObject * module,PyObject * object,PyObject * callback)126 _weakref_proxy_impl(PyObject *module, PyObject *object, PyObject *callback)
127 /*[clinic end generated code: output=d68fa4ad9ea40519 input=4808adf22fd137e7]*/
128 {
129 return PyWeakref_NewProxy(object, callback);
130 }
131
132
133 static PyMethodDef
134 weakref_functions[] = {
135 _WEAKREF_GETWEAKREFCOUNT_METHODDEF
136 _WEAKREF__REMOVE_DEAD_WEAKREF_METHODDEF
137 _WEAKREF_GETWEAKREFS_METHODDEF
138 _WEAKREF_PROXY_METHODDEF
139 {NULL, NULL, 0, NULL}
140 };
141
142 static int
weakref_exec(PyObject * module)143 weakref_exec(PyObject *module)
144 {
145 if (PyModule_AddObjectRef(module, "ref", (PyObject *) &_PyWeakref_RefType) < 0) {
146 return -1;
147 }
148 if (PyModule_AddObjectRef(module, "ReferenceType",
149 (PyObject *) &_PyWeakref_RefType) < 0) {
150 return -1;
151 }
152 if (PyModule_AddObjectRef(module, "ProxyType",
153 (PyObject *) &_PyWeakref_ProxyType) < 0) {
154 return -1;
155 }
156 if (PyModule_AddObjectRef(module, "CallableProxyType",
157 (PyObject *) &_PyWeakref_CallableProxyType) < 0) {
158 return -1;
159 }
160
161 return 0;
162 }
163
164 static struct PyModuleDef_Slot weakref_slots[] = {
165 {Py_mod_exec, weakref_exec},
166 {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
167 {Py_mod_gil, Py_MOD_GIL_NOT_USED},
168 {0, NULL}
169 };
170
171 static struct PyModuleDef weakrefmodule = {
172 PyModuleDef_HEAD_INIT,
173 "_weakref",
174 "Weak-reference support module.",
175 0,
176 weakref_functions,
177 weakref_slots,
178 NULL,
179 NULL,
180 NULL
181 };
182
183 PyMODINIT_FUNC
PyInit__weakref(void)184 PyInit__weakref(void)
185 {
186 return PyModuleDef_Init(&weakrefmodule);
187 }
188