how to print stack trace when TimeConstrained times out

According to the documentation, TimeConstrained generates an interrupt which interrupts the computation. This interrupt is treated just like an abort, at least in the sense that it respects AbortProtect.

I want to see the contents of the stack at the time the abort is generated, before the aborted evaluation is removed from the stack. I tried this:

changeAbort[] :=
(
Unprotect[Abort];
testAbort = True;
Abort[args___] :=
(
Print[Stack[_]]; (* in real life, to a log file *)
Block[{testAbort = False}, Abort[args]]
) /; testAbort
Protect[Abort];
)


This works for aborts that I generate myself. For example,

While[True, Abort[]]


aborts and prints the following stack trace:

(*
{While[True,Abort[]],Print[Stack[_]];Block[{testAbort=False},Abort[]],Print[Stack[_]]}
*)


Along (spiritually) similar lines, I can print the the stack at the time a message is displayed with this code:

InternalAddHandler["Message", Print[Stack[_]]&];


Getting back to TimeConstrained, neither of the following give me a stack trace:

changeAbort[];TimeConstrained[While[True, Null], 1]
TimeConstrained[changeAbort[]; While[True, Null], 1]


The last line was written in case TimeConstrained was implemented by temporarily redefining Abort. Unfortunately, it doesn't work.

Is there some way to intercept the interrupt generated by TimeConstrained so that I can get a stack trace of the aborted computation, before it is removed from the stack?

-
There are of course other ways to get at this information, such as Trace, TracePrint, interrupting the computation by hand, etc. However, when running a large number of computations with long timeouts in parallel, such methods become inefficient. Having a stack trace generated automatically when a computation hangs would save me a lot of time. –  Tobias Hagge Jan 30 '13 at 17:51

According to the documentation this CheckAbort construction (I think) should work to return the second argument.

In[37]:= CheckAbort[
TimeConstrained[
Pause[2], .2], "You were too slow so I gave up and left."]

(* Out[37]= \$Aborted *)


Clearly it has a different idea of what it should do.

I traipsed through and as best I could tell there is a strong difference of opinion between TimeConstrained's cleaning up aborts after itself, and what CheckAbort later needs to see. This might be something someone can improve, but not me.

Here is a simple workaround. If the TimeConstrained fires, give it an optional third argument to retrigger an abort.

CheckAbort[
TimeConstrained[Pause[2], .2,
Abort[]], "You were too slow so I gave up and left."]

(* Out[36]= "You were too slow so I gave up and left." *)
`

Now we get the CheckAbort result indicating it caught an abort.

-
This isn't quite what I need. I'm hoping to get a stack trace that measures the progress of the evaluation of the first argument to TimeConstrained, at the time that TimeConstrained generates the interrupt. This is unfortunately less than clear in my question; I'll edit it. –  Tobias Hagge Jan 30 '13 at 0:39