Skip to content

Commit e78bb47

Browse files
author
kristjan.jonsson
committed
Fix a problem with delayed decref of tasklets. We need to know if slp_schedule_task() actually did schedule a new task, or if it was a no-op (due to same-task switching or some error). Fix the api to get information about that and manually clear the delayed decref flag when appropriate.
This fixes an assertion in test/taskspeed.py for debug builds. git-svn-id: http://svn.python.org/projects/stackless/trunk@82414 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent fcd1a8e commit e78bb47

File tree

5 files changed

+42
-20
lines changed

5 files changed

+42
-20
lines changed

Stackless/core/stackless_impl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,8 @@ PyAPI_FUNC(PyObject *) slp_tasklet_new(PyTypeObject *type, PyObject *args,
376376

377377
PyAPI_FUNC(PyObject *) slp_schedule_task(PyTaskletObject *prev,
378378
PyTaskletObject *next,
379-
int stackless);
379+
int stackless,
380+
int *did_switch);
380381

381382
PyAPI_FUNC(int) initialize_main_and_current(void);
382383

Stackless/module/channelobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ generic_channel_action(PyChannelObject *self, PyObject *arg, int dir, int stackl
481481
}
482482
}
483483
ts->st.runflags |= runflags; /* extra info for slp_schedule_task */
484-
retval = slp_schedule_task(source, target, stackless);
484+
retval = slp_schedule_task(source, target, stackless, 0);
485485

