From: Rocky Bernstein Date: 2008-02-12T03:33:39+09:00 Subject: Re: Timeout::Error ------=_Part_20358_281728.1202754827706 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline I wonder if this isn't made worse by the fact that backtrace and caller elements are strings. Wouldn't it be better for these to return some sort of structure or class for which there is a to_s method defined that gives a string representation that is compatible with the current string representation? On Feb 11, 2008 12:54 PM, MenTaLguY wrote: > 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 > > > > > > > > > ------=_Part_20358_281728.1202754827706 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline I wonder if this isn't made worse by the fact that backtrace and caller elements are strings. Wouldn't it be better for these to return  some sort of structure or class for which there is a to_s method defined that gives a string representation that is compatible with the current string representation?

On Feb 11, 2008 12:54 PM, MenTaLguY <mental@rydia.net> wrote:
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 <nobu@ruby-lang.org> 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
>
>
>



------=_Part_20358_281728.1202754827706--