[Ironruby-core] Lock during module initialization

Shri Borde Shri.Borde at microsoft.com
Tue Dec 16 14:36:28 EST 2008


Will add the lock and the TODO.

Btw, the bug I was running into was that "threadObject.inspect" was incorrectly binding to KernelOps.Inspect rather than ThreadOps.Inspect when executed on a second thread. The first thread was in the middle of calling EnsureInitialized on the Thread class.

Thanks,
Shri

From: Tomas Matousek
Sent: Tuesday, December 16, 2008 7:59 AM
To: Shri Borde
Subject: RE: Lock during module initialization

This seems to be a good temporary workaround and it might be close to the right long term solution (could you add a TODO comment next to the lock statement?). There are no cycles in inheritance hierarchy (a module inclusion cannot be cyclic) and any time an uninitialized module is accessed we need to initialize only its ancestors.  (Actually, the _mixins array should contain all mixins serialized into a list - i.e. all mixins included into the mixins in the array are contained in the array as well. That implies we might not need to call the virtual EnsureInitialized method on the _mixins's elements. There are more such improvements to be made in module initialization and they should lead to better performance and thread-safety as well.

There has been a discussion on Ruby list recently on how 'require' should work in a multi-threaded program. The conclusion seems to be similar to the Python's approach (a global mutex for require). 'require' is thread-unsafe in today's MRI. In general, MRI's behavior is mostly undefined in multi-threaded environment today.

(BTW: The built-ins initialization we are doing is a little bit more complicated than in MRI since we are postponing it until it is really needed. In MRI all built-ins are initialized during startup. We initialize them as they are accessed.)

Tomas

From: Shri Borde
Sent: Monday, December 15, 2008 11:20 PM
To: Tomas Matousek
Subject: Lock during module initialization

IronRuby code was misbehaving and calling an incorrect method in the presence of multiple threads. This was because RubyModule.EnsureInitialized just returns if _state is, for example, State.Initializing. I add the lock shown below which fixes the problem.

        internal virtual void EnsureInitialized() {
            lock(this) {
                if (_state == State.Uninitialized) {
                    for (int i = 0; i < _mixins.Length; i++) {
                        _mixins[i].EnsureInitialized();
                    }

                    if (_state == State.Uninitialized) {
                        InitializeMembers();
                    }
                }
            }
        }

This probably opens up the possibility of deadlocks if there are mutually-dependent modules or some such complicated scheme. Is the lock good enough for now since it fixes wrong behavior which is hard to track down? A deadlock will be easier to debug.

What is the long term story here? Python allows module importing on only one thread at a time. The CLR maintains a list of types being initialized and knows to break cycles of mutually dependent cctors. What does MRI do? I don't think green threads make the problem any simpler. What does JRuby do?

Thanks,
Shri

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/ironruby-core/attachments/20081216/3e8b7737/attachment.html>


More information about the Ironruby-core mailing list