Projects

Ticket #176 (new defect)

Opened 3 years ago

Last modified 14 months ago

timeout fails to raise a Timeout::Error

Reported by: acangiano@… Owned by: lsansonetti@…
Priority: major Milestone: MacRuby 1.0
Component: MacRuby Keywords:
Cc:

Description (last modified by martinlagardette@…) (diff)

timeout should raise a Timeout::Error with message "execution expired" when the time is up. Right now it doesn't.

For example, you can try the following:

require 'timeout'

timeout(2) do
  1+1 while true
end

Change History

Changed 20 months ago by martinlagardette@…

  • description modified (diff)

Changed 18 months ago by watson1978@…

I propose the following patch as a workaround until the problem of Thread is solved.

Please give me an opinion :-)

Changed 18 months ago by lsansonetti@…

I can see 2 problems. First, the 1+1 while true expression will never trigger a pthread cancelation point, which means it can't be interrupted (and timeout.rb uses thread cancelation). Second, it looks like current timeout.rb doesn't even cancel loop { 1+1 } which triggers cancelation points.

Your patch seems to fix the second problem. I don't believe the first problem is even fixable with the current macruby implementation.

Changed 18 months ago by watson1978@…

I see. This is a difficult issue :(

Changed 18 months ago by watson1978@…

Using a patch of comment:2, "1+1 while true" loops forever within "while (t->status != THREAD_DEAD) {" (line:168, thread.c).
Then, t->status was "THREAD_KILLED".

Changed 18 months ago by watson1978@…

The following patch seems to work well.

Changed 18 months ago by watson1978@…

$ cat t.rb
require 'timeout'

puts "** case 1"
v = Timeout.timeout(1) {
  52
}
p v == 52

puts "** case 2"
begin
  Timeout.timeout(1) {
    loop do
      1 + 1
    end
  }
rescue Timeout::Error
  p :ok
else
  p :ng
end

puts "** case 3"
begin
  Timeout.timeout(1) {
    1 + 1 while true
  }
rescue Timeout::Error
  p :ok
else
  p :ng
end

puts "** case 4"
th = Thread.new {sleep 2}
begin
  Timeout.timeout(1) {th.join}
rescue Timeout::Error
  p :ok
else
  p :ng
end

I was not considering "case 4" X(

$ macruby t.rb
** case 1
true
** case 2
:ok
** case 3
:ok
** case 4
terminate called after throwing an instance of 'RoxorThreadRaiseException*'
zsh: abort      macruby t.rb

Changed 18 months ago by lsansonetti@…

I think case 3 is unfixable unless we modify the way 1+1 while true is compiled. There is no way to "kill" this expression since it never enters a pthread cancelation point. So in the current context, Thread#raise cannot be deterministic in MacRuby. I am not sure this is important (I think Thread#raise should never be used anyways).

If we can make timeout.rb work for most of the case (at least not crash) it's good enough for now, I think.

Changed 14 months ago by lsansonetti@…

  • milestone set to MacRuby 1.0

Let's try to make timeout.rb work for most of the cases in 1.0.

Note: See TracTickets for help on using tickets.