On Mon, 12 Jan 2009 10:59:52 -0600, Ken Bloom wrote:

> On Mon, 12 Jan 2009 10:34:26 -0500, Charles Oliver Nutter wrote:
> 
>> Ken Bloom wrote:
>>> Which reminds me of another question I had. You were discussing
>>> somewhere else how Thread.critical works in JRuby. Does
>>> Thread.critical / Thread.exclusive in JRuby protect other threads
>>> against changes to the core class methods? Can I run
>>> Thread.critical=true , dramatically redefine operators on the core
>>> classes, redefine the operators back their original implementations,
>>> run Thread.critical=false, and expect that no other JRuby thread can
>>> get in and be broken becuase I've dramatically gutted the core
>>> classes?
>> 
>> You could up until about a week ago, when I proactively modified
>> critical= to just be a reentrant global lock. So basically..
>> 
>> Before:
>> * critical= causes the current thread to be the only thread running *
>> ...except on JRuby where threads run in parallel and have to reach a
>> checkpoint before they stop
>> * ...or if code you call from within a critical section itself spins up
>> threads
>> 
>> After:
>> 
>> * critical= acquires or releases a lock on a global mutex * threads
>> that don't have critical sections continue running * threads that try
>> to acquire the lock while another thread has it block
>> 
>> This was actually proposed by Shri Borde of IronRuby and blogged here:
>> 
>> http://blogs.msdn.com/shrib/archive/2009/01/07/proposed-spec-for-ruby-
s-
> thread-critical.aspx
>> 
>> She (he?) proposes that almost all current uses of critical= intend to
>> simply delimit a critical section of code, and so a single global mutex
>> is sufficient for those cases. And in light of the fact that native
>> calls and parallel-threaded impls can't be guaranteed to deschedule
>> other threads, I think this is a much more concrete and reasonable
>> definition. So I agreed, said so on a critical-related ruby-core
>> thread, and went ahead with the change. Nothing has broken so far :)
>> 
>> For your case, I think your best bet is to either make those changes
>> before other threads start running or just accept that some of them
>> won't see your changes all at once. I believe what you want to do may
>> work on MRI, since it doesn't actually run threads in parallel and
>> critical= stops it from scheduling new ones on its own.
> 
> My goal is that other threads don't see the changes, by operating as
> follows:
> 
> In Ruby 1.8 pseudocode:
> 
> old_critical=Thread.critical
> begin
>   Thread.critical=true
>  
>   [Fixnum,String].each{|klass| override_methods_on klass}
>   result=builderblock.call
>   [Fixnum,String].each{|klass| restore_methods_on klass}
> ensure
>   Thread.critical=old_critical
> end
> 
> Can I guarantee that other threads won't see my badly mangled Fixnum and
> String? Or is there some possiblity that another thread would continue
> executing and call (now badly broken) methods on Fixnum and String for a
> while before it hit a checkpoint that made it hit the lock? From your
> description it sounds like the latter is the case, in which case I need
> to be looking at sandboxing solutions or warn people very loudly that
> this part of the library is not thread safe and cannot be made thread
> safe. (AIUI, there's also no standard way of sandboxing right now.)
> 
>> But also note that critical= is gone in 1.9, so you should not use it
>> anyway. Use a Mutex whenever possible...it's quick, easy, and safe.
>> 
>> - Charlie
> 
> In Ruby 1.9 pesudocode this is only slightly different:
> 
> Thread.exclusive do
>   [Fixnum,String].each{|klass| override_methods_on klass}
>   result=builderblock.call
>   [Fixnum,String].each{|klass| restore_methods_on klass}
> end
> 
> (The methods being overridden in this case are pretty much any useful
> binary operator on Fixnum and String, so this is pretty drastic, not to
> mention that one of those operators is != which people have been
> gripeing about a lot on ruby-core.)
> 
> --Ken

Oh, shoot. I just realized I'd have the same problem if code passed to 
the s-expression builder called user-defined custom methods (which is 
actually a desired behavior) to use their results. Those methods would be 
broken inside by the wretching monkey patching going on. I guess it's 
probably best to abandon the idea of the s-expression builder completely, 
or do it with a string, an explicit binding, and ripper.

--Ken

-- 
Chanoch (Ken) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/