xref: /petsc/src/binding/petsc4py/src/petsc4py/PETSc/cyclicgc.pxi (revision 8577b683712d1cca1e9b8fdaa9ae028364224dad)
1# --------------------------------------------------------------------
2
3cdef extern from * nogil:
4    int printf(char *, ...)
5
6cdef extern from "Python.h":
7    """
8    #if defined(Py_LIMITED_API)
9    #define _pytype_enable_gc(t, traverse, clear) \
10    do { (void)(traverse); (void)(clear); } while (0)
11    #else
12    #define _pytype_enable_gc(t, traverse, clear) \
13    do { (t)->tp_traverse = (traverse); (t)->tp_clear = (clear); } while (0)
14    #endif
15    #if PY_VERSION_HEX < 0x030B0000 && !defined(Py_Version)
16    #define Py_Version __Pyx_get_runtime_version()
17    #endif
18    """
19    const unsigned long Py_Version
20    enum: Py_TPFLAGS_HEAPTYPE
21    ctypedef struct PyObject
22    ctypedef struct PyTypeObject
23    void Py_VISIT(void*) noexcept
24    PyTypeObject *Py_TYPE(PyObject *) noexcept
25    unsigned long PyType_GetFlags(PyTypeObject *type) noexcept
26    ctypedef int (*visitproc)(PyObject *, void *) noexcept
27    ctypedef int (*traverseproc)(PyObject *, visitproc, void *) noexcept
28    ctypedef int (*inquiry)(PyObject *) noexcept
29    void _pytype_enable_gc(PyTypeObject *, traverseproc, inquiry)
30
31cdef extern from "<petsc/private/garbagecollector.h>" nogil:
32    PetscErrorCode PetscGarbageCleanup(MPI_Comm)
33    PetscErrorCode PetscGarbageView(MPI_Comm, PetscViewer)
34
35cdef int tp_traverse(PyObject *o, visitproc _visit, void *_arg) noexcept:
36    cdef visitproc visit "visit" = _visit
37    cdef void *arg "arg" = _arg
38    <void> visit
39    <void> arg
40    if Py_Version >= 0x03090000:
41        if not (PyType_GetFlags(Py_TYPE(o)) & Py_TPFLAGS_HEAPTYPE):
42            Py_VISIT(Py_TYPE(o))
43    cdef PetscObject p = (<Object>o).obj[0]
44    if p == NULL: return 0
45    cdef PyObject *d = <PyObject*>p.python_context
46    if d == NULL: return 0
47    Py_VISIT(d)
48    return 0
49
50cdef int tp_clear(PyObject *o) noexcept:
51    cdef PetscObject *p = (<Object>o).obj
52    PetscDEALLOC(p)
53    return 0
54
55cdef inline void TypeEnableGC(PyTypeObject *t) noexcept:
56    _pytype_enable_gc(t, tp_traverse, tp_clear)
57
58
59def garbage_cleanup(comm: Comm | None = None) -> None:
60    """Clean up unused PETSc objects.
61
62    Collective.
63
64    Notes
65    -----
66    If the communicator ``comm`` if not provided or it is `None`,
67    then `COMM_WORLD` is used.
68
69    """
70    if not (<int>PetscInitializeCalled): return
71    if (<int>PetscFinalizeCalled): return
72    cdef MPI_Comm ccomm = MPI_COMM_NULL
73    if comm is None:
74        ccomm = GetComm(COMM_WORLD, MPI_COMM_NULL)
75        CHKERR(PetscGarbageCleanup(ccomm))
76    else:
77        ccomm = GetComm(comm, MPI_COMM_NULL)
78        if ccomm == MPI_COMM_NULL:
79            raise ValueError("null communicator")
80        CHKERR(PetscGarbageCleanup(ccomm))
81
82
83def garbage_view(comm: Comm | None = None) -> None:
84    """Print summary of the garbage PETSc objects.
85
86    Collective.
87
88    Notes
89    -----
90    Print out garbage summary on each rank of the communicator ``comm``.
91    If no communicator is provided then `COMM_WORLD` is used.
92
93    """
94    if not (<int>PetscInitializeCalled): return
95    if (<int>PetscFinalizeCalled): return
96    cdef MPI_Comm ccomm = MPI_COMM_NULL
97    if comm is None:
98        comm = COMM_WORLD
99    ccomm = GetComm(comm, MPI_COMM_NULL)
100    if ccomm == MPI_COMM_NULL:
101        raise ValueError("null communicator")
102    CHKERR(PetscGarbageView(ccomm, NULL))
103
104# --------------------------------------------------------------------
105