summaryrefslogtreecommitdiffstats
path: root/Doc
diff options
context:
space:
mode:
Diffstat (limited to 'Doc')
-rw-r--r--Doc/api/api.tex130
1 files changed, 126 insertions, 4 deletions
diff --git a/Doc/api/api.tex b/Doc/api/api.tex
index 5ff8fda..5726341 100644
--- a/Doc/api/api.tex
+++ b/Doc/api/api.tex
@@ -4975,10 +4975,10 @@ to provide any explicit support for garbage collection.
To create a container type, the \member{tp_flags} field of the type
object must include the \constant{Py_TPFLAGS_GC} and provide an
-implementation of the \member{tp_traverse} handler. The value of the
-\member{tp_basicsize} field must include \constant{PyGC_HEAD_SIZE} as
-well. If instances of the type are mutable, a \member{tp_clear}
-implementation must also be provided.
+implementation of the \member{tp_traverse} handler. The computed
+value of the \member{tp_basicsize} field must include
+\constant{PyGC_HEAD_SIZE} as well. If instances of the type are
+mutable, a \member{tp_clear} implementation must also be provided.
\begin{datadesc}{Py_TPFLAGS_GC}
Objects with a type with this flag set must conform with the rules
@@ -4992,6 +4992,17 @@ implementation must also be provided.
collector is disabled at compile time then this is \code{0}.
\end{datadesc}
+Constructors for container types must conform to two rules:
+
+\begin{enumerate}
+\item The memory for the object must be allocated using
+ \cfunction{PyObject_New()} or \cfunction{PyObject_VarNew()}.
+
+\item Once all the fields which may contain references to other
+ containers are initialized, it must call
+ \cfunction{PyObject_GC_Init()}.
+\end{enumerate}
+
\begin{cfuncdesc}{void}{PyObject_GC_Init}{PyObject *op}
Adds the object \var{op} to the set of container objects tracked by
the collector. The collector can run at unexpected times so objects
@@ -5000,6 +5011,17 @@ implementation must also be provided.
usually near the end of the constructor.
\end{cfuncdesc}
+Similarly, the deallocator for the object must conform to a similar
+pair of rules:
+
+\begin{enumerate}
+\item Before fields which refer to other containers are invalidated,
+ \cfunction{PyObject_GC_Fini()} must be called.
+
+\item The object's memory must be deallocated using
+ \cfunction{PyObject_Del()}.
+\end{enumerate}
+
\begin{cfuncdesc}{void}{PyObject_GC_Fini}{PyObject *op}
Remove the object \var{op} from the set of container objects tracked
by the collector. Note that \cfunction{PyObject_GC_Init()} can be
@@ -5045,6 +5067,106 @@ The \member{tp_clear} handler must be of the \ctype{inquiry} type, or
\end{ctypedesc}
+\subsection{Example Cycle Collector Support
+ \label{example-cycle-support}}
+
+This example shows only enough of the implementation of an extension
+type to show how the garbage collector support needs to be added. It
+shows the definition of the object structure, the
+\member{tp_traverse}, \member{tp_clear} and \member{tp_dealloc}
+implementations, the type structure, and a constructor --- the module
+initialization needed to export the constructor to Python is not shown
+as there are no special considerations there for the collector. To
+make this interesting, assume that the module exposes ways for the
+\member{container} field of the object to be modified. Note that
+since no checks are made on the type of the object used to initialize
+\member{container}, we have to assume that it may be a container.
+
+\begin{verbatim}
+#include "Python.h"
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *container;
+} MyObject;
+
+static int
+my_traverse(MyObject *self, visitproc visit, void *arg)
+{
+ if (self->container != NULL)
+ return visit(self->container, arg);
+ else
+ return 0;
+}
+
+static int
+my_clear(MyObject *self)
+{
+ Py_XDECREF(self->container);
+ self->container = NULL;
+
+ return 0;
+}
+
+static void
+my_dealloc(MyObject *self)
+{
+ PyObject_GC_Fini((PyObject *) self);
+ Py_XDECREF(self->container);
+ PyObject_Del(self);
+}
+\end{verbatim}
+
+\begin{verbatim}
+statichere PyTypeObject
+MyObject_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "MyObject",
+ sizeof(MyObject) + PyGC_HEAD_SIZE,
+ 0,
+ (destructor)my_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,
+ 0, /* tp_doc */
+ (traverseproc)my_traverse, /* tp_traverse */
+ (inquiry)my_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+};
+
+/* This constructor should be made accessible from Python. */
+static PyObject *
+new_object(PyObject *unused, PyObject *args)
+{
+ PyObject *container = NULL;
+ MyObject *result = NULL;
+
+ if (PyArg_ParseTuple(args, "|O:new_object", &container)) {
+ result = PyObject_New(MyObject, &MyObject_Type);
+ if (result != NULL) {
+ result->container = container;
+ PyObject_GC_Init();
+ }
+ }
+ return (PyObject *) result;
+}
+\end{verbatim}
+
+
% \chapter{Debugging \label{debugging}}
%
% XXX Explain Py_DEBUG, Py_TRACE_REFS, Py_REF_DEBUG.