@@ -591,7 +591,7 @@ new_lock(void)
591
591
#endif
592
592
593
593
static PyObject *
594
- schedule_task_block (PyTaskletObject * prev , int stackless )
594
+ schedule_task_block (PyTaskletObject * prev , int stackless , int * did_switch )
595
595
{
596
596
PyThreadState * ts = PyThreadState_GET ();
597
597
PyObject * retval ;
@@ -615,12 +615,12 @@ schedule_task_block(PyTaskletObject *prev, int stackless)
615
615
*/
616
616
if (PyBomb_Check (prev -> tempval ))
617
617
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 );
619
619
}
620
620
if (!(retval = make_deadlock_bomb ()))
621
621
return NULL ;
622
622
TASKLET_SETVAL_OWN (prev , retval );
623
- return slp_schedule_task (prev , prev , stackless );
623
+ return slp_schedule_task (prev , prev , stackless , did_switch );
624
624
}
625
625
#ifdef WITH_THREAD
626
626
if (ts -> st .thread .self_lock == NULL ) {
@@ -679,7 +679,7 @@ schedule_task_block(PyTaskletObject *prev, int stackless)
679
679
next = prev ;
680
680
#endif
681
681
/* 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 );
683
683
PR ("schedule() is done" );
684
684
return retval ;
685
685
}
@@ -688,7 +688,8 @@ schedule_task_block(PyTaskletObject *prev, int stackless)
688
688
689
689
static PyObject * schedule_task_unblock (PyTaskletObject * prev ,
690
690
PyTaskletObject * next ,
691
- int stackless )
691
+ int stackless ,
692
+ int * did_switch )
692
693
{
693
694
PyThreadState * ts = PyThreadState_GET ();
694
695
PyThreadState * nts = next -> cstate -> tstate ;
@@ -724,7 +725,7 @@ static PyObject *schedule_task_unblock(PyTaskletObject *prev,
724
725
Py_END_ALLOW_THREADS
725
726
726
727
/* get myself ready */
727
- retval = slp_schedule_task (prev , prev , stackless );
728
+ retval = slp_schedule_task (prev , prev , stackless , did_switch );
728
729
729
730
/* see whether the other thread still exists and is really blocked */
730
731
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,
804
805
805
806
806
807
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 )
808
810
{
809
811
PyThreadState * ts = PyThreadState_GET ();
810
812
PyCStackObject * * cstprev ;
811
813
PyObject * retval ;
812
814
int (* transfer )(PyCStackObject * * , PyCStackObject * , PyTaskletObject * );
813
815
int no_soft_irq ;
816
+
817
+ if (did_switch )
818
+ * did_switch = 0 ; /* only set this if an actual switch occurs */
814
819
815
820
if (next == NULL ) {
816
- return schedule_task_block (prev , stackless );
821
+ return schedule_task_block (prev , stackless , did_switch );
817
822
}
818
823
#ifdef WITH_THREAD
819
824
/* note that next->cstate is undefined if it is ourself */
820
825
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 );
822
827
}
823
828
#endif
824
829
@@ -915,6 +920,8 @@ slp_schedule_task(PyTaskletObject *prev, PyTaskletObject *next, int stackless)
915
920
ts -> recursion_depth = next -> recursion_depth ;
916
921
917
922
ts -> st .current = next ;
923
+ if (did_switch )
924
+ * did_switch = 1 ;
918
925
919
926
assert (next -> cstate != NULL );
920
927
if (next -> cstate -> nesting_level != 0 ) {
@@ -973,6 +980,8 @@ slp_schedule_task(PyTaskletObject *prev, PyTaskletObject *next, int stackless)
973
980
TASKLET_CLAIMVAL (prev , & retval );
974
981
if (PyBomb_Check (retval ))
975
982
retval = slp_bomb_explode (retval );
983
+ if (did_switch )
984
+ * did_switch = 1 ;
976
985
return retval ;
977
986
}
978
987
else {
@@ -1066,9 +1075,13 @@ schedule_task_destruct(PyTaskletObject *prev, PyTaskletObject *next)
1066
1075
ts -> st .del_post_switch = (PyObject * )prev ;
1067
1076
1068
1077
/* 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 {
1072
1085
/* main is exiting */
1073
1086
TASKLET_CLAIMVAL (prev , & retval );
1074
1087
if (PyBomb_Check (retval ))
0 commit comments