The command “timeout” which debuted in Coretuils 7.0 Beta (2008-10-05) is an exceedingly useful command. Often I write a script which needs to run a particular command for a period of time and then stop and restart. Before timeout this was quite painful. Some commands such as nc (netcat) and curl offer native timeouts as they are dealing with network operations. Non-network related commands almost never offer timeouts.

Often I have to use a utility program where I am suspect as to it’s ability to complete successfully in a given time period. I can ensure the command will stop within my timeframe by using the timeout command. An example would be a java class of which I am suspect. I can use the timeout command to let it complete successfully when my time limit is not reached and be killed once the time limit has expired. Below I run the suspect java class “SometimesLongRunning” using timeout. The command is supposed to finish in 5 seconds, I am however giving it up to 1 minute to finish. The first time the class “SometimesLongRunning” executes, it completes successfully in 5 seconds:

$ date; timeout 1m java SometimesLongRunning; date
Sat Jan 15 10:11:33 CST 2011
Sat Jan 15 10:11:38 CST 2011

However, as I suspected, on subsequent runs it will not complete in 5 seconds and the 1 minute timeout is enforced:

$ date; timeout 1m java SometimesLongRunning; date
Sat Jan 15 10:13:53 CST 2011
Sat Jan 15 10:14:53 CST 2011

Timeout by default sends the TERM signal after the timeout has expired, however by using the -s or –signal options you can tell timeout to send any signal you desire. I can see many uses for this feature. For example, let’s say I am having a problem with initialization of a JVM, I can use this to send the QUIT signal and have a thread dump taken soon after the JVM is launched. Much quicker than I could do so by hand and less racy than other solutions.

Back to the long running java class. Timeout allows me to do one better than simply killing the process after a specified time. I can use the –signal and –kill-after options together to take a thread dump after 10 seconds and kill the JVM after 1 minute. This allows me to both ensure the process respects my time limit and also gives me debugging information as where the JVM was stuck.


$ date; timeout --signal QUIT --kill-after 60s 10s java SometimesLongRunning; date
Sat Jan 15 10:18:03 CST 2011
2011-01-15 10:18:13
Full thread dump Java HotSpot(TM) 64-Bit Server VM (11.0-b16 mixed mode):

