<div>NOTE:  we are presently running 2.5.7, but I&#39;ve confirmed that this change is still applicable to 2.5.9.  I&#39;ve not had a chance to look at 3.x or 4.x in any way.</div>
<div> </div>
<div>We recently wanted to change our kill_delay on our system to allow jobs adequate time to properly clean up in the event of a qdel.  At the same time I started playing with qsig and discovered that sending a USR1 signal to process would cause it to terminate (even if the jobscript/job properly handled SIGUSR1).</div>

<div> </div>
<div>It tuns out that both issues are related to the same problem: The failure of the user&#39;s shell (by default) to catch and properly handle signals.  This has been discussed here (and on torqueusers) several times in the past and the general recommendation has always been to have the user add the necessary &quot;trap&quot; statements to their .bashrc (or appropriate file) in addition to putting them in their job script.  </div>

<div> </div>
<div>The reasons for these recommendations stems from the process hierarchy that is created by pbs_mom:</div>
<p><font face="courier new,monospace">pbs_mom,6488 -p 
<div>  `-bash,10919</div>
<div>     `-16398.hpdjsl001,10978 -l /var/spool/pbs/mom_priv/jobs/<a href="http://16398.hpdjsl001.SC">16398.hpdjsl001.SC</a></div>
<div></div></font>
<div> </div>
<div>pbs_mom launches a shell (in my case bash) which, in turn, invokes the job script.  When the user executes a qsig or qdel... the server passes the signal to the mom and the mom signals both of these processes.  If the job script has the necessary trap calls in it... it, of course, handles the signal properly, but the shell process will exit... and many shells will exit even on on a seemingly innocuous SIGUSR1.  </div>

<div> </div>
<div>If the shell process exits... the pbs_mom believes the job to have died and automatically enters into a mode where it sends a SIGTERM to the jobscript and ~5seconds later a SIGKILL.  This happens whether regardless of the singal the user sent (even SIGUSR1) or in the event of a qdel.  However, given that the goal of a qdel is to remove a job... most Torque users are probably none the wiser that it isn&#39;t going through the &quot;correct&quot; termination sequence. </div>

<div> </div>
<div>We have a large user community (and most are not technical enough) that I don&#39;t reasonably expect them to be able to properly implement the changes to their individual login files.  I&#39;ve considering having our system configuration files updated, but this would affect all users (even those that don&#39;t submit jobs) and I we would be stuck maintaining a solution that works for each of about five different shells we have installed.</div>

<div> </div>
<div>So I wondered if there couldn&#39;t be a better way.</div>
<div> </div>
<div>I looked at the pbs_mom source and found how the pbs_mom passes the script command to invoked into the shell process.  It does so via a pipe which is connected to the shell&#39;s stdin. So I thought, &quot;why couldn&#39;t the shell simply &#39;exec&#39; the job script instead of running it as a simple command line?&quot;  It turns out that the pipe is closed shortly after the script&#39;s path is passed to the shell so it&#39;s not like pbs_mom was going to talk to the shell anymore... so why leave the shell running?  If the shell is no longer running... that&#39;s one less process to have worry about catching signals... and potentially it&#39;s less memory wasted on the compute node.</div>

