<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Generator" content="Microsoft Word 14 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
        {mso-style-priority:34;
        margin-top:0cm;
        margin-right:0cm;
        margin-bottom:0cm;
        margin-left:36.0pt;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";}
span.EmailStyle17
        {mso-style-type:personal-compose;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri","sans-serif";}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
/* List Definitions */
@list l0
        {mso-list-id:476070898;
        mso-list-type:hybrid;
        mso-list-template-ids:-1749789754 67698705 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l0:level1
        {mso-level-text:"%1\)";
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level2
        {mso-level-number-format:alpha-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level3
        {mso-level-number-format:roman-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:right;
        text-indent:-9.0pt;}
@list l0:level4
        {mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level5
        {mso-level-number-format:alpha-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level6
        {mso-level-number-format:roman-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:right;
        text-indent:-9.0pt;}
@list l0:level7
        {mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level8
        {mso-level-number-format:alpha-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;}
@list l0:level9
        {mso-level-number-format:roman-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:right;
        text-indent:-9.0pt;}
ol
        {margin-bottom:0cm;}
ul
        {margin-bottom:0cm;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal"><span lang="IS">So, I have been working with multithreaded stuff, even done some fixes.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="IS">There is this function, </span>slp_kill_tasks_with_stacks, which is supposed to kill tasklets with stacks.  It turns out, that for all threads but the main thread, it kills _<i>all</i>_ tasklets, because such tasklets each
 have their own cstate object.  Yes, all tasklets on worker threads are linked into the cstate circular list, in order to have them killed when a thread goes away.  This is achieved through the function tasklet_ensure_linkage().  Whether this is required, is
 another topic.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Now, the last thing this function does to a tasklet thus killed is to change its cstate->tstate to the initial tstate.  That’s right, it makes it so that it appears to have come from the main thread.   I have been experimenting with setting
 this to NULl instead, to indicate that it comes from a dead thread.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Anyway, this is when I found out that slp_kill_tasks_with_stacks actually does not work at all.  When this function is entered, when the thtread state is being cleared, tstate->ts.main (and tstate->ts.current) is already NULL, having been
 cleared here, in tasklet_end():<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New";color:green">/* capture all exceptions */<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">   
<span style="color:blue">if</span> (ismain) {<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">       
<span style="color:green">/*<o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New";color:green">         * Main wants to exit. We clean up, but leave the<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New";color:green">         * runnables chain intact.<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New";color:green">         */<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">        ts->st.main = NULL;<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">        Py_DECREF(retval);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">        retval = schedule_task_destruct(task, task);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">        Py_DECREF(task);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">       
<span style="color:blue">return</span> retval;<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">    }<o:p></o:p></span></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">So, all the gymnastics that slp_kill_tasks_with_stacks does with trying to place tasklets before the “current” tasklet and so on are senseless since thre is no current tasklet.  In parcicular:  When a tasklet that is to be killed is linked
 into the current queue, it becomes the “main” tasklet and also the “current” tasklet.  PyTasklet_Kill then attempts to kill the current tasklet.  The kill function attempts to get the current frame, but then this code kicks in:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New";color:green">/*<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New";color:green">     * silently do nothing if the tasklet is dead.<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New";color:green">     * simple raising would kill ourself in this case.<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New";color:green">     */<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">   
<span style="color:blue">if</span> (slp_get_frame(task) == NULL)<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">        Py_RETURN_NONE;<o:p></o:p></span></p>
<p class="MsoNormal">And<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New";color:green">/* CAUTION: This function returns a borrowed reference */<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">PyFrameObject *<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">slp_get_frame(PyTaskletObject *task)<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">{<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">    PyThreadState *ts = PyThreadState_GET();<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:10.0pt;font-family:"Courier New"">   
<span style="color:blue">return</span> ts->st.current == task ? ts->frame : task->f.frame;<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New"">}</span><o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">So, slp_get_frame returns the ts->frame which already is NULL.
<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">In effect, it leaves the killed tasklet then in a strange state, where its next and prev members point to itself, but it has a NULL frame.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">So, how can we fix tasklet killing on exit? It seems necessary, at least for threads with real C state in order to release any special C state that may be pendin on the C stack.<o:p></o:p></p>
<p class="MsoNormal">First, off, the code in tasklet_end, which clears the main tasklet, is incompatible with the kill_task_with_cstate.<o:p></o:p></p>
<p class="MsoNormal">Secondly, the latter function does appear very fragile.  What happens if a tasklet that is being killed refuses to die?  Or creates new tasklets?  I wonder if we should have a super exception, one that is not catchable as a system_exit,
 to ensure that they die….  Or maybe just require programs not to handle tasklet exit or do any magic tasklet stuff during such a handle clause.  But that’s a different story.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">What I think should happen is probably something like this.  Assuming that kill_tasks_with_cstate can be called with the man and current tasklets still valid:<o:p></o:p></p>
<p class="MsoListParagraph" style="text-indent:-18.0pt;mso-list:l0 level1 lfo1"><![if !supportLists]><span style="mso-list:Ignore">1)<span style="font:7.0pt "Times New Roman"">     
</span></span><![endif]>All runnable tasklets are removed from the runnable queue and decrefed, possibly resulting in them dying on their own or being killed, leaving only the main tasklet in the queue.<o:p></o:p></p>
<p class="MsoListParagraph" style="text-indent:-18.0pt;mso-list:l0 level1 lfo1"><![if !supportLists]><span style="mso-list:Ignore">2)<span style="font:7.0pt "Times New Roman"">     
</span></span><![endif]>Then proceed with killing each tasklet.  Now that there is only one in the queue left, there is no need to worry about the queue ordering.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Anyway, enough ranting.  I’m not sure what to do here.  It is annoying that the main tasklet is cleared like this.  But perhaps it is necessary.  Perhaps it is necessary to create a new temporary main tasklet…  Who knows.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">K<o:p></o:p></p>
</div>
</body>
</html>