486486
if (interthread) {
487487
if (cando) {

Stackless/module/scheduling.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ new_lock(void)
591591
#endif
592592

593593
static PyObject *
594-
schedule_task_block(PyTaskletObject *prev, int stackless)
594+
schedule_task_block(PyTaskletObject *prev, int stackless, int *did_switch)
595595
{
596596
PyThreadState *ts = PyThreadState_GET();
597597
PyObject *retval;
@@ -615,12 +615,12 @@ schedule_task_block(PyTaskletObject *prev, int stackless)
615615
*/
616616
if (PyBomb_Check(prev->tempval))
617617
TASKLET_SETVAL(ts->st.main, prev->tempval);
618-
return slp_schedule_task(prev, ts->st.main, stackless);
618+
return slp_schedule_task(prev, ts->st.main, stackless, did_switch);
619619
}
620620
if (!(retval = make_deadlock_bomb()))
621621
return NULL;
622622
TASKLET_SETVAL_OWN(prev, retval);
623-
return slp_schedule_task(prev, prev, stackless);
623+
return slp_schedule_task(prev, prev, stackless, did_switch);
624624
}
625625
#ifdef WITH_THREAD
626626
if (ts->st.thread.self_lock == NULL) {
@@ -679,7 +679,7 @@ schedule_task_block(PyTaskletObject *prev, int stackless)
679679
next = prev;
680680
#endif
681681
/* this must be after releasing the locks because of hard switching */
682-
retval = slp_schedule_task(prev, next, stackless);
682+
retval = slp_schedule_task(prev, next, stackless, did_switch);
683683
PR("schedule() is done");
684684
return retval;
685685
}
@@ -688,7 +688,8 @@ schedule_task_block(PyTaskletObject *prev, int stackless)
688688

689689
static PyObject *schedule_task_unblock(PyTaskletObject *prev,
690690
PyTaskletObject *next,
691-
int stackless)
691+
int stackless,
692+
int *did_switch)
692693
{
693694
PyThreadState *ts = PyThreadState_GET();
694695
PyThreadState *nts = next->cstate->tstate;
@@ -724,7 +725,7 @@ static PyObject *schedule_task_unblock(PyTaskletObject *prev,
724725
Py_END_ALLOW_THREADS
725726

726727
/* get myself ready */
727-
retval = slp_schedule_task(prev, prev, stackless);
728+
retval = slp_schedule_task(prev, prev, stackless, did_switch);
728729

729730
/* see whether the other thread still exists and is really blocked */
730731
if (is_thread_alive(thread_id) && nts->st.thread.is_locked) {
@@ -804,21 +805,25 @@ static void slp_schedule_soft_irq(PyThreadState *ts, PyTaskletObject *prev,
804805

805806

806807
PyObject *
807-
slp_schedule_task(PyTaskletObject *prev, PyTaskletObject *next, int stackless)
808+
slp_schedule_task(PyTaskletObject *prev, PyTaskletObject *next, int stackless,
809+
int *did_switch)
808810
{
809811
PyThreadState *ts = PyThreadState_GET();
810812
PyCStackObject **cstprev;
811813
PyObject *retval;
812814
int (*transfer)(PyCStackObject **, PyCStackObject *, PyTaskletObject *);
813815
int no_soft_irq;
816+
817+
if (did_switch)
818+
*did_switch = 0; /* only set this if an actual switch occurs */
814819

815820
if (next == NULL) {
816-
return schedule_task_block(prev, stackless);
821+
return schedule_task_block(prev, stackless, did_switch);
817822
}
818823
#ifdef WITH_THREAD
819824
/* note that next->cstate is undefined if it is ourself */
820825
if (next->cstate != NULL && next->cstate->tstate != ts) {
821-
return schedule_task_unblock(prev, next, stackless);
826+
return schedule_task_unblock(prev, next, stackless, did_switch);
822827
}
823828
#endif
824829

@@ -915,6 +920,8 @@ slp_schedule_task(PyTaskletObject *prev, PyTaskletObject *next, int stackless)
915920
ts->recursion_depth = next->recursion_depth;
916921

917922
ts->st.current = next;
923+
if (did_switch)
924+
*did_switch = 1;
918925

919926
assert(next->cstate != NULL);
920927
if (next->cstate->nesting_level != 0) {
@@ -973,6 +980,8 @@ slp_schedule_task(PyTaskletObject *prev, PyTaskletObject *next, int stackless)
973980
TASKLET_CLAIMVAL(prev, &retval);
974981
if (PyBomb_Check(retval))
975982
retval = slp_bomb_explode(retval);
983+
if (did_switch)
984+
*did_switch = 1;
976985
return retval;
977986
}
978987
else {
@@ -1066,9 +1075,13 @@ schedule_task_destruct(PyTaskletObject *prev, PyTaskletObject *next)
10661075
ts->st.del_post_switch = (PyObject *)prev;
10671076

10681077
/* do a soft switch */
1069-
if (prev != next)
1070-
retval = slp_schedule_task(prev, next, 1);
1071-
else {
1078+
if (prev != next) {
1079+
int switched;
1080+
retval = slp_schedule_task(prev, next, 1, &switched);
1081+
if (!switched)
1082+
/* something happened, cancel prev's decref */
1083+
ts->st.del_post_switch = 0;
1084+
} else {
10721085
/* main is exiting */
10731086
TASKLET_CLAIMVAL(prev, &retval);
10741087
if (PyBomb_Check(retval))

Stackless/module/stacklessmodule.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ PyStackless_Schedule(PyObject *retval, int remove)
4545
PyThreadState *ts = PyThreadState_GET();
4646
PyTaskletObject *prev = ts->st.current, *next = prev->next;
4747
PyObject *ret = NULL;
48+
int switched;
4849

4950
if (ts->st.main == NULL) return PyStackless_Schedule_M(retval, remove);
5051
/* make sure we hold a reference to the previous tasklet */
@@ -65,7 +66,14 @@ PyStackless_Schedule(PyObject *retval, int remove)
6566
assert(ts->st.del_post_switch == NULL);
6667
ts->st.del_post_switch = (PyObject*)prev;
6768

68-
return slp_schedule_task(prev, next, stackless);
69+
ret = slp_schedule_task(prev, next, stackless, &switched);
70+
71+
/* however, if this was a no-op (e.g. prev==next, or an error occurred)
72+
* we need to decref prev ourselves
73+
*/
74+
if (!switched)
75+
Py_CLEAR(ts->st.del_post_switch);
76+
return ret;
6977
}
7078

7179
PyObject *
@@ -226,7 +234,7 @@ interrupt_timeout_return(void)
226234
else
227235
current->flags.pending_irq = 0;
228236

229-
return slp_schedule_task(ts->st.current, ts->st.main, 1);
237+
return slp_schedule_task(ts->st.current, ts->st.main, 1, 0);
230238
}
231239

232240
static PyObject *
@@ -270,7 +278,7 @@ PyStackless_RunWatchdogEx(long timeout, int flags)
270278

271279
/* now let them run until the end. */
272280
ts->st.runflags = flags;
273-
retval = slp_schedule_task(ts->st.main, ts->st.current, 0);
281+
retval = slp_schedule_task(ts->st.main, ts->st.current, 0, 0);
274282
ts->st.runflags = 0;
275283
ts->st.interrupt = NULL;
276284

Stackless/module/taskletobject.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ static TASKLET_RUN_HEAD(impl_tasklet_run)
524524
if (ts->st.main == NULL) return PyTasklet_Run_M(task);
525525
if (PyTasklet_Insert(task))
526526
return NULL;
527-
return slp_schedule_task(ts->st.current, task, stackless);
527+
return slp_schedule_task(ts->st.current, task, stackless, 0);
528528
}
529529

530530
static TASKLET_RUN_HEAD(wrap_tasklet_run)
@@ -739,7 +739,7 @@ post_schedule_remove(PyFrameObject *f, int exc, PyObject *retval)
739739
slp_current_remove(); /* reference used in tempval */
740740
TASKLET_SETVAL_OWN(self, parent);
741741
TASKLET_SETVAL_OWN(parent, retval); /* consume it */
742-
ret = slp_schedule_task(parent, self, 1);
742+
ret = slp_schedule_task(parent, self, 1, 0);
743743
return ret;
744744
}
745745

@@ -891,7 +891,7 @@ static TASKLET_RAISE_EXCEPTION_HEAD(impl_tasklet_raise_exception)
891891
TASKLET_CLAIMVAL(self, &bomb);
892892
return slp_bomb_explode(bomb);
893893
}
894-
return slp_schedule_task(ts->st.current, self, stackless);
894+
return slp_schedule_task(ts->st.current, self, stackless, 0);
895895
}
896896

897897

0 commit comments

Comments
 (0)