cpython/Objects/weakrefobject.c

#include "Python.h"
#include "pycore_critical_section.h"
#include "pycore_lock.h"
#include "pycore_modsupport.h"    // _PyArg_NoKwnames()
#include "pycore_object.h"        // _PyObject_GET_WEAKREFS_LISTPTR()
#include "pycore_pyerrors.h"      // _PyErr_ChainExceptions1()
#include "pycore_pystate.h"
#include "pycore_weakref.h"       // _PyWeakref_GET_REF()

#ifdef Py_GIL_DISABLED
/*
 * Thread-safety for free-threaded builds
 * ======================================
 *
 * In free-threaded builds we need to protect mutable state of:
 *
 * - The weakref (wr_object, hash, wr_callback)
 * - The referenced object (its head-of-list pointer)
 * - The linked list of weakrefs
 *
 * For now we've chosen to address this in a straightforward way:
 *
 * - The weakref's hash is protected using the weakref's per-object lock.
 * - The other mutable is protected by a striped lock keyed on the referenced
 *   object's address.
 * - The striped lock must be locked using `_Py_LOCK_DONT_DETACH` in order to
 *   support atomic deletion from WeakValueDictionaries. As a result, we must
 *   be careful not to perform any operations that could suspend while the
 *   lock is held.
 *
 * Since the world is stopped when the GC runs, it is free to clear weakrefs
 * without acquiring any locks.
 */

#endif

#define GET_WEAKREFS_LISTPTR(o)


Py_ssize_t
_PyWeakref_GetWeakrefCount(PyObject *obj)
{}

static PyObject *weakref_vectorcall(PyObject *self, PyObject *const *args, size_t nargsf, PyObject *kwnames);

static void
init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
{}

// Clear the weakref and steal its callback into `callback`, if provided.
static void
clear_weakref_lock_held(PyWeakReference *self, PyObject **callback)
{}

// Clear the weakref and its callback
static void
clear_weakref(PyObject *op)
{}


/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
 * the callback intact and uncalled.  It must be possible to call self's
 * tp_dealloc() after calling this, so self has to be left in a sane enough
 * state for that to work.  We expect tp_dealloc to decref the callback
 * then.  The reason for not letting clear_weakref() decref the callback
 * right now is that if the callback goes away, that may in turn trigger
 * another callback (if a weak reference to the callback exists) -- running
 * arbitrary Python code in the middle of gc is a disaster.  The convolution
 * here allows gc to delay triggering such callbacks until the world is in
 * a sane state again.
 */
void
_PyWeakref_ClearRef(PyWeakReference *self)
{}

static void
weakref_dealloc(PyObject *self)
{}


static int
gc_traverse(PyObject *op, visitproc visit, void *arg)
{}


static int
gc_clear(PyObject *op)
{}


static PyObject *
weakref_vectorcall(PyObject *self, PyObject *const *args,
                   size_t nargsf, PyObject *kwnames)
{}

static Py_hash_t
weakref_hash_lock_held(PyWeakReference *self)
{}

static Py_hash_t
weakref_hash(PyObject *op)
{}

static PyObject *
weakref_repr(PyObject *self)
{}

/* Weak references only support equality, not ordering. Two weak references
   are equal if the underlying objects are equal. If the underlying object has
   gone away, they are equal if they are identical. */

static PyObject *
weakref_richcompare(PyObject* self, PyObject* other, int op)
{}

/* Given the head of an object's list of weak references, extract the
 * two callback-less refs (ref and proxy).  Used to determine if the
 * shared references exist and to determine the back link for newly
 * inserted references.
 */
static void
get_basic_refs(PyWeakReference *head,
               PyWeakReference **refp, PyWeakReference **proxyp)
{}

/* Insert 'newref' in the list after 'prev'.  Both must be non-NULL. */
static void
insert_after(PyWeakReference *newref, PyWeakReference *prev)
{}

/* Insert 'newref' at the head of the list; 'list' points to the variable
 * that stores the head.
 */
static void
insert_head(PyWeakReference *newref, PyWeakReference **list)
{}

/* See if we can reuse either the basic ref or proxy in list instead of
 * creating a new weakref
 */
static PyWeakReference *
try_reuse_basic_ref(PyWeakReference *list, PyTypeObject *type,
                    PyObject *callback)
{}

static int
is_basic_ref(PyWeakReference *ref)
{}

static int
is_basic_proxy(PyWeakReference *proxy)
{}

static int
is_basic_ref_or_proxy(PyWeakReference *wr)
{}

/* Insert `newref` in the appropriate position in `list` */
static void
insert_weakref(PyWeakReference *newref, PyWeakReference **list)
{}

static PyWeakReference *
allocate_weakref(PyTypeObject *type, PyObject *obj, PyObject *callback)
{}

static PyWeakReference *
get_or_create_weakref(PyTypeObject *type, PyObject *obj, PyObject *callback)
{}

