Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / amd64 / html / python / ext / node24.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<link rel="STYLESHEET" href="ext.css" type='text/css' />
<link rel="SHORTCUT ICON" href="../icons/pyfav.png" type="image/png" />
<link rel='start' href='../index.html' title='Python Documentation Index' />
<link rel="first" href="ext.html" title='Extending and Embedding the Python Interpreter' />
<link rel='contents' href='contents.html' title="Contents" />
<link rel='last' href='about.html' title='About this document...' />
<link rel='help' href='about.html' title='About this document...' />
<link rel="prev" href="node23.html" />
<link rel="parent" href="dnt-basics.html" />
<link rel="next" href="dnt-type-methods.html" />
<meta name='aesop' content='information' />
<title>2.1.3 Supporting cyclic garbage collection</title>
</head>
<body>
<DIV CLASS="navigation">
<div id='top-navigation-panel' xml:id='top-navigation-panel'>
<table align="center" width="100%" cellpadding="0" cellspacing="2">
<tr>
<td class='online-navigation'><a rel="prev" title="2.1.2 Providing finer control"
href="node23.html"><img src='../icons/previous.png'
border='0' height='32' alt='Previous Page' width='32' /></A></td>
<td class='online-navigation'><a rel="parent" title="2.1 The Basics"
href="dnt-basics.html"><img src='../icons/up.png'
border='0' height='32' alt='Up One Level' width='32' /></A></td>
<td class='online-navigation'><a rel="next" title="2.2 Type Methods"
href="dnt-type-methods.html"><img src='../icons/next.png'
border='0' height='32' alt='Next Page' width='32' /></A></td>
<td align="center" width="100%">Extending and Embedding the Python Interpreter</td>
<td class='online-navigation'><a rel="contents" title="Table of Contents"
href="contents.html"><img src='../icons/contents.png'
border='0' height='32' alt='Contents' width='32' /></A></td>
<td class='online-navigation'><img src='../icons/blank.png'
border='0' height='32' alt='' width='32' /></td>
<td class='online-navigation'><img src='../icons/blank.png'
border='0' height='32' alt='' width='32' /></td>
</tr></table>
<div class='online-navigation'>
<b class="navlabel">Previous:</b>
<a class="sectref" rel="prev" href="node23.html">2.1.2 Providing finer control</A>
<b class="navlabel">Up:</b>
<a class="sectref" rel="parent" href="dnt-basics.html">2.1 The Basics</A>
<b class="navlabel">Next:</b>
<a class="sectref" rel="next" href="dnt-type-methods.html">2.2 Type Methods</A>
</div>
<hr /></div>
</DIV>
<!--End of Navigation Panel-->
<H2><A NAME="SECTION004130000000000000000">
2.1.3 Supporting cyclic garbage collection</A>
</H2>
<P>
Python has a cyclic-garbage collector that can identify unneeded
objects even when their reference counts are not zero. This can happen
when objects are involved in cycles. For example, consider:
<P>
<div class="verbatim"><pre>
&gt;&gt;&gt; l = []
&gt;&gt;&gt; l.append(l)
&gt;&gt;&gt; del l
</pre></div>
<P>
In this example, we create a list that contains itself. When we delete
it, it still has a reference from itself. Its reference count doesn't
drop to zero. Fortunately, Python's cyclic-garbage collector will
eventually figure out that the list is garbage and free it.
<P>
In the second version of the <tt class="class">Noddy</tt> example, we allowed any
kind of object to be stored in the <tt class="member">first</tt> or <tt class="member">last</tt>
attributes<A NAME="tex2html8"
HREF="#foot1173"><SUP>2.4</SUP></A>. This
means that <tt class="class">Noddy</tt> objects can participate in cycles:
<P>
<div class="verbatim"><pre>
&gt;&gt;&gt; import noddy2
&gt;&gt;&gt; n = noddy2.Noddy()
&gt;&gt;&gt; l = [n]
&gt;&gt;&gt; n.first = l
</pre></div>
<P>
This is pretty silly, but it gives us an excuse to add support for the
cyclic-garbage collector to the <tt class="class">Noddy</tt> example. To support
cyclic garbage collection, types need to fill two slots and set a
class flag that enables these slots:
<P>
<div class="verbatim">
<pre>#include &lt;Python.h&gt;
#include "structmember.h"
typedef struct {
PyObject_HEAD
PyObject *first;
PyObject *last;
int number;
} Noddy;
static int
Noddy_traverse(Noddy *self, visitproc visit, void *arg)
{
int vret;
if (self-&gt;first) {
vret = visit(self-&gt;first, arg);
if (vret != 0)
return vret;
}
if (self-&gt;last) {
vret = visit(self-&gt;last, arg);
if (vret != 0)
return vret;
}
return 0;
}
static int
Noddy_clear(Noddy *self)
{
PyObject *tmp;
tmp = self-&gt;first;
self-&gt;first = NULL;
Py_XDECREF(tmp);
tmp = self-&gt;last;
self-&gt;last = NULL;
Py_XDECREF(tmp);
return 0;
}
static void
Noddy_dealloc(Noddy* self)
{
Noddy_clear(self);
self-&gt;ob_type-&gt;tp_free((PyObject*)self);
}
static PyObject *
Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
Noddy *self;
self = (Noddy *)type-&gt;tp_alloc(type, 0);
if (self != NULL) {
self-&gt;first = PyString_FromString("");
if (self-&gt;first == NULL)
{
Py_DECREF(self);
return NULL;
}
self-&gt;last = PyString_FromString("");
if (self-&gt;last == NULL)
{
Py_DECREF(self);
return NULL;
}
self-&gt;number = 0;
}
return (PyObject *)self;
}
static int
Noddy_init(Noddy *self, PyObject *args, PyObject *kwds)
{
PyObject *first=NULL, *last=NULL, *tmp;
static char *kwlist[] = {"first", "last", "number", NULL};
if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
&amp;first, &amp;last,
&amp;self-&gt;number))
return -1;
if (first) {
tmp = self-&gt;first;
Py_INCREF(first);
self-&gt;first = first;
Py_XDECREF(tmp);
}
if (last) {
tmp = self-&gt;last;
Py_INCREF(last);
self-&gt;last = last;
Py_XDECREF(tmp);
}
return 0;
}
static PyMemberDef Noddy_members[] = {
{"first", T_OBJECT_EX, offsetof(Noddy, first), 0,
"first name"},
{"last", T_OBJECT_EX, offsetof(Noddy, last), 0,
"last name"},
{"number", T_INT, offsetof(Noddy, number), 0,
"noddy number"},
{NULL} /* Sentinel */
};
static PyObject *
Noddy_name(Noddy* self)
{
static PyObject *format = NULL;
PyObject *args, *result;
if (format == NULL) {
format = PyString_FromString("%s %s");
if (format == NULL)
return NULL;
}
if (self-&gt;first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first");
return NULL;
}
if (self-&gt;last == NULL) {
PyErr_SetString(PyExc_AttributeError, "last");
return NULL;
}
args = Py_BuildValue("OO", self-&gt;first, self-&gt;last);
if (args == NULL)
return NULL;
result = PyString_Format(format, args);
Py_DECREF(args);
return result;
}
static PyMethodDef Noddy_methods[] = {
{"name", (PyCFunction)Noddy_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
static PyTypeObject NoddyType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"noddy.Noddy", /*tp_name*/
sizeof(Noddy), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)Noddy_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_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
"Noddy objects", /* tp_doc */
(traverseproc)Noddy_traverse, /* tp_traverse */
(inquiry)Noddy_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Noddy_methods, /* tp_methods */
Noddy_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Noddy_init, /* tp_init */
0, /* tp_alloc */
Noddy_new, /* tp_new */
};
static PyMethodDef module_methods[] = {
{NULL} /* Sentinel */
};
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
initnoddy4(void)
{
PyObject* m;
if (PyType_Ready(&amp;NoddyType) &lt; 0)
return;
m = Py_InitModule3("noddy4", module_methods,
"Example module that creates an extension type.");
if (m == NULL)
return;
Py_INCREF(&amp;NoddyType);
PyModule_AddObject(m, "Noddy", (PyObject *)&amp;NoddyType);
}
</pre>
<div class="footer">
<a href="noddy4.txt" type="text/plain">Download as text (original file name: <span class="file">noddy4.c</span>).</a>
</div></div>
<P>
The traversal method provides access to subobjects that
could participate in cycles:
<P>
<div class="verbatim"><pre>
static int
Noddy_traverse(Noddy *self, visitproc visit, void *arg)
{
int vret;
if (self-&gt;first) {
vret = visit(self-&gt;first, arg);
if (vret != 0)
return vret;
}
if (self-&gt;last) {
vret = visit(self-&gt;last, arg);
if (vret != 0)
return vret;
}
return 0;
}
</pre></div>
<P>
For each subobject that can participate in cycles, we need to call the
<tt class="cfunction">visit()</tt> function, which is passed to the traversal method.
The <tt class="cfunction">visit()</tt> function takes as arguments the subobject and
the extra argument <var>arg</var> passed to the traversal method. It
returns an integer value that must be returned if it is non-zero.
<P>
Python 2.4 and higher provide a <tt class="cfunction">Py_VISIT()</tt> macro that automates
calling visit functions. With <tt class="cfunction">Py_VISIT()</tt>,
<tt class="cfunction">Noddy_traverse()</tt> can be simplified:
<P>
<div class="verbatim"><pre>
static int
Noddy_traverse(Noddy *self, visitproc visit, void *arg)
{
Py_VISIT(self-&gt;first);
Py_VISIT(self-&gt;last);
return 0;
}
</pre></div>
<P>
<span class="note"><b class="label">Note:</b>
Note that the <tt class="member">tp_traverse</tt> implementation must name its
arguments exactly <var>visit</var> and <var>arg</var> in order to use
<tt class="cfunction">Py_VISIT()</tt>. This is to encourage uniformity
across these boring implementations.</span>
<P>
We also need to provide a method for clearing any subobjects that can
participate in cycles. We implement the method and reimplement the
deallocator to use it:
<P>
<div class="verbatim"><pre>
static int
Noddy_clear(Noddy *self)
{
PyObject *tmp;
tmp = self-&gt;first;
self-&gt;first = NULL;
Py_XDECREF(tmp);
tmp = self-&gt;last;
self-&gt;last = NULL;
Py_XDECREF(tmp);
return 0;
}
static void
Noddy_dealloc(Noddy* self)
{
Noddy_clear(self);
self-&gt;ob_type-&gt;tp_free((PyObject*)self);
}
</pre></div>
<P>
Notice the use of a temporary variable in <tt class="cfunction">Noddy_clear()</tt>.
We use the temporary variable so that we can set each member to <tt class="constant">NULL</tt>
before decrementing its reference count. We do this because, as was
discussed earlier, if the reference count drops to zero, we might
cause code to run that calls back into the object. In addition,
because we now support garbage collection, we also have to worry about
code being run that triggers garbage collection. If garbage
collection is run, our <tt class="member">tp_traverse</tt> handler could get called.
We can't take a chance of having <tt class="cfunction">Noddy_traverse()</tt> called
when a member's reference count has dropped to zero and its value
hasn't been set to <tt class="constant">NULL</tt>.
<P>
Python 2.4 and higher provide a <tt class="cfunction">Py_CLEAR()</tt> that automates
the careful decrementing of reference counts. With
<tt class="cfunction">Py_CLEAR()</tt>, the <tt class="cfunction">Noddy_clear()</tt> function can be
simplified:
<P>
<div class="verbatim"><pre>
static int
Noddy_clear(Noddy *self)
{
Py_CLEAR(self-&gt;first);
Py_CLEAR(self-&gt;last);
return 0;
}
</pre></div>
<P>
Finally, we add the <tt class="constant">Py_TPFLAGS_HAVE_GC</tt> flag to the class
flags:
<P>
<div class="verbatim"><pre>
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
</pre></div>
<P>
That's pretty much it. If we had written custom <tt class="member">tp_alloc</tt> or
<tt class="member">tp_free</tt> slots, we'd need to modify them for cyclic-garbage
collection. Most extensions will use the versions automatically
provided.
<P>
<BR><HR><H4>Footnotes</H4>
<DL>
<DT><A NAME="foot1173">...
attributes</A><A
HREF="node24.html#tex2html8"><SUP>2.4</SUP></A></DT>
<DD>Even in the third version, we aren't guaranteed to
avoid cycles. Instances of string subclasses are allowed and string
subclasses could allow cycles even if normal strings don't.
</DD>
</DL>
<DIV CLASS="navigation">
<div class='online-navigation'>
<p></p><hr />
<table align="center" width="100%" cellpadding="0" cellspacing="2">
<tr>
<td class='online-navigation'><a rel="prev" title="2.1.2 Providing finer control"
href="node23.html"><img src='../icons/previous.png'
border='0' height='32' alt='Previous Page' width='32' /></A></td>
<td class='online-navigation'><a rel="parent" title="2.1 The Basics"
href="dnt-basics.html"><img src='../icons/up.png'
border='0' height='32' alt='Up One Level' width='32' /></A></td>
<td class='online-navigation'><a rel="next" title="2.2 Type Methods"
href="dnt-type-methods.html"><img src='../icons/next.png'
border='0' height='32' alt='Next Page' width='32' /></A></td>
<td align="center" width="100%">Extending and Embedding the Python Interpreter</td>
<td class='online-navigation'><a rel="contents" title="Table of Contents"
href="contents.html"><img src='../icons/contents.png'
border='0' height='32' alt='Contents' width='32' /></A></td>
<td class='online-navigation'><img src='../icons/blank.png'
border='0' height='32' alt='' width='32' /></td>
<td class='online-navigation'><img src='../icons/blank.png'
border='0' height='32' alt='' width='32' /></td>
</tr></table>
<div class='online-navigation'>
<b class="navlabel">Previous:</b>
<a class="sectref" rel="prev" href="node23.html">2.1.2 Providing finer control</A>
<b class="navlabel">Up:</b>
<a class="sectref" rel="parent" href="dnt-basics.html">2.1 The Basics</A>
<b class="navlabel">Next:</b>
<a class="sectref" rel="next" href="dnt-type-methods.html">2.2 Type Methods</A>
</div>
</div>
<hr />
<span class="release-info">Release 2.4.2, documentation updated on 28 September 2005.</span>
</DIV>
<!--End of Navigation Panel-->
<ADDRESS>
See <i><a href="about.html">About this document...</a></i> for information on suggesting changes.
</ADDRESS>
</BODY>
</HTML>