[Python-Dev] Re: tp_clear return value

Tim Peters tim.one@comcast.net
Thu, 10 Apr 2003 14:09:57 -0400


[Tim]
> Still, I expect both could be handled by setjmp in the gc
> module get_ref* driver functions and longjmp (as needed) in the
> gc module visitor functions.  IOW, the tp_traverse slot functions don't
> really need to cooperate, or even know anything about "early returns".

[martin@v.loewis.de]
> That would require that tp_traverse does not modify any refcount while
> iterating, right?

Or do anything else that relies on calls to visit() returning.  I've looked
at every traverse slot in the core, and there's no problem with those.  I
don't think that's an accident -- the only purpose of an object's
tp_traverse is to invoke the visit callback on the non-NULL PyObject*
pointers the object has.  So, e.g., there isn't an incref or decref in any
of 'em now; at worst there's an int loop counter.

> It seems unpythonish to use setjmp/longjmp for exceptions.

I'm not suggesting adding setjmp/longjmp to the Python language <0.9 wink>.
I'm suggesting using them for two specific and obscure gc module callbacks
that aren't normally used (*most* of the gc module callbacks wouldn't use
setjmp/longjmp); in return, mounds of frequently executed code like

static int
func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
{
	int err;
	if (f->func_code) {
		err = visit(f->func_code, arg);
		if (err)
			return err;
	}
	if (f->func_globals) {
		err = visit(f->func_globals, arg);
		if (err)
			return err;
	}
	if (f->func_module) {
		err = visit(f->func_module, arg);
		if (err)
			return err;
	}
	if (f->func_defaults) {
		err = visit(f->func_defaults, arg);
		if (err)
			return err;
	}
	if (f->func_doc) {
		err = visit(f->func_doc, arg);
		if (err)
			return err;
	}
	...
	return 0;
}

could become the simpler and faster

static int
func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
{
	int err;
	if (f->func_code)
		visit(f->func_code, arg);
	if (f->func_globals)
		visit(f->func_globals, arg);
	if (f->func_module)
		visit(f->func_module, arg);
	if (f->func_defaults)
		visit(f->func_defaults, arg);
	if (f->func_doc)
		visit(f->func_doc, arg);
	...
	return 0;
}

(I kept the final return 0 so that the signature wouldn't change.)