• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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