mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 11:49:12 +00:00 
			
		
		
		
	Make itertools.tee and its internal teedataobject participate in GC. This
alone does not solve the leak in test_generators, unfortunately, but it is part of test_generators' problem and it does solve other cycles.
This commit is contained in:
		
							parent
							
								
									5d0f4c6193
								
							
						
					
					
						commit
						19bf33bc7a
					
				
					 1 changed files with 72 additions and 20 deletions
				
			
		| 
						 | 
					@ -340,7 +340,7 @@ teedataobject_new(PyObject *it)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	teedataobject *tdo;
 | 
						teedataobject *tdo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tdo = PyObject_New(teedataobject, &teedataobject_type);
 | 
						tdo = PyObject_GC_New(teedataobject, &teedataobject_type);
 | 
				
			||||||
	if (tdo == NULL)
 | 
						if (tdo == NULL)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -348,6 +348,7 @@ teedataobject_new(PyObject *it)
 | 
				
			||||||
	tdo->nextlink = NULL;
 | 
						tdo->nextlink = NULL;
 | 
				
			||||||
	Py_INCREF(it);
 | 
						Py_INCREF(it);
 | 
				
			||||||
	tdo->it = it;
 | 
						tdo->it = it;
 | 
				
			||||||
 | 
						PyObject_GC_Track(tdo);
 | 
				
			||||||
	return (PyObject *)tdo;
 | 
						return (PyObject *)tdo;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -381,16 +382,34 @@ teedataobject_getitem(teedataobject *tdo, int i)
 | 
				
			||||||
	return value;
 | 
						return value;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					teedataobject_traverse(teedataobject *tdo, visitproc visit, void * arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						Py_VISIT(tdo->it);
 | 
				
			||||||
 | 
						for (i = 0; i < tdo->numread; i++)
 | 
				
			||||||
 | 
							Py_VISIT(tdo->values[i]);
 | 
				
			||||||
 | 
						Py_VISIT(tdo->nextlink);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					teedataobject_clear(teedataobject *tdo)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						Py_CLEAR(tdo->it);
 | 
				
			||||||
 | 
						for (i=0 ; i<tdo->numread ; i++)
 | 
				
			||||||
 | 
							Py_CLEAR(tdo->values[i]);
 | 
				
			||||||
 | 
						Py_CLEAR(tdo->nextlink);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
teedataobject_dealloc(teedataobject *tdo)
 | 
					teedataobject_dealloc(teedataobject *tdo)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						PyObject_GC_UnTrack(tdo);
 | 
				
			||||||
 | 
						teedataobject_clear(tdo);
 | 
				
			||||||
	for (i=0 ; i<tdo->numread ; i++)
 | 
						PyObject_GC_Del(tdo);
 | 
				
			||||||
		Py_DECREF(tdo->values[i]);
 | 
					 | 
				
			||||||
	Py_XDECREF(tdo->it);
 | 
					 | 
				
			||||||
	Py_XDECREF(tdo->nextlink);
 | 
					 | 
				
			||||||
	PyObject_Del(tdo);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PyDoc_STRVAR(teedataobject_doc, "Data container common to multiple tee objects.");
 | 
					PyDoc_STRVAR(teedataobject_doc, "Data container common to multiple tee objects.");
 | 
				
			||||||
| 
						 | 
					@ -417,9 +436,26 @@ static PyTypeObject teedataobject_type = {
 | 
				
			||||||
	PyObject_GenericGetAttr,		/* tp_getattro */
 | 
						PyObject_GenericGetAttr,		/* tp_getattro */
 | 
				
			||||||
	0,					/* tp_setattro */
 | 
						0,					/* tp_setattro */
 | 
				
			||||||
	0,					/* tp_as_buffer */
 | 
						0,					/* tp_as_buffer */
 | 
				
			||||||
	Py_TPFLAGS_DEFAULT,			/* tp_flags */
 | 
						Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,	/* tp_flags */
 | 
				
			||||||
	teedataobject_doc,			/* tp_doc */
 | 
						teedataobject_doc,			/* tp_doc */
 | 
				
			||||||
	0,					/* tp_traverse */
 | 
						(traverseproc)teedataobject_traverse,	/* tp_traverse */
 | 
				
			||||||
 | 
						(inquiry)teedataobject_clear,		/* tp_clear */
 | 
				
			||||||
 | 
						0,					/* tp_richcompare */
 | 
				
			||||||
 | 
						0,					/* tp_weaklistoffset */
 | 
				
			||||||
 | 
						0,					/* tp_iter */
 | 
				
			||||||
 | 
						0,					/* tp_iternext */
 | 
				
			||||||
 | 
						0,					/* tp_methods */
 | 
				
			||||||
 | 
						0,					/* tp_members */
 | 
				
			||||||
 | 
						0,					/* tp_getset */
 | 
				
			||||||
 | 
						0,					/* tp_base */
 | 
				
			||||||
 | 
						0,					/* tp_dict */
 | 
				
			||||||
 | 
						0,					/* tp_descr_get */
 | 
				
			||||||
 | 
						0,					/* tp_descr_set */
 | 
				
			||||||
 | 
						0,					/* tp_dictoffset */
 | 
				
			||||||
 | 
						0,					/* tp_init */
 | 
				
			||||||
 | 
						0,					/* tp_alloc */
 | 
				
			||||||
 | 
						0,					/* tp_new */
 | 
				
			||||||
 | 
						PyObject_GC_Del,			/* tp_free */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -443,12 +479,19 @@ tee_next(teeobject *to)
 | 
				
			||||||
	return value;
 | 
						return value;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					tee_traverse(teeobject *to, visitproc visit, void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Py_VISIT((PyObject *)to->dataobj);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyObject *
 | 
					static PyObject *
 | 
				
			||||||
tee_copy(teeobject *to)
 | 
					tee_copy(teeobject *to)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	teeobject *newto;
 | 
						teeobject *newto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	newto = PyObject_New(teeobject, &tee_type);
 | 
						newto = PyObject_GC_New(teeobject, &tee_type);
 | 
				
			||||||
	if (newto == NULL)
 | 
						if (newto == NULL)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	Py_INCREF(to->dataobj);
 | 
						Py_INCREF(to->dataobj);
 | 
				
			||||||
| 
						 | 
					@ -474,12 +517,13 @@ tee_fromiterable(PyObject *iterable)
 | 
				
			||||||
		goto done;
 | 
							goto done;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	to = PyObject_New(teeobject, &tee_type);
 | 
						to = PyObject_GC_New(teeobject, &tee_type);
 | 
				
			||||||
	if (to == NULL) 
 | 
						if (to == NULL) 
 | 
				
			||||||
		goto done;
 | 
							goto done;
 | 
				
			||||||
	to->dataobj = (teedataobject *)teedataobject_new(it);
 | 
						to->dataobj = (teedataobject *)teedataobject_new(it);
 | 
				
			||||||
	to->index = 0;
 | 
						to->index = 0;
 | 
				
			||||||
	to->weakreflist = NULL;
 | 
						to->weakreflist = NULL;
 | 
				
			||||||
 | 
						PyObject_GC_Track(to);
 | 
				
			||||||
done:
 | 
					done:
 | 
				
			||||||
	Py_XDECREF(it);
 | 
						Py_XDECREF(it);
 | 
				
			||||||
	return (PyObject *)to;
 | 
						return (PyObject *)to;
 | 
				
			||||||
| 
						 | 
					@ -495,13 +539,21 @@ tee_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 | 
				
			||||||
	return tee_fromiterable(iterable);
 | 
						return tee_fromiterable(iterable);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static int
 | 
				
			||||||
tee_dealloc(teeobject *to)
 | 
					tee_clear(teeobject *to)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (to->weakreflist != NULL)
 | 
						if (to->weakreflist != NULL)
 | 
				
			||||||
		PyObject_ClearWeakRefs((PyObject *) to);
 | 
							PyObject_ClearWeakRefs((PyObject *) to);
 | 
				
			||||||
	Py_XDECREF(to->dataobj);
 | 
						Py_CLEAR(to->dataobj);
 | 
				
			||||||
	PyObject_Del(to);
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					tee_dealloc(teeobject *to)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						PyObject_GC_UnTrack(to);
 | 
				
			||||||
 | 
						tee_clear(to);
 | 
				
			||||||
 | 
						PyObject_GC_Del(to);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PyDoc_STRVAR(teeobject_doc,
 | 
					PyDoc_STRVAR(teeobject_doc,
 | 
				
			||||||
| 
						 | 
					@ -534,10 +586,10 @@ static PyTypeObject tee_type = {
 | 
				
			||||||
	0,				/* tp_getattro */
 | 
						0,				/* tp_getattro */
 | 
				
			||||||
	0,				/* tp_setattro */
 | 
						0,				/* tp_setattro */
 | 
				
			||||||
	0,				/* tp_as_buffer */
 | 
						0,				/* tp_as_buffer */
 | 
				
			||||||
	Py_TPFLAGS_DEFAULT,		/* tp_flags */
 | 
						Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,	/* tp_flags */
 | 
				
			||||||
	teeobject_doc,			/* tp_doc */
 | 
						teeobject_doc,			/* tp_doc */
 | 
				
			||||||
	0,				/* tp_traverse */
 | 
						(traverseproc)tee_traverse,	/* tp_traverse */
 | 
				
			||||||
	0,				/* tp_clear */
 | 
						(inquiry)tee_clear,		/* tp_clear */
 | 
				
			||||||
	0,				/* tp_richcompare */
 | 
						0,				/* tp_richcompare */
 | 
				
			||||||
	offsetof(teeobject, weakreflist),	/* tp_weaklistoffset */
 | 
						offsetof(teeobject, weakreflist),	/* tp_weaklistoffset */
 | 
				
			||||||
	PyObject_SelfIter,		/* tp_iter */
 | 
						PyObject_SelfIter,		/* tp_iter */
 | 
				
			||||||
| 
						 | 
					@ -553,7 +605,7 @@ static PyTypeObject tee_type = {
 | 
				
			||||||
	0,				/* tp_init */
 | 
						0,				/* tp_init */
 | 
				
			||||||
	0,				/* tp_alloc */
 | 
						0,				/* tp_alloc */
 | 
				
			||||||
	tee_new,			/* tp_new */
 | 
						tee_new,			/* tp_new */
 | 
				
			||||||
	PyObject_Del,			/* tp_free */
 | 
						PyObject_GC_Del,		/* tp_free */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyObject *
 | 
					static PyObject *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue