From: MenTaLguY Date: 2008-02-12T02:54:39+09:00 Subject: Re: Timeout::Error Is there a way to implement this which doesn't rely on parsing the exception backtrace? It's going to be nasty for other Ruby implementations, and isn't great performance-wise. -mental On Sun, 10 Feb 2008 11:42:04 +0900, Nobuyoshi Nakada wrote: > Hi, > > At Sun, 10 Feb 2008 07:24:43 +0900, > Joel VanderWerf wrote in [ruby-core:15458]: >> Sorry, I wasn't clear. I'm not disagreeing with you, just suggesting >> that timeouts could be sensitive to location on the stack. > > Agreed your suggestion, even for nested timeouts. > > > @@ -25,6 +25,10 @@ > module Timeout > # Raised by Timeout#timeout when the block times out. > - class Error < Interrupt > + class Error < StandardError > end > + class ExitException < ::Exception # :nodoc: > + end > + > + CALLER_OFFSET = ((c = caller[0]) && /\A#{Regexp.quote(__FILE__)}:/o =~ > c) ? 1 : 0 > > # Executes the method's block. If the block execution terminates > before > @@ -36,6 +40,7 @@ module Timeout > # into your classes so they have a #timeout method, as well as a module > method, > # so you can call it directly as Timeout.timeout(). > - def timeout(sec, exception = Error) #:yield: +sec+ > + def timeout(sec, klass = nil) #:yield: +sec+ > return yield(sec) if sec == nil or sec.zero? > + exception = klass || Class.new(ExitException) > begin > x = Thread.current > @@ -45,4 +50,15 @@ module Timeout > } > return yield(sec) > + rescue exception => e > + rej = /\A#{Regexp.quote(__FILE__)}:#{__LINE__-4}\z/o > + (bt = e.backtrace).reject! {|m| rej =~ m} > + level = -caller(CALLER_OFFSET).size > + while /\A#{Regexp.quote(__FILE__)}:/o =~ bt[level] > + bt.delete_at(level) > + level += 1 > + end > + raise if klass # if exception class is specified, it > + # would be expected outside. > + raise Error, e.message, e.backtrace > ensure > if y and y.alive? > @@ -62,5 +78,5 @@ end > # Defined for backwards compatibility with earlier versions of > timeout.rb, see > # Timeout#timeout. > -def timeout(n, e = Timeout::Error, &block) > +def timeout(n, e = nil, &block) > Timeout::timeout(n, e, &block) > end > > >