Skip to content
Snippets Groups Projects
  • Nat Goodspeed's avatar
    310db14b
    DRTVWR-493: Improve exception safety of LLSingleton initialization. · 310db14b
    Nat Goodspeed authored
    Add try/catch clauses to constructSingleton() (to catch exceptions in the
    subclass constructor) and finishInitializing() (to catch exceptions in the
    subclass initSingleton() method). Each of these catch clauses rethrows the
    exception -- they're for cleanup, not for ultimate handling.
    
    Introduce LLSingletonBase::reset_initializing(list_t::size_t). The idea is
    that since we can't know whether the exception happened before or after the
    push_initializing() call in LLSingletonBase's constructor, we can't just pop
    the stack. Instead, constructSingleton() captures the stack size before
    attempting to construct the new LLSingleton subclass. On exception, it calls
    reset_initializing() to restore the stack to that size.
    
    Naturally that requires a corresponding LLSingleton_manage_master method,
    whose MasterList specialization is a no-op.
    
    finishInitializing()'s exception handling is a bit simpler because it has a
    constructed LLSingleton subclass instance in hand, therefore
    push_initializing() has definitely been called, therefore it can call
    pop_initializing().
    
    Break out new static capture_dependency() method from finishInitializing()
    because, in the previous LLSingleton::getInstance() implementation, the logic
    now wrapped in capture_dependency() was reached even in the INITIALIZED case.
    TODO: Add a new EInitState to differentiate "have been constructed, now
    calling initSingleton()" from "fully initialized, normal case" -- in the
    latter control path we should not be calling capture_dependency().
    
    The LLSingleton_manage_master<LLSingletonBase::MasterList> specialization's
    get_initializing() function (which called get_initializing_from()) was
    potentially dangerous. get_initializing() is called by push_initializing(),
    which (in the general case) is called by LLSingletonBase's constructor. If
    somehow the MasterList's LLSingletonBase constructor ended up calling
    get_initializing(), it would have called get_initializing_from(), passing an
    LLSingletonBase which had not yet been constructed into the MasterList. In
    particular, its mInitializing map would not yet have been initialized at all.
    
    Since the MasterList must not, by design, depend on any other LLSingletons,
    LLSingleton_manage_master<LLSingletonBase::MasterList>::get_initializing()
    need not return a list from the official mInitializing map anyway. It can, and
    should, and now does, return a static dummy list. That obviates
    get_initializing_from(), which is removed.
    
    That in turn means we no longer need to pass get_initializing() an
    LLSingletonBase*. Remove that parameter.
    310db14b
    History
    DRTVWR-493: Improve exception safety of LLSingleton initialization.
    Nat Goodspeed authored
    Add try/catch clauses to constructSingleton() (to catch exceptions in the
    subclass constructor) and finishInitializing() (to catch exceptions in the
    subclass initSingleton() method). Each of these catch clauses rethrows the
    exception -- they're for cleanup, not for ultimate handling.
    
    Introduce LLSingletonBase::reset_initializing(list_t::size_t). The idea is
    that since we can't know whether the exception happened before or after the
    push_initializing() call in LLSingletonBase's constructor, we can't just pop
    the stack. Instead, constructSingleton() captures the stack size before
    attempting to construct the new LLSingleton subclass. On exception, it calls
    reset_initializing() to restore the stack to that size.
    
    Naturally that requires a corresponding LLSingleton_manage_master method,
    whose MasterList specialization is a no-op.
    
    finishInitializing()'s exception handling is a bit simpler because it has a
    constructed LLSingleton subclass instance in hand, therefore
    push_initializing() has definitely been called, therefore it can call
    pop_initializing().
    
    Break out new static capture_dependency() method from finishInitializing()
    because, in the previous LLSingleton::getInstance() implementation, the logic
    now wrapped in capture_dependency() was reached even in the INITIALIZED case.
    TODO: Add a new EInitState to differentiate "have been constructed, now
    calling initSingleton()" from "fully initialized, normal case" -- in the
    latter control path we should not be calling capture_dependency().
    
    The LLSingleton_manage_master<LLSingletonBase::MasterList> specialization's
    get_initializing() function (which called get_initializing_from()) was
    potentially dangerous. get_initializing() is called by push_initializing(),
    which (in the general case) is called by LLSingletonBase's constructor. If
    somehow the MasterList's LLSingletonBase constructor ended up calling
    get_initializing(), it would have called get_initializing_from(), passing an
    LLSingletonBase which had not yet been constructed into the MasterList. In
    particular, its mInitializing map would not yet have been initialized at all.
    
    Since the MasterList must not, by design, depend on any other LLSingletons,
    LLSingleton_manage_master<LLSingletonBase::MasterList>::get_initializing()
    need not return a list from the official mInitializing map anyway. It can, and
    should, and now does, return a static dummy list. That obviates
    get_initializing_from(), which is removed.
    
    That in turn means we no longer need to pass get_initializing() an
    LLSingletonBase*. Remove that parameter.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.