static int
parse_weakref_init_args(const char *funcname, PyObject *args, PyObject *kwargs,
                        PyObject **obp, PyObject **callbackp)
{}

static PyObject *
weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{}

static int
weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
{}


static PyMemberDef weakref_members[] =;

static PyMethodDef weakref_methods[] =;

PyTypeObject
_PyWeakref_RefType =;


static bool
proxy_check_ref(PyObject *obj)
{}


/* If a parameter is a proxy, check that it is still "live" and wrap it,
 * replacing the original value with the raw object.  Raises ReferenceError
 * if the param is a dead proxy.
 */
#define UNWRAP(o)

#define WRAP_UNARY(method, generic)

#define WRAP_BINARY(method, generic)

/* Note that the third arg needs to be checked for NULL since the tp_call
 * slot can receive NULL for this arg.
 */
#define WRAP_TERNARY(method, generic)

#define WRAP_METHOD(method, SPECIAL)


/* direct slots */

WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
WRAP_UNARY(proxy_str, PyObject_Str)
WRAP_TERNARY(proxy_call, PyObject_Call)

static PyObject *
proxy_repr(PyObject *proxy)
{}


static int
proxy_setattr(PyObject *proxy, PyObject *name, PyObject *value)
{}

static PyObject *
proxy_richcompare(PyObject *proxy, PyObject *v, int op)
{}

/* number slots */
WRAP_BINARY(proxy_add, PyNumber_Add)
WRAP_BINARY(proxy_sub, PyNumber_Subtract)
WRAP_BINARY(proxy_mul, PyNumber_Multiply)
WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
WRAP_BINARY(proxy_mod, PyNumber_Remainder)
WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
WRAP_TERNARY(proxy_pow, PyNumber_Power)
WRAP_UNARY(proxy_neg, PyNumber_Negative)
WRAP_UNARY(proxy_pos, PyNumber_Positive)
WRAP_UNARY(proxy_abs, PyNumber_Absolute)
WRAP_UNARY(proxy_invert, PyNumber_Invert)
WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
WRAP_BINARY(proxy_and, PyNumber_And)
WRAP_BINARY(proxy_xor, PyNumber_Xor)
WRAP_BINARY(proxy_or, PyNumber_Or)
WRAP_UNARY(proxy_int, PyNumber_Long)
WRAP_UNARY(proxy_float, PyNumber_Float)
WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
WRAP_UNARY(proxy_index, PyNumber_Index)
WRAP_BINARY(proxy_matmul, PyNumber_MatrixMultiply)
WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply)

static int
proxy_bool(PyObject *proxy)
{}

static void
proxy_dealloc(PyObject *self)
{}

/* sequence slots */

static int
proxy_contains(PyObject *proxy, PyObject *value)
{}

/* mapping slots */

static Py_ssize_t
proxy_length(PyObject *proxy)
{}

WRAP_BINARY(proxy_getitem, PyObject_GetItem)

static int
proxy_setitem(PyObject *proxy, PyObject *key, PyObject *value)
{}

/* iterator slots */

static PyObject *
proxy_iter(PyObject *proxy)
{}

static PyObject *
proxy_iternext(PyObject *proxy)
{}


WRAP_METHOD()
WRAP_METHOD()


static PyMethodDef proxy_methods[] =;


static PyNumberMethods proxy_as_number =;

static PySequenceMethods proxy_as_sequence =;

static PyMappingMethods proxy_as_mapping =;


PyTypeObject
_PyWeakref_ProxyType =;


PyTypeObject
_PyWeakref_CallableProxyType =;

PyObject *
PyWeakref_NewRef(PyObject *ob, PyObject *callback)
{}

PyObject *
PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
{}


int
PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
{}


PyObject *
PyWeakref_GetObject(PyObject *ref)
{}

/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
 * handle_weakrefs().
 */
static void
handle_callback(PyWeakReference *ref, PyObject *callback)
{}

/* This function is called by the tp_dealloc handler to clear weak references.
 *
 * This iterates through the weak references for 'object' and calls callbacks
 * for those references which have one.  It returns when all callbacks have
 * been attempted.
 */
void
PyObject_ClearWeakRefs(PyObject *object)
{}

void
PyUnstable_Object_ClearWeakRefsNoCallbacks(PyObject *obj)
{}

/* This function is called by _PyStaticType_Dealloc() to clear weak references.
 *
 * This is called at the end of runtime finalization, so we can just
 * wipe out the type's weaklist.  We don't bother with callbacks
 * or anything else.
 */
void
_PyStaticType_ClearWeakRefs(PyInterpreterState *interp, PyTypeObject *type)
{}

void
_PyWeakref_ClearWeakRefsNoCallbacks(PyObject *obj)
{}

int
_PyWeakref_IsDead(PyObject *weakref)
{}