Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e28d8ae

Browse files
committed
Be more clear about the specific rules for supporting the cyclic GC in an
extension object. Also included an example showing exactly what needs to be done and nothing else. This closes SF bug #228591.
1 parent f5db48e commit e28d8ae

1 file changed

Lines changed: 126 additions & 4 deletions

File tree

Doc/api/api.tex

Lines changed: 126 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4975,10 +4975,10 @@ \section{Supporting Cyclic Garbarge Collection
49754975

49764976
To create a container type, the \member{tp_flags} field of the type
49774977
object must include the \constant{Py_TPFLAGS_GC} and provide an
4978-
implementation of the \member{tp_traverse} handler. The value of the
4979-
\member{tp_basicsize} field must include \constant{PyGC_HEAD_SIZE} as
4980-
well. If instances of the type are mutable, a \member{tp_clear}
4981-
implementation must also be provided.
4978+
implementation of the \member{tp_traverse} handler. The computed
4979+
value of the \member{tp_basicsize} field must include
4980+
\constant{PyGC_HEAD_SIZE} as well. If instances of the type are
4981+
mutable, a \member{tp_clear} implementation must also be provided.
49824982

49834983
\begin{datadesc}{Py_TPFLAGS_GC}
49844984
Objects with a type with this flag set must conform with the rules
@@ -4992,6 +4992,17 @@ \section{Supporting Cyclic Garbarge Collection
49924992
collector is disabled at compile time then this is \code{0}.
49934993
\end{datadesc}
49944994

4995+
Constructors for container types must conform to two rules:
4996+
4997+
\begin{enumerate}
4998+
\item The memory for the object must be allocated using
4999+
\cfunction{PyObject_New()} or \cfunction{PyObject_VarNew()}.
5000+
5001+
\item Once all the fields which may contain references to other
5002+
containers are initialized, it must call
5003+
\cfunction{PyObject_GC_Init()}.
5004+
\end{enumerate}
5005+
49955006
\begin{cfuncdesc}{void}{PyObject_GC_Init}{PyObject *op}
49965007
Adds the object \var{op} to the set of container objects tracked by
49975008
the collector. The collector can run at unexpected times so objects
@@ -5000,6 +5011,17 @@ \section{Supporting Cyclic Garbarge Collection
50005011
usually near the end of the constructor.
50015012
\end{cfuncdesc}
50025013

5014+
Similarly, the deallocator for the object must conform to a similar
5015+
pair of rules:
5016+
5017+
\begin{enumerate}
5018+
\item Before fields which refer to other containers are invalidated,
5019+
\cfunction{PyObject_GC_Fini()} must be called.
5020+
5021+
\item The object's memory must be deallocated using
5022+
\cfunction{PyObject_Del()}.
5023+
\end{enumerate}
5024+
50035025
\begin{cfuncdesc}{void}{PyObject_GC_Fini}{PyObject *op}
50045026
Remove the object \var{op} from the set of container objects tracked
50055027
by the collector. Note that \cfunction{PyObject_GC_Init()} can be
@@ -5045,6 +5067,106 @@ \section{Supporting Cyclic Garbarge Collection
50455067
\end{ctypedesc}
50465068

50475069

5070+
\subsection{Example Cycle Collector Support
5071+
\label{example-cycle-support}}
5072+
5073+
This example shows only enough of the implementation of an extension
5074+
type to show how the garbage collector support needs to be added. It
5075+
shows the definition of the object structure, the
5076+
\member{tp_traverse}, \member{tp_clear} and \member{tp_dealloc}
5077+
implementations, the type structure, and a constructor --- the module
5078+
initialization needed to export the constructor to Python is not shown
5079+
as there are no special considerations there for the collector. To
5080+
make this interesting, assume that the module exposes ways for the
5081+
\member{container} field of the object to be modified. Note that
5082+
since no checks are made on the type of the object used to initialize
5083+
\member{container}, we have to assume that it may be a container.
5084+
5085+
\begin{verbatim}
5086+
#include "Python.h"
5087+
5088+
typedef struct {
5089+
PyObject_HEAD
5090+
PyObject *container;
5091+
} MyObject;
5092+
5093+
static int
5094+
my_traverse(MyObject *self, visitproc visit, void *arg)
5095+
{
5096+
if (self->container != NULL)
5097+
return visit(self->container, arg);
5098+
else
5099+
return 0;
5100+
}
5101+
5102+
static int
5103+
my_clear(MyObject *self)
5104+
{
5105+
Py_XDECREF(self->container);
5106+
self->container = NULL;
5107+
5108+
return 0;
5109+
}
5110+
5111+
static void
5112+
my_dealloc(MyObject *self)
5113+
{
5114+
PyObject_GC_Fini((PyObject *) self);
5115+
Py_XDECREF(self->container);
5116+
PyObject_Del(self);
5117+
}
5118+
\end{verbatim}
5119+
5120+
\begin{verbatim}
5121+
statichere PyTypeObject
5122+
MyObject_Type = {
5123+
PyObject_HEAD_INIT(NULL)
5124+
0,
5125+
"MyObject",
5126+
sizeof(MyObject) + PyGC_HEAD_SIZE,
5127+
0,
5128+
(destructor)my_dealloc, /* tp_dealloc */
5129+
0, /* tp_print */
5130+
0, /* tp_getattr */
5131+
0, /* tp_setattr */
5132+
0, /* tp_compare */
5133+
0, /* tp_repr */
5134+
0, /* tp_as_number */
5135+
0, /* tp_as_sequence */
5136+
0, /* tp_as_mapping */
5137+
0, /* tp_hash */
5138+
0, /* tp_call */
5139+
0, /* tp_str */
5140+
0, /* tp_getattro */
5141+
0, /* tp_setattro */
5142+
0, /* tp_as_buffer */
5143+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,
5144+
0, /* tp_doc */
5145+
(traverseproc)my_traverse, /* tp_traverse */
5146+
(inquiry)my_clear, /* tp_clear */
5147+
0, /* tp_richcompare */
5148+
0, /* tp_weaklistoffset */
5149+
};
5150+
5151+
/* This constructor should be made accessible from Python. */
5152+
static PyObject *
5153+
new_object(PyObject *unused, PyObject *args)
5154+
{
5155+
PyObject *container = NULL;
5156+
MyObject *result = NULL;
5157+
5158+
if (PyArg_ParseTuple(args, "|O:new_object", &container)) {
5159+
result = PyObject_New(MyObject, &MyObject_Type);
5160+
if (result != NULL) {
5161+
result->container = container;
5162+
PyObject_GC_Init();
5163+
}
5164+
}
5165+
return (PyObject *) result;
5166+
}
5167+
\end{verbatim}
5168+
5169+
50485170
% \chapter{Debugging \label{debugging}}
50495171
%
50505172
% XXX Explain Py_DEBUG, Py_TRACE_REFS, Py_REF_DEBUG.

0 commit comments

Comments
 (0)