Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / amd64 / html / python / ext / node24.html
CommitLineData
920dae64
AT
1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
2<html>
3<head>
4<link rel="STYLESHEET" href="ext.css" type='text/css' />
5<link rel="SHORTCUT ICON" href="../icons/pyfav.png" type="image/png" />
6<link rel='start' href='../index.html' title='Python Documentation Index' />
7<link rel="first" href="ext.html" title='Extending and Embedding the Python Interpreter' />
8<link rel='contents' href='contents.html' title="Contents" />
9<link rel='last' href='about.html' title='About this document...' />
10<link rel='help' href='about.html' title='About this document...' />
11<link rel="prev" href="node23.html" />
12<link rel="parent" href="dnt-basics.html" />
13<link rel="next" href="dnt-type-methods.html" />
14<meta name='aesop' content='information' />
15<title>2.1.3 Supporting cyclic garbage collection</title>
16</head>
17<body>
18<DIV CLASS="navigation">
19<div id='top-navigation-panel' xml:id='top-navigation-panel'>
20<table align="center" width="100%" cellpadding="0" cellspacing="2">
21<tr>
22<td class='online-navigation'><a rel="prev" title="2.1.2 Providing finer control"
23 href="node23.html"><img src='../icons/previous.png'
24 border='0' height='32' alt='Previous Page' width='32' /></A></td>
25<td class='online-navigation'><a rel="parent" title="2.1 The Basics"
26 href="dnt-basics.html"><img src='../icons/up.png'
27 border='0' height='32' alt='Up One Level' width='32' /></A></td>
28<td class='online-navigation'><a rel="next" title="2.2 Type Methods"
29 href="dnt-type-methods.html"><img src='../icons/next.png'
30 border='0' height='32' alt='Next Page' width='32' /></A></td>
31<td align="center" width="100%">Extending and Embedding the Python Interpreter</td>
32<td class='online-navigation'><a rel="contents" title="Table of Contents"
33 href="contents.html"><img src='../icons/contents.png'
34 border='0' height='32' alt='Contents' width='32' /></A></td>
35<td class='online-navigation'><img src='../icons/blank.png'
36 border='0' height='32' alt='' width='32' /></td>
37<td class='online-navigation'><img src='../icons/blank.png'
38 border='0' height='32' alt='' width='32' /></td>
39</tr></table>
40<div class='online-navigation'>
41<b class="navlabel">Previous:</b>
42<a class="sectref" rel="prev" href="node23.html">2.1.2 Providing finer control</A>
43<b class="navlabel">Up:</b>
44<a class="sectref" rel="parent" href="dnt-basics.html">2.1 The Basics</A>
45<b class="navlabel">Next:</b>
46<a class="sectref" rel="next" href="dnt-type-methods.html">2.2 Type Methods</A>
47</div>
48<hr /></div>
49</DIV>
50<!--End of Navigation Panel-->
51
52<H2><A NAME="SECTION004130000000000000000">
532.1.3 Supporting cyclic garbage collection</A>
54</H2>
55
56<P>
57Python has a cyclic-garbage collector that can identify unneeded
58objects even when their reference counts are not zero. This can happen
59when objects are involved in cycles. For example, consider:
60
61<P>
62<div class="verbatim"><pre>
63&gt;&gt;&gt; l = []
64&gt;&gt;&gt; l.append(l)
65&gt;&gt;&gt; del l
66</pre></div>
67
68<P>
69In this example, we create a list that contains itself. When we delete
70it, it still has a reference from itself. Its reference count doesn't
71drop to zero. Fortunately, Python's cyclic-garbage collector will
72eventually figure out that the list is garbage and free it.
73
74<P>
75In the second version of the <tt class="class">Noddy</tt> example, we allowed any
76kind of object to be stored in the <tt class="member">first</tt> or <tt class="member">last</tt>
77attributes<A NAME="tex2html8"
78 HREF="#foot1173"><SUP>2.4</SUP></A>. This
79means that <tt class="class">Noddy</tt> objects can participate in cycles:
80
81<P>
82<div class="verbatim"><pre>
83&gt;&gt;&gt; import noddy2
84&gt;&gt;&gt; n = noddy2.Noddy()
85&gt;&gt;&gt; l = [n]
86&gt;&gt;&gt; n.first = l
87</pre></div>
88
89<P>
90This is pretty silly, but it gives us an excuse to add support for the
91cyclic-garbage collector to the <tt class="class">Noddy</tt> example. To support
92cyclic garbage collection, types need to fill two slots and set a
93class flag that enables these slots:
94
95<P>
96<div class="verbatim">
97<pre>#include &lt;Python.h&gt;
98#include "structmember.h"
99
100typedef struct {
101 PyObject_HEAD
102 PyObject *first;
103 PyObject *last;
104 int number;
105} Noddy;
106
107static int
108Noddy_traverse(Noddy *self, visitproc visit, void *arg)
109{
110 int vret;
111
112 if (self-&gt;first) {
113 vret = visit(self-&gt;first, arg);
114 if (vret != 0)
115 return vret;
116 }
117 if (self-&gt;last) {
118 vret = visit(self-&gt;last, arg);
119 if (vret != 0)
120 return vret;
121 }
122
123 return 0;
124}
125
126static int
127Noddy_clear(Noddy *self)
128{
129 PyObject *tmp;
130
131 tmp = self-&gt;first;
132 self-&gt;first = NULL;
133 Py_XDECREF(tmp);
134
135 tmp = self-&gt;last;
136 self-&gt;last = NULL;
137 Py_XDECREF(tmp);
138
139 return 0;
140}
141
142static void
143Noddy_dealloc(Noddy* self)
144{
145 Noddy_clear(self);
146 self-&gt;ob_type-&gt;tp_free((PyObject*)self);
147}
148
149static PyObject *
150Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
151{
152 Noddy *self;
153
154 self = (Noddy *)type-&gt;tp_alloc(type, 0);
155 if (self != NULL) {
156 self-&gt;first = PyString_FromString("");
157 if (self-&gt;first == NULL)
158 {
159 Py_DECREF(self);
160 return NULL;
161 }
162
163 self-&gt;last = PyString_FromString("");
164 if (self-&gt;last == NULL)
165 {
166 Py_DECREF(self);
167 return NULL;
168 }
169
170 self-&gt;number = 0;
171 }
172
173 return (PyObject *)self;
174}
175
176static int
177Noddy_init(Noddy *self, PyObject *args, PyObject *kwds)
178{
179 PyObject *first=NULL, *last=NULL, *tmp;
180
181 static char *kwlist[] = {"first", "last", "number", NULL};
182
183 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
184 &amp;first, &amp;last,
185 &amp;self-&gt;number))
186 return -1;
187
188 if (first) {
189 tmp = self-&gt;first;
190 Py_INCREF(first);
191 self-&gt;first = first;
192 Py_XDECREF(tmp);
193 }
194
195 if (last) {
196 tmp = self-&gt;last;
197 Py_INCREF(last);
198 self-&gt;last = last;
199 Py_XDECREF(tmp);
200 }
201
202 return 0;
203}
204
205static PyMemberDef Noddy_members[] = {
206 {"first", T_OBJECT_EX, offsetof(Noddy, first), 0,
207 "first name"},
208 {"last", T_OBJECT_EX, offsetof(Noddy, last), 0,
209 "last name"},
210 {"number", T_INT, offsetof(Noddy, number), 0,
211 "noddy number"},
212 {NULL} /* Sentinel */
213};
214
215static PyObject *
216Noddy_name(Noddy* self)
217{
218 static PyObject *format = NULL;
219 PyObject *args, *result;
220
221 if (format == NULL) {
222 format = PyString_FromString("%s %s");
223 if (format == NULL)
224 return NULL;
225 }
226
227 if (self-&gt;first == NULL) {
228 PyErr_SetString(PyExc_AttributeError, "first");
229 return NULL;
230 }
231
232 if (self-&gt;last == NULL) {
233 PyErr_SetString(PyExc_AttributeError, "last");
234 return NULL;
235 }
236
237 args = Py_BuildValue("OO", self-&gt;first, self-&gt;last);
238 if (args == NULL)
239 return NULL;
240
241 result = PyString_Format(format, args);
242 Py_DECREF(args);
243
244 return result;
245}
246
247static PyMethodDef Noddy_methods[] = {
248 {"name", (PyCFunction)Noddy_name, METH_NOARGS,
249 "Return the name, combining the first and last name"
250 },
251 {NULL} /* Sentinel */
252};
253
254static PyTypeObject NoddyType = {
255 PyObject_HEAD_INIT(NULL)
256 0, /*ob_size*/
257 "noddy.Noddy", /*tp_name*/
258 sizeof(Noddy), /*tp_basicsize*/
259 0, /*tp_itemsize*/
260 (destructor)Noddy_dealloc, /*tp_dealloc*/
261 0, /*tp_print*/
262 0, /*tp_getattr*/
263 0, /*tp_setattr*/
264 0, /*tp_compare*/
265 0, /*tp_repr*/
266 0, /*tp_as_number*/
267 0, /*tp_as_sequence*/
268 0, /*tp_as_mapping*/
269 0, /*tp_hash */
270 0, /*tp_call*/
271 0, /*tp_str*/
272 0, /*tp_getattro*/
273 0, /*tp_setattro*/
274 0, /*tp_as_buffer*/
275 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
276 "Noddy objects", /* tp_doc */
277 (traverseproc)Noddy_traverse, /* tp_traverse */
278 (inquiry)Noddy_clear, /* tp_clear */
279 0, /* tp_richcompare */
280 0, /* tp_weaklistoffset */
281 0, /* tp_iter */
282 0, /* tp_iternext */
283 Noddy_methods, /* tp_methods */
284 Noddy_members, /* tp_members */
285 0, /* tp_getset */
286 0, /* tp_base */
287 0, /* tp_dict */
288 0, /* tp_descr_get */
289 0, /* tp_descr_set */
290 0, /* tp_dictoffset */
291 (initproc)Noddy_init, /* tp_init */
292 0, /* tp_alloc */
293 Noddy_new, /* tp_new */
294};
295
296static PyMethodDef module_methods[] = {
297 {NULL} /* Sentinel */
298};
299
300#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
301#define PyMODINIT_FUNC void
302#endif
303PyMODINIT_FUNC
304initnoddy4(void)
305{
306 PyObject* m;
307
308 if (PyType_Ready(&amp;NoddyType) &lt; 0)
309 return;
310
311 m = Py_InitModule3("noddy4", module_methods,
312 "Example module that creates an extension type.");
313
314 if (m == NULL)
315 return;
316
317 Py_INCREF(&amp;NoddyType);
318 PyModule_AddObject(m, "Noddy", (PyObject *)&amp;NoddyType);
319}
320</pre>
321<div class="footer">
322<a href="noddy4.txt" type="text/plain">Download as text (original file name: <span class="file">noddy4.c</span>).</a>
323</div></div>
324
325<P>
326The traversal method provides access to subobjects that
327could participate in cycles:
328
329<P>
330<div class="verbatim"><pre>
331static int
332Noddy_traverse(Noddy *self, visitproc visit, void *arg)
333{
334 int vret;
335
336 if (self-&gt;first) {
337 vret = visit(self-&gt;first, arg);
338 if (vret != 0)
339 return vret;
340 }
341 if (self-&gt;last) {
342 vret = visit(self-&gt;last, arg);
343 if (vret != 0)
344 return vret;
345 }
346
347 return 0;
348}
349</pre></div>
350
351<P>
352For each subobject that can participate in cycles, we need to call the
353<tt class="cfunction">visit()</tt> function, which is passed to the traversal method.
354The <tt class="cfunction">visit()</tt> function takes as arguments the subobject and
355the extra argument <var>arg</var> passed to the traversal method. It
356returns an integer value that must be returned if it is non-zero.
357
358<P>
359Python 2.4 and higher provide a <tt class="cfunction">Py_VISIT()</tt> macro that automates
360calling visit functions. With <tt class="cfunction">Py_VISIT()</tt>,
361<tt class="cfunction">Noddy_traverse()</tt> can be simplified:
362
363<P>
364<div class="verbatim"><pre>
365static int
366Noddy_traverse(Noddy *self, visitproc visit, void *arg)
367{
368 Py_VISIT(self-&gt;first);
369 Py_VISIT(self-&gt;last);
370 return 0;
371}
372</pre></div>
373
374<P>
375<span class="note"><b class="label">Note:</b>
376Note that the <tt class="member">tp_traverse</tt> implementation must name its
377 arguments exactly <var>visit</var> and <var>arg</var> in order to use
378 <tt class="cfunction">Py_VISIT()</tt>. This is to encourage uniformity
379 across these boring implementations.</span>
380
381<P>
382We also need to provide a method for clearing any subobjects that can
383participate in cycles. We implement the method and reimplement the
384deallocator to use it:
385
386<P>
387<div class="verbatim"><pre>
388static int
389Noddy_clear(Noddy *self)
390{
391 PyObject *tmp;
392
393 tmp = self-&gt;first;
394 self-&gt;first = NULL;
395 Py_XDECREF(tmp);
396
397 tmp = self-&gt;last;
398 self-&gt;last = NULL;
399 Py_XDECREF(tmp);
400
401 return 0;
402}
403
404static void
405Noddy_dealloc(Noddy* self)
406{
407 Noddy_clear(self);
408 self-&gt;ob_type-&gt;tp_free((PyObject*)self);
409}
410</pre></div>
411
412<P>
413Notice the use of a temporary variable in <tt class="cfunction">Noddy_clear()</tt>.
414We use the temporary variable so that we can set each member to <tt class="constant">NULL</tt>
415before decrementing its reference count. We do this because, as was
416discussed earlier, if the reference count drops to zero, we might
417cause code to run that calls back into the object. In addition,
418because we now support garbage collection, we also have to worry about
419code being run that triggers garbage collection. If garbage
420collection is run, our <tt class="member">tp_traverse</tt> handler could get called.
421We can't take a chance of having <tt class="cfunction">Noddy_traverse()</tt> called
422when a member's reference count has dropped to zero and its value
423hasn't been set to <tt class="constant">NULL</tt>.
424
425<P>
426Python 2.4 and higher provide a <tt class="cfunction">Py_CLEAR()</tt> that automates
427the careful decrementing of reference counts. With
428<tt class="cfunction">Py_CLEAR()</tt>, the <tt class="cfunction">Noddy_clear()</tt> function can be
429simplified:
430
431<P>
432<div class="verbatim"><pre>
433static int
434Noddy_clear(Noddy *self)
435{
436 Py_CLEAR(self-&gt;first);
437 Py_CLEAR(self-&gt;last);
438 return 0;
439}
440</pre></div>
441
442<P>
443Finally, we add the <tt class="constant">Py_TPFLAGS_HAVE_GC</tt> flag to the class
444flags:
445
446<P>
447<div class="verbatim"><pre>
448 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
449</pre></div>
450
451<P>
452That's pretty much it. If we had written custom <tt class="member">tp_alloc</tt> or
453<tt class="member">tp_free</tt> slots, we'd need to modify them for cyclic-garbage
454collection. Most extensions will use the versions automatically
455provided.
456
457<P>
458<BR><HR><H4>Footnotes</H4>
459<DL>
460<DT><A NAME="foot1173">...
461attributes</A><A
462 HREF="node24.html#tex2html8"><SUP>2.4</SUP></A></DT>
463<DD>Even in the third version, we aren't guaranteed to
464avoid cycles. Instances of string subclasses are allowed and string
465subclasses could allow cycles even if normal strings don't.
466
467</DD>
468</DL>
469<DIV CLASS="navigation">
470<div class='online-navigation'>
471<p></p><hr />
472<table align="center" width="100%" cellpadding="0" cellspacing="2">
473<tr>
474<td class='online-navigation'><a rel="prev" title="2.1.2 Providing finer control"
475 href="node23.html"><img src='../icons/previous.png'
476 border='0' height='32' alt='Previous Page' width='32' /></A></td>
477<td class='online-navigation'><a rel="parent" title="2.1 The Basics"
478 href="dnt-basics.html"><img src='../icons/up.png'
479 border='0' height='32' alt='Up One Level' width='32' /></A></td>
480<td class='online-navigation'><a rel="next" title="2.2 Type Methods"
481 href="dnt-type-methods.html"><img src='../icons/next.png'
482 border='0' height='32' alt='Next Page' width='32' /></A></td>
483<td align="center" width="100%">Extending and Embedding the Python Interpreter</td>
484<td class='online-navigation'><a rel="contents" title="Table of Contents"
485 href="contents.html"><img src='../icons/contents.png'
486 border='0' height='32' alt='Contents' width='32' /></A></td>
487<td class='online-navigation'><img src='../icons/blank.png'
488 border='0' height='32' alt='' width='32' /></td>
489<td class='online-navigation'><img src='../icons/blank.png'
490 border='0' height='32' alt='' width='32' /></td>
491</tr></table>
492<div class='online-navigation'>
493<b class="navlabel">Previous:</b>
494<a class="sectref" rel="prev" href="node23.html">2.1.2 Providing finer control</A>
495<b class="navlabel">Up:</b>
496<a class="sectref" rel="parent" href="dnt-basics.html">2.1 The Basics</A>
497<b class="navlabel">Next:</b>
498<a class="sectref" rel="next" href="dnt-type-methods.html">2.2 Type Methods</A>
499</div>
500</div>
501<hr />
502<span class="release-info">Release 2.4.2, documentation updated on 28 September 2005.</span>
503</DIV>
504<!--End of Navigation Panel-->
505<ADDRESS>
506See <i><a href="about.html">About this document...</a></i> for information on suggesting changes.
507</ADDRESS>
508</BODY>
509</HTML>