www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Can D throw a hanging exception if a function takes too long?

reply ajvincent juno.com writes:
Earlier today, while working on a BigDecimal library for D (my first project in
D, porting a JavaScript-based BigDecimal library I wrote a few years ago), I
accidentally caused a hang in my code.

I'm thinking it would be really nice to specify a code block like this:
unittest {
timelimit(n) {
// code to run goes here
}
}

where n is a number of milliseconds that the code within must finish running by.
If the elapsed amount of time passes, throw an exception and bail out.

I don't know anything worth talking about when it comes to compilers, so if this
is a "mission: impossible" task, I'd like to know.
Sep 26 2004
next sibling parent reply Burton Radons <burton-radons shaw.ca> writes:
ajvincent juno.com wrote:
 Earlier today, while working on a BigDecimal library for D (my first project in
 D, porting a JavaScript-based BigDecimal library I wrote a few years ago), I
 accidentally caused a hang in my code.
 
 I'm thinking it would be really nice to specify a code block like this:
 unittest {
 timelimit(n) {
 // code to run goes here
 }
 }

Kids, don't call this at home. I have no idea if it's actually doing it properly. All I know is that it worked the one time I tried it. private import std.thread; private import std.c.windows.windows; extern (Windows) BOOL TerminateThread (HANDLE handle, DWORD exitCode); class TimeLimitError : Error { this () { super ("TimeLimitError: Time limit has run out."); } } void timelimit (ulong milliseconds, void delegate () call) { int call_wrap () { call (); return 0; } Thread thread = new Thread (&call_wrap); thread.start (); try thread.wait (milliseconds); catch (ThreadError error) { } if (thread.getState == Thread.TS.RUNNING) { TerminateThread (thread.hdl, 0); foreach (inout Thread compare; Thread.getAll ()) if (compare === thread) { compare = null; break; } Thread.nthreads --; CloseHandle (thread.hdl); throw new TimeLimitError (); } } Usage example: timelimit (100, delegate void () { while (1) printf (""); }); Does anyone know if there's a way to terminate threads in Linux?
Sep 26 2004
parent Regan Heath <regan netwin.co.nz> writes:
On Sun, 26 Sep 2004 23:50:15 -0700, Burton Radons <burton-radons shaw.ca> 
wrote:

<snip>

 Does anyone know if there's a way to terminate threads in Linux?

pthread_kill(); Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 27 2004
prev sibling next sibling parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <cj8bge$17ni$1 digitaldaemon.com>, ajvincent juno.com says...

I'm thinking it would be really nice to specify a code block like this:
unittest {
timelimit(n) {
// code to run goes here
}
}

where n is a number of milliseconds that the code within must finish running by.

Actualy, I think the code would look like this: # unittest # { # auto TimeLimit timeLimit = new TimeLimit(n); # // code to run goes here # } where TimeLimit is an auto class. Its job would be simply to sleep for the given timeout and then throw - unless it gets destructed first.
if this
is a "mission: impossible" task, I'd like to know.

I can imagine some difficulties ... throwing exceptions in constructors/destructors; throwing exceptions from another thread, and so on. It may be that the exception handling mechanism is not the ideal tool for this, but that's the best idea I have so far. Jill
Sep 26 2004
parent reply teqDruid <teqDruid_member pathlink.com> writes:
In article <cj8dj5$1bg2$1 digitaldaemon.com>, Arcane Jill says...
In article <cj8bge$17ni$1 digitaldaemon.com>, ajvincent juno.com says...

I'm thinking it would be really nice to specify a code block like this:
unittest {
timelimit(n) {
// code to run goes here
}
}

where n is a number of milliseconds that the code within must finish running by.

Actualy, I think the code would look like this: # unittest # { # auto TimeLimit timeLimit = new TimeLimit(n); # // code to run goes here # } where TimeLimit is an auto class. Its job would be simply to sleep for the given timeout and then throw - unless it gets destructed first.
if this
is a "mission: impossible" task, I'd like to know.

I can imagine some difficulties ... throwing exceptions in constructors/destructors; throwing exceptions from another thread, and so on. It may be that the exception handling mechanism is not the ideal tool for this, but that's the best idea I have so far. Jill

