cinap_lenrekadd hg and python4bb9e2215 years agoHistory
1390 lines · 40.0 KB · C
RawDownload
	int num_freed = 0; 	gc_list_init(&wrcb_to_call); 	/* Clear all weakrefs to the objects in unreachable.  If such a weakref	 * also has a callback, move it into `wrcb_to_call` if the callback	 * needs to be invoked.  Note that we cannot invoke any callbacks until	 * all weakrefs to unreachable objects are cleared, lest the callback	 * resurrect an unreachable object via a still-active weakref.  We	 * make another pass over wrcb_to_call, invoking callbacks, after this	 * pass completes.	 */	for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) {		PyWeakReference **wrlist; 		op = FROM_GC(gc);		assert(IS_TENTATIVELY_UNREACHABLE(op));		next = gc->gc.gc_next; 		if (! PyType_SUPPORTS_WEAKREFS(op->ob_type))			continue; 		/* It supports weakrefs.  Does it have any? */		wrlist = (PyWeakReference **)			     		PyObject_GET_WEAKREFS_LISTPTR(op); 		/* `op` may have some weakrefs.  March over the list, clear		 * all the weakrefs, and move the weakrefs with callbacks		 * that must be called into wrcb_to_call.		 */		for (wr = *wrlist; wr != NULL; wr = *wrlist) {			PyGC_Head *wrasgc;	/* AS_GC(wr) */ 			/* _PyWeakref_ClearRef clears the weakref but leaves			 * the callback pointer intact.  Obscure:  it also			 * changes *wrlist.			 */			assert(wr->wr_object == op);			_PyWeakref_ClearRef(wr);			assert(wr->wr_object == Py_None);			if (wr->wr_callback == NULL)				continue;	/* no callback */ 	/* Headache time.  `op` is going away, and is weakly referenced by	 * `wr`, which has a callback.  Should the callback be invoked?  If wr	 * is also trash, no:	 *	 * 1. There's no need to call it.  The object and the weakref are	 *    both going away, so it's legitimate to pretend the weakref is	 *    going away first.  The user has to ensure a weakref outlives its	 *    referent if they want a guarantee that the wr callback will get	 *    invoked.	 *	 * 2. It may be catastrophic to call it.  If the callback is also in	 *    cyclic trash (CT), then although the CT is unreachable from	 *    outside the current generation, CT may be reachable from the	 *    callback.  Then the callback could resurrect insane objects.	 *	 * Since the callback is never needed and may be unsafe in this case,	 * wr is simply left in the unreachable set.  Note that because we	 * already called _PyWeakref_ClearRef(wr), its callback will never	 * trigger.	 *	 * OTOH, if wr isn't part of CT, we should invoke the callback:  the	 * weakref outlived the trash.  Note that since wr isn't CT in this	 * case, its callback can't be CT either -- wr acted as an external	 * root to this generation, and therefore its callback did too.  So	 * nothing in CT is reachable from the callback either, so it's hard	 * to imagine how calling it later could create a problem for us.  wr	 * is moved to wrcb_to_call in this case.	 */	 		if (IS_TENTATIVELY_UNREACHABLE(wr))	 			continue;			assert(IS_REACHABLE(wr)); 			/* Create a new reference so that wr can't go away			 * before we can process it again.			 */			Py_INCREF(wr); 			/* Move wr to wrcb_to_call, for the next pass. */			wrasgc = AS_GC(wr);			assert(wrasgc != next); /* wrasgc is reachable, but			                           next isn't, so they can't			                           be the same */			gc_list_move(wrasgc, &wrcb_to_call);		}	} 	/* Invoke the callbacks we decided to honor.  It's safe to invoke them	 * because they can't reference unreachable objects.	 */	while (! gc_list_is_empty(&wrcb_to_call)) {		PyObject *temp;		PyObject *callback; 		gc = wrcb_to_call.gc.gc_next;		op = FROM_GC(gc);		assert(IS_REACHABLE(op));		assert(PyWeakref_Check(op));		wr = (PyWeakReference *)op;		callback = wr->wr_callback;		assert(callback != NULL); 		/* copy-paste of weakrefobject.c's handle_callback() */		temp = PyObject_CallFunctionObjArgs(callback, wr, NULL);		if (temp == NULL)			PyErr_WriteUnraisable(callback);		else			Py_DECREF(temp); 		/* Give up the reference we created in the first pass.  When		 * op's refcount hits 0 (which it may or may not do right now),		 * op's tp_dealloc will decref op->wr_callback too.  Note		 * that the refcount probably will hit 0 now, and because this		 * weakref was reachable to begin with, gc didn't already		 * add it to its count of freed objects.  Example:  a reachable		 * weak value dict maps some key to this reachable weakref.		 * The callback removes this key->weakref mapping from the		 * dict, leaving no other references to the weakref (excepting		 * ours).		 */		Py_DECREF(op);		if (wrcb_to_call.gc.gc_next == gc) {			/* object is still alive -- move it */			gc_list_move(gc, old);		}		else			++num_freed;	} 	return num_freed;} static voiddebug_instance(char *msg, PyInstanceObject *inst){	char *cname;	/* simple version of instance_repr */	PyObject *classname = inst->in_class->cl_name;	if (classname != NULL && PyString_Check(classname))		cname = PyString_AsString(classname);	else		cname = "?";	PySys_WriteStderr("gc: %.100s <%.100s instance at %p>\n",			  msg, cname, inst);} static voiddebug_cycle(char *msg, PyObject *op){	if ((debug & DEBUG_INSTANCES) && PyInstance_Check(op)) {		debug_instance(msg, (PyInstanceObject *)op);	}	else if (debug & DEBUG_OBJECTS) {		PySys_WriteStderr("gc: %.100s <%.100s %p>\n",				  msg, op->ob_type->tp_name, op);	}} /* Handle uncollectable garbage (cycles with finalizers, and stuff reachable * only from such cycles). * If DEBUG_SAVEALL, all objects in finalizers are appended to the module * garbage list (a Python list), else only the objects in finalizers with * __del__ methods are appended to garbage.  All objects in finalizers are * merged into the old list regardless. * Returns 0 if all OK, <0 on error (out of memory to grow the garbage list). * The finalizers list is made empty on a successful return. */static inthandle_finalizers(PyGC_Head *finalizers, PyGC_Head *old){	PyGC_Head *gc = finalizers->gc.gc_next; 	if (garbage == NULL) {		garbage = PyList_New(0);		if (garbage == NULL)			Py_FatalError("gc couldn't create gc.garbage list");	}	for (; gc != finalizers; gc = gc->gc.gc_next) {		PyObject *op = FROM_GC(gc); 		if ((debug & DEBUG_SAVEALL) || has_finalizer(op)) {			if (PyList_Append(garbage, op) < 0)				return -1;		}	} 	gc_list_merge(finalizers, old);	return 0;} /* Break reference cycles by clearing the containers involved.	This is * tricky business as the lists can be changing and we don't know which * objects may be freed.  It is possible I screwed something up here. */static voiddelete_garbage(PyGC_Head *collectable, PyGC_Head *old){	inquiry clear; 	while (!gc_list_is_empty(collectable)) {		PyGC_Head *gc = collectable->gc.gc_next;		PyObject *op = FROM_GC(gc); 		assert(IS_TENTATIVELY_UNREACHABLE(op));		if (debug & DEBUG_SAVEALL) {			PyList_Append(garbage, op);		}		else {			if ((clear = op->ob_type->tp_clear) != NULL) {				Py_INCREF(op);				clear(op);				Py_DECREF(op);			}		}		if (collectable->gc.gc_next == gc) {			/* object is still alive, move it, it may die later */			gc_list_move(gc, old);			gc->gc.gc_refs = GC_REACHABLE;		}	}} /* This is the main function.  Read this to understand how the * collection process works. */static Py_ssize_tcollect(int generation){	int i;	Py_ssize_t m = 0; /* # objects collected */	Py_ssize_t n = 0; /* # unreachable objects that couldn't be collected */	PyGC_Head *young; /* the generation we are examining */	PyGC_Head *old; /* next older generation */	PyGC_Head unreachable; /* non-problematic unreachable trash */	PyGC_Head finalizers;  /* objects with, & reachable from, __del__ */	PyGC_Head *gc;	double t1 = 0.0; 	if (delstr == NULL) {		delstr = PyString_InternFromString("__del__");		if (delstr == NULL)			Py_FatalError("gc couldn't allocate \"__del__\"");	} 	if (debug & DEBUG_STATS) {		if (tmod != NULL) {			PyObject *f = PyObject_CallMethod(tmod, "time", NULL);			if (f == NULL) {				PyErr_Clear();			}			else {				t1 = PyFloat_AsDouble(f);				Py_DECREF(f);			}		}		PySys_WriteStderr("gc: collecting generation %d...\n",				  generation);		PySys_WriteStderr("gc: objects in each generation:");		for (i = 0; i < NUM_GENERATIONS; i++)			PySys_WriteStderr(" %" PY_FORMAT_SIZE_T "d",					  gc_list_size(GEN_HEAD(i)));		PySys_WriteStderr("\n");	} 	/* update collection and allocation counters */	if (generation+1 < NUM_GENERATIONS)		generations[generation+1].count += 1;	for (i = 0; i <= generation; i++)		generations[i].count = 0; 	/* merge younger generations with one we are currently collecting */	for (i = 0; i < generation; i++) {		gc_list_merge(GEN_HEAD(i), GEN_HEAD(generation));	} 	/* handy references */	young = GEN_HEAD(generation);	if (generation < NUM_GENERATIONS-1)		old = GEN_HEAD(generation+1);	else		old = young; 	/* Using ob_refcnt and gc_refs, calculate which objects in the	 * container set are reachable from outside the set (i.e., have a	 * refcount greater than 0 when all the references within the	 * set are taken into account).	 */	update_refs(young);	subtract_refs(young); 	/* Leave everything reachable from outside young in young, and move	 * everything else (in young) to unreachable.	 * NOTE:  This used to move the reachable objects into a reachable	 * set instead.  But most things usually turn out to be reachable,	 * so it's more efficient to move the unreachable things.	 */	gc_list_init(&unreachable);	move_unreachable(young, &unreachable); 	/* Move reachable objects to next generation. */	if (young != old)		gc_list_merge(young, old); 	/* All objects in unreachable are trash, but objects reachable from	 * finalizers can't safely be deleted.  Python programmers should take	 * care not to create such things.  For Python, finalizers means	 * instance objects with __del__ methods.  Weakrefs with callbacks	 * can also call arbitrary Python code but they will be dealt with by	 * handle_weakrefs(). 	 */	gc_list_init(&finalizers);	move_finalizers(&unreachable, &finalizers);	/* finalizers contains the unreachable objects with a finalizer;	 * unreachable objects reachable *from* those are also uncollectable,	 * and we move those into the finalizers list too.	 */	move_finalizer_reachable(&finalizers); 	/* Collect statistics on collectable objects found and print	 * debugging information.	 */	for (gc = unreachable.gc.gc_next; gc != &unreachable;			gc = gc->gc.gc_next) {		m++;		if (debug & DEBUG_COLLECTABLE) {			debug_cycle("collectable", FROM_GC(gc));		}		if (tmod != NULL && (debug & DEBUG_STATS)) {			PyObject *f = PyObject_CallMethod(tmod, "time", NULL);			if (f == NULL) {				PyErr_Clear();			}			else {				t1 = PyFloat_AsDouble(f)-t1;				Py_DECREF(f);				PySys_WriteStderr("gc: %.4fs elapsed.\n", t1);			}		}	} 	/* Clear weakrefs and invoke callbacks as necessary. */	m += handle_weakrefs(&unreachable, old); 	/* Call tp_clear on objects in the unreachable set.  This will cause	 * the reference cycles to be broken.  It may also cause some objects	 * in finalizers to be freed.	 */	delete_garbage(&unreachable, old); 	/* Collect statistics on uncollectable objects found and print	 * debugging information. */	for (gc = finalizers.gc.gc_next;	     gc != &finalizers;	     gc = gc->gc.gc_next) {		n++;		if (debug & DEBUG_UNCOLLECTABLE)			debug_cycle("uncollectable", FROM_GC(gc));	}	if (debug & DEBUG_STATS) {		if (m == 0 && n == 0)			PySys_WriteStderr("gc: done.\n");		else			PySys_WriteStderr(			    "gc: done, "			    "%" PY_FORMAT_SIZE_T "d unreachable, "			    "%" PY_FORMAT_SIZE_T "d uncollectable.\n",			    n+m, n);	} 	/* Append instances in the uncollectable set to a Python	 * reachable list of garbage.  The programmer has to deal with	 * this if they insist on creating this type of structure.	 */	(void)handle_finalizers(&finalizers, old); 	if (PyErr_Occurred()) {		if (gc_str == NULL)			gc_str = PyString_FromString("garbage collection");		PyErr_WriteUnraisable(gc_str);		Py_FatalError("unexpected exception during garbage collection");	}	return n+m;} static Py_ssize_tcollect_generations(void){	int i;	Py_ssize_t n = 0; 	/* Find the oldest generation (higest numbered) where the count	 * exceeds the threshold.  Objects in the that generation and	 * generations younger than it will be collected. */	for (i = NUM_GENERATIONS-1; i >= 0; i--) {		if (generations[i].count > generations[i].threshold) {			n = collect(i);			break;		}	}	return n;} PyDoc_STRVAR(gc_enable__doc__,"enable() -> None\n""\n""Enable automatic garbage collection.\n"); static PyObject *gc_enable(PyObject *self, PyObject *noargs){	enabled = 1;	Py_INCREF(Py_None);	return Py_None;} PyDoc_STRVAR(gc_disable__doc__,"disable() -> None\n""\n""Disable automatic garbage collection.\n"); static PyObject *gc_disable(PyObject *self, PyObject *noargs){	enabled = 0;	Py_INCREF(Py_None);	return Py_None;} PyDoc_STRVAR(gc_isenabled__doc__,"isenabled() -> status\n""\n""Returns true if automatic garbage collection is enabled.\n"); static PyObject *gc_isenabled(PyObject *self, PyObject *noargs){	return PyBool_FromLong((long)enabled);} PyDoc_STRVAR(gc_collect__doc__,"collect([generation]) -> n\n""\n""With no arguments, run a full collection.  The optional argument\n""may be an integer specifying which generation to collect.  A ValueError\n""is raised if the generation number is invalid.\n\n""The number of unreachable objects is returned.\n"); static PyObject *gc_collect(PyObject *self, PyObject *args, PyObject *kws){	static char *keywords[] = {"generation", NULL};	int genarg = NUM_GENERATIONS - 1;	Py_ssize_t n; 	if (!PyArg_ParseTupleAndKeywords(args, kws, "|i", keywords, &genarg))		return NULL; 	else if (genarg < 0 || genarg >= NUM_GENERATIONS) {		PyErr_SetString(PyExc_ValueError, "invalid generation");		return NULL;	} 	if (collecting)		n = 0; /* already collecting, don't do anything */	else {		collecting = 1;		n = collect(genarg);		collecting = 0;	} 	return PyInt_FromSsize_t(n);} PyDoc_STRVAR(gc_set_debug__doc__,"set_debug(flags) -> None\n""\n""Set the garbage collection debugging flags. Debugging information is\n""written to sys.stderr.\n""\n""flags is an integer and can have the following bits turned on:\n""\n""  DEBUG_STATS - Print statistics during collection.\n""  DEBUG_COLLECTABLE - Print collectable objects found.\n""  DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects found.\n""  DEBUG_INSTANCES - Print instance objects.\n""  DEBUG_OBJECTS - Print objects other than instances.\n""  DEBUG_SAVEALL - Save objects to gc.garbage rather than freeing them.\n""  DEBUG_LEAK - Debug leaking programs (everything but STATS).\n"); static PyObject *gc_set_debug(PyObject *self, PyObject *args){	if (!PyArg_ParseTuple(args, "i:set_debug", &debug))		return NULL; 	Py_INCREF(Py_None);	return Py_None;} 

Lines 501–1000 of 1390. Previous lines