[Stackless-checkins] r51423 - in stackless/trunk/Stackless: core/stackless_impl.h core/stacklesseval.c test/test_exit_tasklet_killing.py

richard.tew python-checkins at python.org
Mon Aug 21 12:54:18 CEST 2006


Author: richard.tew
Date: Mon Aug 21 12:54:17 2006
New Revision: 51423

Added:
   stackless/trunk/Stackless/test/test_exit_tasklet_killing.py
      - copied unchanged from r51422, stackless/Python-2.4.3/dev/Stackless/test/test_exit_tasklet_killing.py
Modified:
   stackless/trunk/Stackless/core/stackless_impl.h
   stackless/trunk/Stackless/core/stacklesseval.c
Log:
Merged in r51422 from stackless/Python-2.4.3/dev.  Text from the commit message repeated:

Fix for error reported by Michael Brenner via the Stackless mailing list.

When the interpreter exits, all the remaining tasklets are killed via slp_kill_tasks_with_stacks in the main tasklet.  However, it is not possible to loop over the tasklets one by one killing them due to how scheduling works and that you need to schedule a tasklet to kill it.  When a tasklet is scheduled, and it finishes or blocks, the next tasklet in the list is then scheduled.  So what would happen is that every tasklet in the scheduler between the tasklet to be killed and the main tasklet, would be scheduled before we were back to the main tasklet and the killing of tasklets.  This is definitely not what we want.

The fix moves the main tasklet after the one we are killing, so that we are directly back to the tasklet killing loop when the one being killed exits.  At this time there is no reproducibility case to include as a unit test, so the script which reproduces the problem is included in the test directory.

Modified: stackless/trunk/Stackless/core/stackless_impl.h
==============================================================================
--- stackless/trunk/Stackless/core/stackless_impl.h	(original)
+++ stackless/trunk/Stackless/core/stackless_impl.h	Mon Aug 21 12:54:17 2006
@@ -356,6 +356,8 @@
 					 PyTaskletObject *next,
 					 int stackless);
 
+PyAPI_FUNC(int) initialize_main_and_current();
+
 /* setting the tasklet's tempval, optimized for no change */
 
 #define TASKLET_SETVAL(task, val) \

Modified: stackless/trunk/Stackless/core/stacklesseval.c
==============================================================================
--- stackless/trunk/Stackless/core/stacklesseval.c	(original)
+++ stackless/trunk/Stackless/core/stacklesseval.c	Mon Aug 21 12:54:17 2006
@@ -290,7 +290,8 @@
 
 	while (1) {
 		PyCStackObject *csfirst = slp_cstack_chain, *cs;
-		PyTaskletObject *t;
+		PyTaskletObject *t, *task;
+		PyTaskletObject **chain;
 
 		if (csfirst == NULL)
 			break;
@@ -310,6 +311,26 @@
 		t = cs->task;
 		Py_INCREF(t);
 
+		/* We need to ensure that the tasklet 't' is in the scheduler
+		 * tasklet chain before this one (our main).  This ensures
+		 * that this one is directly switched back to after 't' is
+		 * killed.  The reason we do this this is because if another
+		 * tasklet is switched to, this is of course it being scheduled
+		 * and run.  Why we do not need to do this for tasklets blocked
+		 * on channels is that when they are scheduled to be run and
+		 * killed, they will be implicitly placed before this one,
+		 * leaving it to run next.
+		 */
+		if (!t->flags.blocked) {
+			chain = &t;
+			SLP_CHAIN_REMOVE(PyTaskletObject, chain, task, next, prev)
+			chain = &cs->tstate->st.main;
+			task = cs->task;
+			SLP_CHAIN_INSERT(PyTaskletObject, chain, task, next, prev);
+			cs->tstate->st.current = cs->tstate->st.main;
+			t = cs->task;
+		}
+
 		PyTasklet_Kill(t);
 		PyErr_Clear();
 
@@ -325,6 +346,8 @@
 {
 	PyThreadState *ts = PyThreadState_Get();
 
+	if (ts->st.main == NULL)
+		initialize_main_and_current();
 	slp_kill_tasks_with_stacks(allthreads ? NULL : ts);
 }
 

_______________________________________________
Stackless-checkins mailing list
Stackless-checkins at stackless.com
http://www.stackless.com/mailman/listinfo/stackless-checkins



More information about the Stackless-checkins mailing list