That's on the right track, but I'd prefer (and I think I'd be easier to implement) this: void myTask() { //Do something } TimedTask t = new TimedTask(&myTask, 1500 /*Time limit*/); t.run(); This wouldn't be too hard to implement in Linux using a threading and some signals... in fact, I think I'll write a quick implementation later today. John
Sep 27 2004
parent reply Benjamin Herr <ben 0x539.de> writes:
teqDruid wrote:
 This wouldn't be too hard to implement in Linux using a threading and some
 signals... in fact, I think I'll write a quick implementation later today.

thought they were meant to be reserved for the user of one's library. -ben
Sep 27 2004
parent teqDruid <teqDruid_member pathlink.com> writes:
pthread_kill sends a signal.  Signals are the most basic form of IPC in Linux.
Basically all they can do is interrupt a thread, but one can obviously build off
of that.  There is a class of signals that are meant to be delivered to a
program from the "outside," but nothing in the pthread standard stops someone
from using them inside a program.

John

In article <cj9dsh$120u$1 digitaldaemon.com>, Benjamin Herr says...
teqDruid wrote:
 This wouldn't be too hard to implement in Linux using a threading and some
 signals... in fact, I think I'll write a quick implementation later today.

thought they were meant to be reserved for the user of one's library. -ben

Sep 27 2004
prev sibling next sibling parent reply "Chr. Grade" <tickle everymail.net> writes:
How about this:

[1] new loop construct

whilst
{
   // never loops more times than u32_max or u64_max
   // compiler issues error if looped more times during unit testing
}


[2] new prefix for keywords

no_overflow ubyte nFoo = 0xFF;

while( nFoo++ ) {};   // error during unit testing


Chr. Grade

ajvincent juno.com wrote:
  > I'm thinking it would be really nice to specify a code block like this:
 unittest {
 timelimit(n) { // code to run goes here };
 }
 
 where n is a number of milliseconds that the code within must finish running
by.
 If the elapsed amount of time passes, throw an exception and bail out.

Sep 27 2004
parent reply Sjoerd van Leent <svanleent wanadoo.nl> writes:
Chr. Grade wrote:
 
 How about this:
 
 [1] new loop construct
 
 whilst
 {
   // never loops more times than u32_max or u64_max
   // compiler issues error if looped more times during unit testing
 }
 
 
 [2] new prefix for keywords
 
 no_overflow ubyte nFoo = 0xFF;
 
 while( nFoo++ ) {};   // error during unit testing
 

Don't quite see it: invariant { assert(nFoo <= 0xFF); } it's valid. Wrap a class that uses this for no_overflow... Regards, Sjoerd
Sep 27 2004
parent reply Sean Kelly <sean f4.ca> writes:
In article <cj9bcm$109b$1 digitaldaemon.com>, Sjoerd van Leent says...
Chr. Grade wrote:
 
 How about this:
 
 [1] new loop construct
 
 whilst
 {
   // never loops more times than u32_max or u64_max
   // compiler issues error if looped more times during unit testing
 }
 
 
 [2] new prefix for keywords
 
 no_overflow ubyte nFoo = 0xFF;
 
 while( nFoo++ ) {};   // error during unit testing
 

Don't quite see it: invariant { assert(nFoo <= 0xFF); } it's valid. Wrap a class that uses this for no_overflow...

But won't ubyte always be <= 0xFF? Sean
Sep 27 2004
next sibling parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Sean Kelly wrote:
 But won't ubyte always be <= 0xFF?

Yeah. Let's correct the idea. It would be very cool if we could have the compiler add automatic assertions which protect (in debug mode) against overflow. My thought is that, in debug mode, overflow should always be an error unless you mark a statement as expecting it. Something like this: int i = <whatever>; /* added automatically by compiler */ assert(i < INT_MAX); i++; /* no assert, since the statement expects overflow * MIGHT happen */ overflow i++; I haven't worked out all of the issues here, but this is my rough idea.
Sep 27 2004
prev sibling next sibling parent Sjoerd van Leent <svanleent wanadoo.nl> writes:
Sean Kelly wrote:
 In article <cj9bcm$109b$1 digitaldaemon.com>, Sjoerd van Leent says...
 
Chr. Grade wrote:

How about this:

[1] new loop construct

whilst
{
  // never loops more times than u32_max or u64_max
  // compiler issues error if looped more times during unit testing
}


[2] new prefix for keywords

no_overflow ubyte nFoo = 0xFF;

while( nFoo++ ) {};   // error during unit testing

Don't quite see it: invariant { assert(nFoo <= 0xFF); } it's valid. Wrap a class that uses this for no_overflow...

But won't ubyte always be <= 0xFF? Sean

I see, my fault. assert (T < T.type.max) or something in that manner would be sufficient. Also the reverse (underflow) could be guarded that way. regards, Sjoerd
Sep 27 2004
prev sibling parent "Chr. Grade" <tickle everymail.net> writes:
Sean Kelly wrote:
 In article <cj9bcm$109b$1 digitaldaemon.com>, Sjoerd van Leent says...
 
Chr. Grade wrote:

How about this:

[1] new loop construct

whilst
{
  // never loops more times than u32_max or u64_max
  // compiler issues error if looped more times during unit testing
}


[2] new prefix for keywords

no_overflow ubyte nFoo = 0xFF;

while( nFoo++ ) {};   // error during unit testing

Don't quite see it: invariant { assert(nFoo <= 0xFF); } it's valid. Wrap a class that uses this for no_overflow...

But won't ubyte always be <= 0xFF? Sean

while( nFoo ) { if( isCarryFlag( nFoo ) ) fnWheep( ... ); nFoo++; }
Sep 28 2004
prev sibling next sibling parent M <M_member pathlink.com> writes:
It is a very good idea, I need them SO MUCH in my programs. And the syntax
should be the same in WINDOWS and LINUX.

So Walter, PLEASE PLEASE PLEASE make it!

In article <cj8bge$17ni$1 digitaldaemon.com>, ajvincent juno.com says...
Earlier today, while working on a BigDecimal library for D (my first project in
D, porting a JavaScript-based BigDecimal library I wrote a few years ago), I
accidentally caused a hang in my code.

I'm thinking it would be really nice to specify a code block like this:
unittest {
timelimit(n) {
// code to run goes here
}
}

where n is a number of milliseconds that the code within must finish running by.
If the elapsed amount of time passes, throw an exception and bail out.

I don't know anything worth talking about when it comes to compilers, so if this
is a "mission: impossible" task, I'd like to know.

Sep 27 2004
prev sibling next sibling parent reply Stewart Gordon <Stewart_member pathlink.com> writes:
In article <cj8bge$17ni$1 digitaldaemon.com>, ajvincent juno.com says...
<snip>
I'm thinking it would be really nice to specify a code block like this:
unittest {
timelimit(n) {
// code to run goes here
}
}

where n is a number of milliseconds that the code within must finish running by.
If the elapsed amount of time passes, throw an exception and bail out.

The time it takes will depend on the speed of the CPU. So wouldn't it make more sense to specify a timelimit in CPU cycles? Stewart.
Sep 27 2004
parent reply ajvincent juno.com writes:
In article <cj92l1$fh7$1 digitaldaemon.com>, Stewart Gordon says...
The time it takes will depend on the speed of the CPU.  So wouldn't it make more
sense 
to specify a timelimit in CPU cycles?

Stewart.

Wow, that got a lot of replies in a hurry! I was strongly considering asking for it to be based on CPU cycles instead of time, for that very reason. For debugging purposes, it does make more sense to base it on how many cycles pass by, if at all possible. Mr. Bright, do you care to chime in? Is this something we can build into the language, or perhaps make as a std library?
Sep 27 2004
parent reply Regan Heath <regan netwin.co.nz> writes:
On Mon, 27 Sep 2004 16:26:22 +0000 (UTC), <ajvincent juno.com> wrote:
 In article <cj92l1$fh7$1 digitaldaemon.com>, Stewart Gordon says...
 The time it takes will depend on the speed of the CPU.  So wouldn't it 
 make more
 sense
 to specify a timelimit in CPU cycles?

 Stewart.

Wow, that got a lot of replies in a hurry! I was strongly considering asking for it to be based on CPU cycles instead of time, for that very reason. For debugging purposes, it does make more sense to base it on how many cycles pass by, if at all possible.

Can you use the clock(); function?
 Mr. Bright, do you care to chime in? Is this something we can build into 
 the
 language, or perhaps make as a std library?

Given the number of ideas so far I think it will be possible to do it with a std library. If it were a language construct would it limit your choices? Basically I'm wondering if everyone might want to do something slightly different and if we had a language construct it would do one thing, and might not be able to do the other things. That said, this sort of thing would be a really nice addition to the support D already has for threads. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 27 2004
parent reply Burton Radons <burton-radons shaw.ca> writes:
Regan Heath wrote:

 Mr. Bright, do you care to chime in? Is this something we can build 
 into the
 language, or perhaps make as a std library?

Given the number of ideas so far I think it will be possible to do it with a std library.

It doesn't specifically require compiler support, but it does require compiler-specific code. If/when I return to this I'll write code for terminating threads correctly and send it to Walter.
 If it were a language construct would it limit your choices? Basically 
 I'm wondering if everyone might want to do something slightly different 
 and if we had a language construct it would do one thing, and might not 
 be able to do the other things.

I think it works nicely as a library function. What it all comes down to is monitored execution of a bunch of code. So the core method of Thread would be: /** Run the thread, calling monitor during execution in the current * thread. If monitor ever returns false, terminate execution of * the thread and return false. If the thread terminates on its * own, return true. */ bit monitored_run (bit delegate () monitor) { /* Start running the thread. */ start (); /* Loop until the thread dies or until monitor returns false. */ while (getState != TS.TERMINATED) { /* Ask the monitor whether to continue. */ if (!monitor ()) { /* Stop execution of the thread. */ terminate (); /* Monitor returned false, return false. */ return false; } /* Yield the current timeslice. */ yield (); } /* Thread terminated on its own, return true. */ return true; } While timelimit would be the function: /** Execute run in a second thread, calling monitor during execution * in the current thread (passing the thread object). If monitor * ever returns false, terminate execution of the thread and return * false. If the thread terminates on its own, return true. */ bit monitored_run (void delegate () run, bit delegate (Thread thread) monitor) { /* Create the thread object. */ Thread thread = new Thread (call); /* Execute a monitored run. */ return thread.monitored_run (delegate bit () { /* Pass the delegate on with the addition of a parameter. */ return monitor (thread); }); } /** Execute call, throwing TimeLimitError if it takes longer than the * specified number of milliseconds. */ void timelimit (uint milliseconds, void delegate () call) { /* Execute a monitored run. */ if (!monitored_run (delegate bit (Thread thread) { /* Wait until the thread dies or until we run out of time. */ thread.wait (milliseconds); /* Return whether the thread died. */ return thread.getState == Thread.TS.TERMINATED; })) { /* Thread took too long; throw up. */ throw new TimeLimitError (); } } You could also monitor changing global state or do any other babysitting you want.
Sep 27 2004
parent reply ajvincent juno.com writes:
In article <cja27m$1d6u$1 digitaldaemon.com>, Burton Radons says...
It doesn't specifically require compiler support, but it does require 
compiler-specific code.  If/when I return to this I'll write code for 
terminating threads correctly and send it to Walter.

Sweet. How nice a feeling it is to encounter a product like D, come up with an idea no one else has really thought of yet, and see people just leap on it with a ton of suggested fixes. It's kind of how I felt here: https://bugzilla.mozilla.org/show_bug.cgi?id=123177 Very invigorating for a newbie to the language.
 If it were a language construct would it limit your choices? Basically 
 I'm wondering if everyone might want to do something slightly different 
 and if we had a language construct it would do one thing, and might not 
 be able to do the other things.

I think it works nicely as a library function. What it all comes down to is monitored execution of a bunch of code. So the core method of Thread would be:

Hmm. If I could ask one minor change, it'd be to see that we save the return value for errors (or 0 for a clean operation) and use an out parameter for the intended return value(s). This is how Mozilla's XPCOM code works.
Sep 27 2004
parent reply Burton Radons <burton-radons shaw.ca> writes:
ajvincent juno.com wrote:

 In article <cja27m$1d6u$1 digitaldaemon.com>, Burton Radons says...
 
If it were a language construct would it limit your choices? Basically 
I'm wondering if everyone might want to do something slightly different 
and if we had a language construct it would do one thing, and might not 
be able to do the other things.

I think it works nicely as a library function. What it all comes down to is monitored execution of a bunch of code. So the core method of Thread would be:

Hmm. If I could ask one minor change, it'd be to see that we save the return value for errors (or 0 for a clean operation) and use an out parameter for the intended return value(s). This is how Mozilla's XPCOM code works.

I'm not sure what you're talking about; how would this impact the API I presented, exactly? /** Run the thread, calling monitor during execution in the current * thread. If monitor ever returns false, terminate execution of * the thread and return false. If the thread terminates on its * own, return true. */ bit Thread.monitored_run (bit delegate () monitor); /** Execute run in a second thread, calling monitor during execution * in the current thread (passing the thread object). If monitor * ever returns false, terminate execution of the thread and return * false. If the thread terminates on its own, return true. */ bit monitored_run (void delegate () run, bit delegate (Thread thread) monitor); /** Execute call, throwing TimeLimitError if it takes longer than the * specified number of milliseconds. */ void timelimit (uint milliseconds, void delegate () call);
Sep 27 2004
parent reply ajvincent juno.com writes:
In article <cja55p$1f2a$1 digitaldaemon.com>, Burton Radons says...
I'm not sure what you're talking about; how would this impact the API I 
presented, exactly?

Forget it. It was just a minor nit anyway. 8-)
Sep 27 2004
parent reply Burton Radons <burton-radons smocky.com> writes:
ajvincent juno.com wrote:

 In article <cja55p$1f2a$1 digitaldaemon.com>, Burton Radons says...
 
I'm not sure what you're talking about; how would this impact the API I 
presented, exactly?

Forget it. It was just a minor nit anyway. 8-)

