From: Ken Bloom Date: 2009-01-13T02:09:35+09:00 Subject: Re: Binding.of_caller examples don't work. 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 -- Chanoch (Ken) Bloom. PhD candidate. Linguistic Cognition Laboratory. Department of Computer Science. Illinois Institute of Technology. http://www.iit.edu/~kbloom1/