Skip to content
Snippets Groups Projects
  • Nat Goodspeed's avatar
    b22f89c9
    DRTVWR-494: Improve thread safety of LLSingleton machinery. · b22f89c9
    Nat Goodspeed authored
    Remove warnings about LLSingleton not being thread-safe because, at this point,
    we have devoted considerable effort to trying to make it thread-safe.
    
    Add LLSingleton<T>::Locker, a nested class which both provides a function-
    static mutex and a scoped lock that uses it. Instantiating Locker, which has a
    nullary constructor, replaces the somewhat cumbersome idiom of declaring a
    std::unique_lock<std::recursive_mutex> lk(getMutex);
    
    This eliminates (or rather, absorbs) the typedefs and getMutex() method from
    LLParamSingleton. Replace explicit std::unique_lock declarations in
    LLParamSingleton methods with Locker declarations.
    
    Remove LLSingleton<T>::SingletonInitializer nested struct. Instead of
    getInstance() relying on function-static initialization to protect (only)
    constructSingleton() calls, explicitly use a Locker instance to cover its
    whole scope, and make the UNINITIALIZED case call constructSingleton().
    Rearrange cases so that after constructSingleton(), control falls through to
    the CONSTRUCTED case and the finishInitializing() call.
    
    Use a Locker instance in other public-facing methods too: instanceExists(),
    wasDeleted(), ~LLSingleton(). Make destructor protected so it can only be called
    via deleteSingleton() (but must be accessible to subclasses for overrides).
    
    Remove LLSingletonBase::get_master() and get_initializing(), which permitted
    directly manipulating the master list and the initializing stack without any
    locking mechanism. Replace with get_initializing_size().
    
    Similarly, replace LLSingleton_manage_master::get_initializing() with
    get_initializing_size(). Use in constructSingleton() in place of
    get_initializing().size().
    
    Remove LLSingletonBase::capture_dependency()'s list_t parameter, which
    accepted the list returned by get_initializing(). Encapsulate that retrieval
    within the scope of the new lock in capture_dependency().
    
    Add LLSingleton_manage_master::capture_dependency(LLSingletonBase*, EInitState)
    to forward (or not) a call to LLSingletonBase::capture_dependency(). Nullary
    LLSingleton<T>::capture_dependency() calls new LLSingleton_manage_master method.
    
    Equip LLSingletonBase::MasterList with a mutex of its own, separate from the
    one donated by the LLSingleton machinery, to serialize use of MasterList data
    members. Introduce MasterList::Lock nested class to lock the MasterList mutex
    while providing a reference to the MasterList instance. Introduce subclasses
    LockedMaster, which provides a reference to the actual mMaster master list
    while holding the MasterList lock; and LockedInitializing, which does the same
    for the initializing list. Make mMaster and get_initializing_() private so
    that consuming code can *only* access those lists via LockedInitializing and
    LockedMaster.
    
    Make MasterList::cleanup_initializing_() private, with a LockedInitializing
    public forwarding method. This avoids another call to MasterList::instance(),
    and also mandates that the lock is currently held during every call.
    
    Similarly, move LLSingletonBase::log_initializing() to a LockedInitializing
    log() method.
    (transplanted from dca0f16266c7bddedb51ae7d7dca468ba87060d5)
    b22f89c9
    History
    DRTVWR-494: Improve thread safety of LLSingleton machinery.
    Nat Goodspeed authored
    Remove warnings about LLSingleton not being thread-safe because, at this point,
    we have devoted considerable effort to trying to make it thread-safe.
    
    Add LLSingleton<T>::Locker, a nested class which both provides a function-
    static mutex and a scoped lock that uses it. Instantiating Locker, which has a
    nullary constructor, replaces the somewhat cumbersome idiom of declaring a
    std::unique_lock<std::recursive_mutex> lk(getMutex);
    
    This eliminates (or rather, absorbs) the typedefs and getMutex() method from
    LLParamSingleton. Replace explicit std::unique_lock declarations in
    LLParamSingleton methods with Locker declarations.
    
    Remove LLSingleton<T>::SingletonInitializer nested struct. Instead of
    getInstance() relying on function-static initialization to protect (only)
    constructSingleton() calls, explicitly use a Locker instance to cover its
    whole scope, and make the UNINITIALIZED case call constructSingleton().
    Rearrange cases so that after constructSingleton(), control falls through to
    the CONSTRUCTED case and the finishInitializing() call.
    
    Use a Locker instance in other public-facing methods too: instanceExists(),
    wasDeleted(), ~LLSingleton(). Make destructor protected so it can only be called
    via deleteSingleton() (but must be accessible to subclasses for overrides).
    
    Remove LLSingletonBase::get_master() and get_initializing(), which permitted
    directly manipulating the master list and the initializing stack without any
    locking mechanism. Replace with get_initializing_size().
    
    Similarly, replace LLSingleton_manage_master::get_initializing() with
    get_initializing_size(). Use in constructSingleton() in place of
    get_initializing().size().
    
    Remove LLSingletonBase::capture_dependency()'s list_t parameter, which
    accepted the list returned by get_initializing(). Encapsulate that retrieval
    within the scope of the new lock in capture_dependency().
    
    Add LLSingleton_manage_master::capture_dependency(LLSingletonBase*, EInitState)
    to forward (or not) a call to LLSingletonBase::capture_dependency(). Nullary
    LLSingleton<T>::capture_dependency() calls new LLSingleton_manage_master method.
    
    Equip LLSingletonBase::MasterList with a mutex of its own, separate from the
    one donated by the LLSingleton machinery, to serialize use of MasterList data
    members. Introduce MasterList::Lock nested class to lock the MasterList mutex
    while providing a reference to the MasterList instance. Introduce subclasses
    LockedMaster, which provides a reference to the actual mMaster master list
    while holding the MasterList lock; and LockedInitializing, which does the same
    for the initializing list. Make mMaster and get_initializing_() private so
    that consuming code can *only* access those lists via LockedInitializing and
    LockedMaster.
    
    Make MasterList::cleanup_initializing_() private, with a LockedInitializing
    public forwarding method. This avoids another call to MasterList::instance(),
    and also mandates that the lock is currently held during every call.
    
    Similarly, move LLSingletonBase::log_initializing() to a LockedInitializing
    log() method.
    (transplanted from dca0f16266c7bddedb51ae7d7dca468ba87060d5)
Code owners
Assign users and groups as approvers for specific file changes. Learn more.