"Low Memory Detector" daemon prio=10 tid=0x00002aacab78b000 nid=0x7161 runnable [0x0000000000000000..0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"CompilerThread1" daemon prio=10 tid=0x00002aacab788000 nid=0x7160 waiting on condition [0x0000000000000000..0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"CompilerThread0" daemon prio=10 tid=0x00002aacab4e2800 nid=0x715f waiting on condition [0x0000000000000000..0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x00002aacab4e0c00 nid=0x715e runnable [0x0000000000000000..0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=10 tid=0x00002aacab4ce000 nid=0x715d in Object.wait() [0x0000000040d35000..0x0000000040d35ca0]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x00002aac023f1210> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
	- locked <0x00002aac023f1210> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x00002aacab4cc800 nid=0x715c in Object.wait() [0x0000000040c34000..0x0000000040c34e20]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x00002aac023f1078> (a java.lang.ref.Reference$Lock)
	at java.lang.Object.wait(Object.java:485)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
	- locked <0x00002aac023f1078> (a java.lang.ref.Reference$Lock)

"main" prio=10 tid=0x0000000040111c00 nid=0x7152 waiting on condition [0x000000004022a000..0x000000004022af60]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at SometimesLongRunning.main(SometimesLongRunning.java:5)

"VM Thread" prio=10 tid=0x00002aacab4c7000 nid=0x715b runnable 

"GC task thread#0 (ParallelGC)" prio=10 tid=0x000000004011c400 nid=0x7153 runnable 

"GC task thread#1 (ParallelGC)" prio=10 tid=0x000000004011e000 nid=0x7154 runnable 

"GC task thread#2 (ParallelGC)" prio=10 tid=0x000000004011f800 nid=0x7155 runnable 

"GC task thread#3 (ParallelGC)" prio=10 tid=0x0000000040121000 nid=0x7156 runnable 

"GC task thread#4 (ParallelGC)" prio=10 tid=0x0000000040122c00 nid=0x7157 runnable 

"GC task thread#5 (ParallelGC)" prio=10 tid=0x0000000040124400 nid=0x7158 runnable 

"GC task thread#6 (ParallelGC)" prio=10 tid=0x0000000040125c00 nid=0x7159 runnable 

"GC task thread#7 (ParallelGC)" prio=10 tid=0x0000000040127800 nid=0x715a runnable 

"VM Periodic Task Thread" prio=10 tid=0x00002aacab78d000 nid=0x7162 waiting on condition 

JNI global references: 590

Heap
 PSYoungGen      total 149952K, used 2571K [0x00002aac023f0000, 0x00002aac0cb40000, 0x00002aaca9940000)
  eden space 128576K, 2% used [0x00002aac023f0000,0x00002aac02672e28,0x00002aac0a180000)
  from space 21376K, 0% used [0x00002aac0b660000,0x00002aac0b660000,0x00002aac0cb40000)
  to   space 21376K, 0% used [0x00002aac0a180000,0x00002aac0a180000,0x00002aac0b660000)
 PSOldGen        total 342720K, used 0K [0x00002aaab3940000, 0x00002aaac87f0000, 0x00002aac023f0000)
  object space 342720K, 0% used [0x00002aaab3940000,0x00002aaab3940000,0x00002aaac87f0000)
 PSPermGen       total 21248K, used 2479K [0x00002aaaae540000, 0x00002aaaafa00000, 0x00002aaab3940000)
  object space 21248K, 11% used [0x00002aaaae540000,0x00002aaaae7abf28,0x00002aaaafa00000)

Killed
Sat Jan 15 10:19:13 CST 2011

3 Responses to “timeout – new coreutils command”

  1. Bliznezz Says:

    much better

    #Newsgroups: comp.unix.admin,comp.unix.solaris,comp.unix.shell
    #From: gwc@root.co.uk (Geoff Clare)
    #Subject: Re: timeout -t (Re: How to give rsh a shorter timeout?)
    #Message-ID:
    #Date: Fri, 13 Feb 1998 18:23:52 GMT

    #
    # Conversion to bash v2 syntax done by Chet Ramey <chet@po.cwru.edu
    # UNTESTED
    #

    prog=${0##*/}
    usage="usage: $prog [-signal] [timeout] [:interval] [+delay] [--] ”

    SIG=-TERM # default signal sent to the process when the timer expires
    timeout=60 # default timeout
    interval=15 # default interval between checks if the process is still alive
    delay=2 # default delay between posting the given signal and
    # destroying the process (kill -KILL)

    while :
    do
    case $1 in
    –) shift; break ;;
    -*) SIG=$1 ;;
    [0-9]*) timeout=$1 ;;
    :*) EXPR=’..\(.*\)’ ; interval=`expr x”$1″ : “$EXPR”` ;;
    +*) EXPR=’..\(.*\)’ ; delay=`expr x”$1″ : “$EXPR”` ;;
    *) break ;;
    esac
    shift
    done

    case $# in
    0) echo “$prog: $usage” >&2 ; exit 2 ;;
    esac

    (
    for t in $timeout $delay
    do
    while (( $t > $interval ))
    do
    sleep $interval
    kill -0 $$ || exit
    t=$(( $t – $interval ))
    done
    sleep $t
    kill $SIG $$ && kill -0 $$ || exit
    SIG=-KILL
    done
    ) 2> /dev/null &

    exec “$@”

  2. Allan Clark Says:

    @Bliznezz agreed, it’s much better that a consistent single binary provides this functionality — I’ve gone the scripting route, and the parent->child->child->service gets a bit dizzying, and trying to kill the script requires additional shellscript gymnastics.

    A few years ago, I went to a single binary for testing services building admin RPMs for Phorm; the binary was much easier to run in a self-test, kill when I’m impatient, and overall work with. Stripped, it’s tiny, too. I would imagine the more standardized coreutils variant would be similarly small and easy.

    Good to see!

    Thanks for commenting on this addition, and for the example!

  3. Ernest Mueller Says:

    Man, I got all pumped up reading this, then realized all the distros we have around here (Ubuntu, Red Hat) don’t have timeout included in their coreutils, because there’s some other older “timeout” package and there were conflicts and distros pulled it and fretted about it in bug trackers and the confusion sadly persists to this day.

    Note to distro guys – get timeout back into coreutils!

Leave a Reply

If Wordpress eats your comment (shell output, loops, ex..) brock (at) gmail dot com.