New trace implementation; and profile (in a similat vein).
diff --git a/Python/ceval.c b/Python/ceval.c
index 3e0c76a..2b60e57 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -71,7 +71,9 @@
 static int assign_subscript PROTO((object *, object *, object *));
 static int assign_slice PROTO((object *, object *, object *, object *));
 static int import_from PROTO((object *, object *, object *));
-static object *call_trace PROTO((object *, frameobject *, char *, object *));
+static void call_exc_trace PROTO((object **, object**, frameobject *));
+static int call_trace
+	PROTO((object **, object **, frameobject *, char *, object *));
 
 
 static frameobject *current_frame;
@@ -109,7 +111,7 @@
 	register object *u;
 	register object *t;
 	register frameobject *f; /* Current frame */
-	object *trace;		/* Trace function or NULL */
+	object *trace = NULL;	/* Trace function or NULL */
 	object *retval;		/* Return value iff why == WHY_RETURN */
 	char *name;		/* Name used by some instructions */
 	FILE *fp;		/* Used by print operations */
@@ -157,13 +159,8 @@
 	
 	current_frame = f;
 
-	trace = sysget("trace");
-	if (trace != NULL) {
-	  if (trace == None) {
-		trace = NULL;
-	  }
-	  else {
-		/* sys.trace, if defined, is a function that will
+	if (sys_trace != NULL) {
+		/* sys_trace, if defined, is a function that will
 		   be called  on *every* entry to a code block.
 		   Its return value, if not None, is a function that
 		   will be called at the start of each executed line
@@ -175,20 +172,22 @@
 		   depends on the situation.  The global trace function
 		   (sys.trace) is also called whenever an exception
 		   is detected. */
-		trace = call_trace(trace, f, "call", arg);
-		if (trace == NULL) {
+		if (call_trace(&sys_trace, &trace, f, "call", arg)) {
 			/* Trace function raised an error */
-			sysset("trace", (object *)NULL);
 			current_frame = f->f_back;
 			DECREF(f);
 			return NULL;
 		}
-		if (trace == None) {
-			/* No need to trace this code block */
-			DECREF(trace);
-			trace = NULL;
+	}
+
+	if (sys_profile != NULL) {
+		/* Similar for sys_profile, except it needn't return
+		   itself and isn't called for "line" events */
+		if (call_trace(&sys_profile, (object**)0, f, "call", arg)) {
+			current_frame = f->f_back;
+			DECREF(f);
+			return NULL;
 		}
-	  }
 	}
 	
 	next_instr = GETUSTRINGVALUE(f->f_code->co_code);
@@ -1005,16 +1004,8 @@
 			if (trace != NULL) {
 				/* Trace each line of code reached */
 				f->f_lasti = INSTR_OFFSET();
-				x = call_trace(trace, f, "line", None);
-				/* The trace function must return itself
-				   in order to continue tracing */
-				DECREF(trace);
-				if (x == None) {
-					DECREF(x);
-					trace = NULL;
-				}
-				else
-					trace = x;
+				err = call_trace(&trace, &trace,
+						 f, "line", None);
 			}
 			break;
 		
@@ -1066,40 +1057,10 @@
 				f->f_lasti -= 2;
 			tb_here(f);
 
-			if (trace) {
-				object *type, *value, *traceback, *arg;
-				err_get(&type, &value);
-				traceback = tb_fetch();
-				arg = newtupleobject(3);
-				if (arg == NULL)
-					err_clear();
-				else {
-					settupleitem(arg, 0, type);
-					settupleitem(arg, 1, value);
-					settupleitem(arg, 2, traceback);
-				}
-				v = call_trace(trace, f, "exception", arg);
-				if (v == NULL) {
-					/* Trace function raised error */
-					tb_here(f);
-					sysset("trace", (object *)NULL);
-					XDECREF(trace);
-					trace = NULL;
-				}
-				else {
-					/* Restore original exception */
-					err_setval(type, value);
-					tb_store(traceback);
-					if (v == None)
-						DECREF(v);
-					else {
-						/* Set trace function */
-						XDECREF(trace);
-						trace = v;
-					}
-				}
-				XDECREF(arg);
-			}
+			if (trace)
+				call_exc_trace(&trace, &trace, f);
+			if (sys_profile)
+				call_exc_trace(&sys_profile, (object**)0, f);
 		}
 		
 		/* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */
@@ -1177,15 +1138,22 @@
 	
 	if (trace) {
 		if (why == WHY_RETURN) {
-			x = call_trace(trace, f, "return", retval);
-			if (x == NULL) {
+			if (call_trace(&trace, &trace, f, "return", retval)) {
 				XDECREF(retval);
 				retval = NULL;
+				why = WHY_EXCEPTION;
 			}
-			else
-				DECREF(x);
 		}
-		DECREF(trace);
+		XDECREF(trace);
+	}
+	
+	if (sys_profile && why == WHY_RETURN) {
+		if (call_trace(&sys_profile, (object**)0,
+			       f, "return", retval)) {
+			XDECREF(retval);
+			retval = NULL;
+			why = WHY_EXCEPTION;
+		}
 	}
 	
 	/* Restore previous frame and release the current one */
@@ -1209,44 +1177,101 @@
 }
 #endif
 
-static object *
-call_trace(trace, f, msg, arg)
-	object *trace;
+static void
+call_exc_trace(p_trace, p_newtrace, f)
+	object **p_trace, **p_newtrace;
+	frameobject *f;
+{
+	object *type, *value, *traceback, *arg;
+	int err;
+	err_get(&type, &value);
+	traceback = tb_fetch();
+	arg = newtupleobject(3);
+	if (arg == NULL) {
+		err = -1;
+		goto cleanup;
+	}
+	settupleitem(arg, 0, type);
+	settupleitem(arg, 1, value);
+	settupleitem(arg, 2, traceback);
+	err = call_trace(p_trace, p_newtrace, f, "exception", arg);
+	XDECREF(arg);
+ cleanup:
+	if (!err) {
+		/* Restore original exception */
+		err_setval(type, value);
+		tb_store(traceback);
+	}
+}
+
+static int
+call_trace(p_trace, p_newtrace, f, msg, arg)
+	object **p_trace; /* in/out; may not be NULL;
+			     may not point to NULL variable initially */
+	object **p_newtrace; /* in/out; may be NULL;
+				may point to NULL variable;
+				may be same variable as p_newtrace */
 	frameobject *f;
 	char *msg;
 	object *arg;
 {
-	object *arglist, *what, *res;
+	object *arglist, *what;
+	object *res = NULL;
 	static int tracing = 0;
 	
 	if (tracing) {
-		/* Don't trace the trace code! */
-		INCREF(None);
-		return None;
+		/* Don't do recursive traces */
+		if (p_newtrace) {
+			XDECREF(*p_newtrace);
+			*p_newtrace = NULL;
+		}
+		return 0;
 	}
 	
 	arglist = newtupleobject(3);
 	if (arglist == NULL)
-		return NULL;
+		goto cleanup;
 	what = newstringobject(msg);
-	if (what == NULL) {
-		DECREF(arglist);
-		return NULL;
-	}
+	if (what == NULL)
+		goto cleanup;
 	INCREF(f);
+	settupleitem(arglist, 0, (object *)f);
+	settupleitem(arglist, 1, what);
 	if (arg == NULL)
 		arg = None;
 	INCREF(arg);
-	settupleitem(arglist, 0, (object *)f);
-	settupleitem(arglist, 1, what);
 	settupleitem(arglist, 2, arg);
 	tracing++;
-	res = call_object(trace, arglist);
+	res = call_object(*p_trace, arglist);
 	tracing--;
-	if (res == NULL)
+ cleanup:
+	XDECREF(arglist);
+	if (res == NULL) {
+		/* The trace proc raised an exception */
 		tb_here(f);
-	DECREF(arglist);
-	return res;
+		XDECREF(*p_trace);
+		*p_trace = NULL;
+		if (p_newtrace) {
+			XDECREF(*p_newtrace);
+			*p_newtrace = NULL;
+		}
+	}
+	else {
+		if (p_newtrace) {
+			XDECREF(*p_newtrace);
+			if (res == None)
+				*p_newtrace = NULL;
+			else {
+				INCREF(res);
+				*p_newtrace = res;
+			}
+		}
+		DECREF(res);
+	}
+	if (res == NULL)
+		return -1;
+	else
+		return 0;
 }
 
 object *