Nested threading? implications to timeout()

On Sep 18, 2006, at 6:01 PM, Arnaud B. wrote:

If you may already be inside a critical section.

(or require ‘thread’ use Thread.exclusive)

This still leaves the race problem.

Where did I say this fixed any race conditions?

If you can raise an exception between an ensure and its first
instruction,

This appears to be impossible in the current interpreter.

NOTHING can be safe in the ensure clause.

If the first node is begin, then you appear to be safe. See my
response to the first message in this thread.

To solve this problem would require some changes to the language
semantics. At the very least external exceptions should not be
accepted when inside an ensure clause. This would require some
interpreter changes and certainly more thougth than what I have given
it.

Threads are switched after returning from rb_eval, not before. The
first node inside an ensure will always be executed. Your thread may
be switched after you begin to return from rb_eval.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On Sep 17, 2006, at 12:36 PM, Joel VanderWerf wrote:

The danger is that a timeout exception may fire during an ensure
Timeout.timeout 2 do
sleep 2

However, that solution only reduces the chance of the timeout
interfering with the ensure clause. Suppose the timeout fires while
the main thread is executing the line “timeout = nil”. (It’s
impossible in this example, but you can get it to happen by putting
a “sleep 5” just after this line.) Then the inner begin…end clause
doesn’t catch the timeout, and the cleanup doesn’t happen. In
general, unless you are very sure about the timings of your code,
you cannot guarantee that the timeout won’t fire at the wrong time.
So it’s a race condition.

From reading rb_eval, it might be possible to fix the race condition
by exploiting implementation details, but I don’t have the
opportunity to examine it in depth.

rb_eval looks something like this:

rb_eval(VALUE self, NODE node) {
switch (nd_type(node)) {
case NODE_ENSURE:
rb_eval(self, node->begin_body);
rb_eval(self, node->ensure_body);
break;
case NODE_RESCUE:
/
/
}
CHECK_INTS; /
check for a thread to switch to or a signal to
process */
}

So threads may be switched (and Timeout::Error raised) only when is
finished evaluating a node.

So if the first item of an ensure is begin (which creates a
NODE_RESCUE) we might be “safe”:

$ parse_tree_show -f
begin
perform some work
ensure
begin
clean up after ourselves
rescue Timeout::Error
retry
end
end
(eval):2: warning: parenthesize argument(s) for future version
(eval):5: warning: parenthesize argument(s) for future version
(eval):5: warning: parenthesize argument(s) for future version
[[:ensure,

this is the begin body.

[:fcall, :perform, [:array, [:fcall, :some, [:array,
[:vcall, :work]]]]],

this is the ensure body

[:rescue,
# this is the inner begin body, we will always reach here after
ensure.
[:fcall,
:clean,
[:array,
[:fcall,
:up,
[:array, [:fcall, :after, [:array, [:vcall, :ourselves]]]]]]],
# this is the rescue statement
[:resbody, [:array, [:colon2, [:const, :Timeout], :Error]],
# this is the rescue body
[:retry]]]]]

I am on vacation starting tomorrow, so I’ll probably look up this
thread when I return.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com