[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: Solaris, FastCGI, Apache, and "timeout.rb:52: [BUG] Segmentation fault"

MenTaLguY

10/5/2007 5:19:00 PM

On Sat, 6 Oct 2007 00:48:01 +0900, Trevor Wennblom <trevor@umn.edu> wrote:
> Just installed Ruby 1.8.6-p110. There seems to be a bug related to
> net/http, FastCGI, and Apache (1 or 2). I'm seeing this with a Rails-
> based application that has no problems with Mongrel, Webrick,
> Lighttpd, or Apache/CGI. This is on a Solaris environment, Ruby
> compiled with GCC.

I would strongly recommend against using timeout.rb: there is no
way to write robust code with it because it can interrupt the block at
any (i.e. the wrong) time, defeating normal cleanup/unwinding.

It shouldn't trigger a bug in the interpreter, granted, but it's
still risky no matter what you do.

-mental


4 Answers

Eric Hodel

10/5/2007 5:41:00 PM

0

On Oct 5, 2007, at 10:19 , MenTaLguY wrote:
> On Sat, 6 Oct 2007 00:48:01 +0900, Trevor Wennblom <trevor@umn.edu>
> wrote:
>> Just installed Ruby 1.8.6-p110. There seems to be a bug related to
>> net/http, FastCGI, and Apache (1 or 2). I'm seeing this with a Rails-
>> based application that has no problems with Mongrel, Webrick,
>> Lighttpd, or Apache/CGI. This is on a Solaris environment, Ruby
>> compiled with GCC.
>
> I would strongly recommend against using timeout.rb: there is no
> way to write robust code with it because it can interrupt the block at
> any (i.e. the wrong) time, defeating normal cleanup/unwinding.

Not true. You can always rescue the Timeout::Error and do proper
cleanup. It just takes work. (This may be dependent upon the way
ruby 1.8 checks to see if it should switch threads, which happens as
you finish executing a node, not as you start it.)

See:

http://blog.segment7.net/articles/2006/04/11/care-and-f...
timeout-timeout

And [ruby-talk:215086] and the rest of that thread.

--
Poor workers blame their tools. Good workers build better tools. The
best workers get their tools to do the work for them. -- Syndicate Wars



MenTaLguY

10/5/2007 7:19:00 PM

0

On Sat, 6 Oct 2007 02:41:11 +0900, Eric Hodel <drbrain@segment7.net> wrote:
>> I would strongly recommend against using timeout.rb: there is no
>> way to write robust code with it because it can interrupt the block at
>> any (i.e. the wrong) time, defeating normal cleanup/unwinding.
>
> Not true. You can always rescue the Timeout::Error and do proper
> cleanup. It just takes work.

Trivial example:

class Average
def initialize
@numbers = []
@total = 0
end

# postcondition: @total == @numbers.inject(0) { |a,n| a + n }
def add(n)
@numbers.push n
@total += n
end
end

Imagine that your timeout block repeatedly calls Average#add, and
the timeout exception is delivered to the thread before the second
statement in Average#add completes. What happens?

Yes, you could rewrite all your code and the libraries it uses to
pervasively use begin/ensure around every statement to maintain
invariants at the finest possible granularity, but it obviously
wouldn't perform well (and is also dependent on thread scheduling
behavior specific to Ruby 1.8).

-mental


Eric Hodel

10/5/2007 7:34:00 PM

0

On Oct 5, 2007, at 12:18 , MenTaLguY wrote:
> On Sat, 6 Oct 2007 02:41:11 +0900, Eric Hodel
> <drbrain@segment7.net> wrote:
>>> I would strongly recommend against using timeout.rb: there is no
>>> way to write robust code with it because it can interrupt the
>>> block at
>>> any (i.e. the wrong) time, defeating normal cleanup/unwinding.
>>
>> Not true. You can always rescue the Timeout::Error and do proper
>> cleanup. It just takes work.
>
> Trivial example:
>
> class Average
> def initialize
> @numbers = []
> @total = 0
> end
>
> # postcondition: @total == @numbers.inject(0) { |a,n| a + n }
> def add(n)
> @numbers.push n
> @total += n
> end
> end
>
> Imagine that your timeout block repeatedly calls Average#add, and
> the timeout exception is delivered to the thread before the second
> statement in Average#add completes. What happens?
>
> Yes, you could rewrite all your code and the libraries it uses to
> pervasively use begin/ensure around every statement to maintain
> invariants at the finest possible granularity, but it obviously
> wouldn't perform well (and is also dependent on thread scheduling
> behavior specific to Ruby 1.8).

When you timeout you cannot be sure of where your calculation
stopped, so you either rescue and cleanup, or you throw out the
results because they did not finish.

Also,

def add(n)
Thread.exclusive do
@numbers.push n
@total += n
end
end

--
Poor workers blame their tools. Good workers build better tools. The
best workers get their tools to do the work for them. -- Syndicate Wars



MenTaLguY

10/5/2007 9:39:00 PM

0

On Sat, 6 Oct 2007 04:33:44 +0900, Eric Hodel <drbrain@segment7.net> wrote:
> When you timeout you cannot be sure of where your calculation
> stopped, so you either rescue and cleanup, or you throw out the
> results because they did not finish.

Not just the results. You need to throw out any
object/class/external resource/etc. which was modified by the
aborted computation, because they may no longer be in a consistent
state.

If libraries (including stdlib) are involved, that may not be
easy to do (and cleanup could be even harder).

> def add(n)
> Thread.exclusive do
> @numbers.push n
> @total += n
> end
> end

What happens if Average comes from a library you're using?

Outside of very trivial blocks, Timeout simply isn't safe unless
the entire stack (from stdlib on up) is written in a way that would
preserve invariants in the face of asynchronous exceptions -- which
is not the case (and likely wouldn't be worth the overhead).

-mental