<div dir="ltr">Summarizing some steps which might help others who are debugging synctask related issues. Since synctasks uses swapcontext() to switch among themselves, the pthread stack would only be representing the current executing tasks stack alone (which usually would be the syncenv_processor() scheduler.) To inspect the &quot;stack backtrace&quot; of other synctasks:<div>
<br></div><div style>0. Attach gdb to the live running (possibly deadlocked or hung) process. This approach does not work on a core dump (there might be a way to apply the same principles on a core dump, any suggestions welcome)</div>
<div><br></div><div>1. Get the address of their &#39;struct synctask&#39;. All the yielded synctasks are linked in a list originating at syncenv-&gt;waitq. The addresses of the links can be typecasted into &#39;struct synctask *&#39; (as long as we are keeping the first member as &#39;all_tasks&#39; in the structure definition).</div>
<div><br></div><div style>2. Once you have the address of the &#39;struct synctask&#39; you want to inspect the backtrace, inspect basic sanity of the structure with:</div><div style><br></div><div style>(gdb) p *(struct synctask *) 0xaddre55</div>
<div style><br></div><div style>Verify that the structure looks reasonably alright.</div><div style><br></div><div style>3. Perform a quick &quot;sneak peek&quot; into that synctask&#39;s backtrace at the time it yielded away:</div>
<div style><br></div><div style>(gdb) set $rsp = ((struct synctask *) 0xaddre55)-&gt;ctx.uc_mcontext.gregs[15]</div><div style>(gdb) set $pc = ((struct synctask *) 0xaddre55)-&gt;ctx.uc_mcontext.gregs[16]</div><div style>
(gdb) bt</div><div style><br></div><div style>Note that you are essentially &quot;sacrificing&quot; the current thread in order to inspect the backtrace. So to be safe, you would want to</div><div style><br></div><div style>
a) save the original $rsp and $pc values</div><div style>b) NOT execute &quot;continue&quot; after setting the synctask&#39;s saved values. Instead just inspect the stack with commands like &quot;bt&quot;, &quot;frame&quot; etc. and revert back the orig $pc and $rsp variables.</div>
<div style><br></div><div style>4. The above step is for x86_64. For other architectures you will need to find out the appropriate names of registers in gdb for the stack pointer and program counter, and also the index number of those saved register values inside gregs[].</div>
<div style><br></div><div style>For i386:</div><div style><br></div><div style>(gdb) set $esp = ((struct synctask *) 0xaddre55)-&gt;ctx.uc_mcontext.gregs[7]</div><div style>(gdb) set $pc = ((struct synctask *) 0xaddre55)-&gt;ctx.uc_mcontext.gregs[14]</div>
<div style><br></div><div style>For your architecture, you will need to confirm by inspecting /usr/include/sys/ucontext.h for the actual offsets of the saved register values.</div><div style><br></div><div style>5. Note that this procedure is not really a &quot;complete context switch&quot;. For a full context switch you will need to load all the saved register values necessary. This is because the compiler may</div>
<div style>chose to maintain variables completely in the registers and not on the stack - more so common in x86_64 than i386. Compiling with -O0 should &quot;improve the situation&quot; most of the times, but not a guarantee. You can load the other registers from the saved values too (look up the appropriate index into gregs[] for the value from /usr/include/sys/ucontext.h), but remember to save the current register values if you care about restoring and resuming the stalled process after inspection.</div>
<div style><br></div><div style>Happy hacking!</div><div style>Avati</div><div style><br></div></div>