<div> </div>
<div>I threw together this rather small patch as a prototype:</div>
<blockquote style="MARGIN-RIGHT:0px" dir="ltr">
<div><font face="courier new,monospace">diff -urN torque-2.5.7/src/resmom/start_exec.c torque-2.5.7-new/src/resmom/start_exec.c</font></div>
<div><font face="courier new,monospace">--- torque-2.5.7/src/resmom/start_exec.c        2011-06-17 17:15:57.000000000 -0500</font></div>
<div><font face="courier new,monospace">+++ torque-2.5.7-new/src/resmom/start_exec.c    2012-03-12 13:29:13.000000000 -0500</font></div>
<div><font face="courier new,monospace">@@ -1966,5 +1966,11 @@</font></div>
<div><font face="courier new,monospace">                {</font></div>
<div><font face="courier new,monospace">                int k;</font></div>
<div><font face="courier new,monospace">  </font></div>
<div><font face="courier new,monospace">+               if (strlen(buf)+5 &lt;= MAXPATHLEN) {</font></div>
<div><font face="courier new,monospace">+                       for (i=strlen(buf); i&gt;=0; i--)</font></div>
<div><font face="courier new,monospace">+                               buf[i+5] = buf[i];</font></div>
<div><font face="courier new,monospace">+                       strncpy(buf, &quot;exec &quot;, 5);</font></div>
<div><font face="courier new,monospace">+               }</font></div>
<div><font face="courier new,monospace">+</font></div>
<div><font face="courier new,monospace">                /* pass name of shell script on pipe */</font></div>
<div><font face="courier new,monospace">                /* will be stdin of shell  */</font></div></blockquote>
<div>...And found it to work as expected in our test environment (with admittedly limited testing).  All this does, (if there is still space in the buffer) is shifts everything over 5 characters and inserts &quot;exec &quot; at the beginning of the command line. The shell invokes the process, which of course, now exec&#39;s the script. The script inherits the pid of the shell as well as its stdin/stdout/stderr so pbs_demux appears to function correctly.</div>

<div> </div>
<div>Every shell I&#39;ve investigated (sh, csh, ksh, bash, zsh) all appear to honor the &quot;exec&quot; command in the same manner so this appears to be a viable solution to this problem (premature shell termination) without requiring users (or admins) to add &quot;trap&quot; statements to dotfiles to protect that one process.  For the record, this doesn&#39;t get anyone off the hook about installing trap&#39;s in the job scripts (or signal handlers in the processes themselves), but this appears to remove one of larger barriers in leveraging qsig(1) and extended kill_delay settings.</div>

<div> </div>
<div>I&#39;lll concede there could be a flaw in my logic, and as I stated above, this has only had limited testing thus far, but I would love to hear what I may have missed and why this couldn&#39;t be a viable change in Torque.</div>

<div> </div>
<div>This was tested by qsub&#39;ing the following perl script directly (no shell job-script around it).  This code simply catches signals, prints the time that they were received, and after the first signal is caught... prints the time in 1 second intervals (since you&#39;ll never see the final SIGKILL you can at least count of the seconds).</div>

<blockquote style="MARGIN-RIGHT:0px" dir="ltr">
<div><font face="courier new,monospace"></font><font face="courier new,monospace">#!/usr/bin/perl -l<br>use constant CATCH =&gt; qw/USR1 USR2 HUP TERM INT QUIT ABRT ILL FPE SEGV ALRM PIPE CHLD/;</font><font face="courier new,monospace"><br>
my $stop;<br>$|=1;</font></div>
<div><font face="courier new,monospace"><br>@SIG{(CATCH)} = (sub { $stop||=1; print join &#39; &#39;, shift, &#39;@&#39;, scalar localtime }) x CATCH;</font></div><font face="courier new,monospace">
<div><br>sleep unless $stop;<br>print (scalar localtime), sleep 1 while 1;</div></font></blockquote>
<div>When tested with a qdel, you&#39;ll see a TERM signal logged at the time invocation, followed by the number of printouts which correspond with your kill_delay setting (defaults to 2 seconds).  Finally you see a second SIGTERM and then ~5 seconds later the output stops (because the process receives a SIGKILL).  For the unfamiliar, when the server asks a mom to do a SIGKILL... it is hard coded to SIGTERM first and then ~5 seconds later to try a SIGKILL.</div>

<div> </div>
<div>Without my patch above (and without adding trap statements to your .bashrc) this script will output two SIGTERM&#39;s (typically within the same second) with about 5 more seconds of printouts (before the final kill). mom_logs will confirm that the initial SIGTERM terminated the shell process, and that the mom then automatically initiated a job termination (via the second TERM and KILL).</div>

<div> </div>
<div>I also won&#39;t take any offense if someone wants to implement the patch more efficiently, I was just trying to do what I wanted with the minimal amount of change to the torque code. </div>
<div> </div>
<div>Thanks,</div>
<div> </div>
<div>-Alan 
<div clear="all"> </div>
<div>-- </div>
<div><a href="mailto:alan@madllama.net">alan@madllama.net</a> <a href="http://humbleville.blogspot.com">http://humbleville.blogspot.com</a></div>
<div> </div></div></p>