Hi,

today I read again source code for Trac's ComponentManager while debugging an issue. In the process I found that the code is prone to race-conditions:
def maybe_init(self, compmgr, init=init, cls=new_class):
    if cls not in compmgr.components:
        compmgr.components[cls] = self
        if init:
            try:
                init(self)
            except:
                del compmgr.components[cls]
                raise
    …

So is is a small time window where the process-wide dict contains instances which have not been initialized. That caused some pretty weird errors for us.

Obviously the correct solution is to add a lock before accessing the compmgr.components.

However there is also a version which does not need any locks:
def maybe_init(self, compmgr, init=init, cls=new_class):
    if cls not in compmgr.components:
        if init:
            init(self)
        compmgr.components[cls] = self
    …

I think the above version should work just as well as the current one while preventing half-initialized instances in the cache, provided that some basic assumptions are met:
 - "compmgr.components[cls] = self" is atomic
 - calling a constructor twice in the worst case is not a problem
 - two components do not instantiate each others within their __init__
   methods (currently the other gets a half-initialized version, the
   latter version will cause an endless loop as two normal Python
   objects would)

Comments?
fs

--
You received this message because you are subscribed to the Google Groups "Trac 
Development" group.
To post to this group, send email to trac-...@googlegroups.com.
To unsubscribe from this group, send email to 
trac-dev+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/trac-dev?hl=en.

Reply via email to