It sounds like you meant a return value from the thread, right? You can have those with this: /** Execute run in a second thread, calling monitor during execution * in the current thread (passing the thread object). If monitor * ever returns false, terminate execution of the thread and return * false. If the thread terminates on its own, put the result of * run in result and return true. */ template monitored_run_return (ReturnType) { bit monitored_run_return ( ReturnType delegate () run, bit delegate (Thread thread) monitor, out ReturnType result) { return !monitored_run (delegate void () { result = run (); }, &monitor); } } /* Example usage. */ void foo () { int return_value; if (monitored_run_return! (int) ( delegate int () { return xyz; }, bit delegate () { return wst; }, return_value)) { printf ("Got back %d!\n", return_value); } }
Sep 27 2004
parent ajvincent juno.com writes:
In article <cja6j1$1fv5$1 digitaldaemon.com>, Burton Radons says...

It sounds like you meant a return value from the thread, right?  You can 
have those with this:
...
     /* Example usage. */
     void foo ()
     {
         int return_value;

         if (monitored_run_return! (int) (
             delegate int () { return xyz; },
             bit delegate () { return wst; },
             return_value))
         {
             printf ("Got back %d!\n", return_value);
         }
     }

That sounds about right. The only difference I see is that foo() I would think would be "int foo()", and as a function return 0 for a successful operation. In other words, just as int main() returns 0 for an error-free operation, I would think this sort of thing could (not "must"!) do the same. All I'm saying is that if foo() returns a value, then the encapsulating code should probably return the same value. Propagate whatever returns (whether they be arguments or actual return statements) out from foo() to the main application.
Sep 27 2004
prev sibling next sibling parent Mike Swieton <mike swieton.net> writes:
On Mon, 27 Sep 2004 06:21:02 +0000, ajvincent wrote:

 Earlier today, while working on a BigDecimal library for D (my first project in
 D, porting a JavaScript-based BigDecimal library I wrote a few years ago), I
 accidentally caused a hang in my code.
 
 I'm thinking it would be really nice to specify a code block like this:
 unittest {
 timelimit(n) {
 // code to run goes here
 }
 }
 
 where n is a number of milliseconds that the code within must finish running
by.
 If the elapsed amount of time passes, throw an exception and bail out.
 
 I don't know anything worth talking about when it comes to compilers, so if
this
 is a "mission: impossible" task, I'd like to know.

I suspect this would be difficult to do at the language level. However, a threading library could have such functionality, but I think a program would need to be designed for it (i.e. set up it's own watchdog thread). What may be more immediately useful to some people, under Unix at least, is the alarm() system call. Mike Swieton __ The difference between losers and winners is that losers don't fail enough. - Ross Jeffries
Sep 27 2004
prev sibling parent Burton Radons <burton-radons shaw.ca> writes:
The main problem I'm finding with writing a robust implementation is 
that we don't want to dump the thread, we want to cause it to unwrap its 
finally stack and then have the manager terminate it.  Just dropping the 
thread might leave important state out of array.

I'll look into the problem more later; there's a solution, I just don't 
have the time and stamina (cold) right now to try to pick apart 
(/dmd/src/phobos/internal/deh.c).  Blech, C.
Sep 27 2004