VirtualBox

Changeset 13887 in vbox for trunk/src/VBox/Main/include


Ignore:
Timestamp:
Nov 5, 2008 6:43:42 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
38887
Message:

Main: Fixed: 1) VirtualBoxBaseWithChildrenNEXT::uninitDependentChildren() chould try to uninitialize already deleted children because they were not properly removed from the map (r38669 regression). Also a rare deadlock was possible in this method if a weak child happened to be uninitializing itself on another thread at the same time (a really old regression).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/VirtualBoxBase.h

    r13837 r13887  
    19521952 * it gets uninitialized, it must call uninit() methods of individual children
    19531953 * manually to disconnect them; a failure to do so will cause crashes in these
    1954  * methods when chidren get destroyed.
     1954 * methods when chidren get destroyed. The same applies to children not calling
     1955 * #removeDependentChild() when getting destrooyed.
    19551956 *
    19561957 * Note that children added by #addDependentChild() are <b>weakly</b> referenced
     
    19651966 * this class so be aware of the need to preserve the {parent, child} lock order
    19661967 * when calling these methods.
     1968 *
     1969 * Read individual method descriptions to get further information.
    19671970 *
    19681971 * @todo This is a VirtualBoxBaseWithChildren equivalent that uses the
     
    20342037     *
    20352038     * Usually gets called from the child's uninit() method.
     2039     *
     2040     * Keep in mind that the called (parent) object may be no longer available
     2041     * (i.e. may be deleted deleted) after this method returns, so you must not
     2042     * call any other parent's methods after that!
    20362043     *
    20372044     * @note Locks #childrenLock() for writing.
     
    22592266 * Also, as opposed to VirtualBoxBaseWithChildren, children added by
    22602267 * #addDependentChild() are <b>strongly</b> referenced, so that they cannot be
    2261  * deleted until #removeDependentChild() is called on them.
    2262  *
    2263  * See individual method descriptions for more information.
     2268 * deleted (even by a third party) until #removeDependentChild() is called on
     2269 * them. This also means that a failure to call #removeDependentChild() and
     2270 * #uninitDependentChildren() at appropriate times as described in
     2271 * VirtualBoxBaseWithChildrenNEXT may cause stuck references that won't be able
     2272 * uninitialize themselves.
     2273 *
     2274 * See individual method descriptions for further information.
    22642275 *
    22652276 * @param C Type of child objects (must inherit VirtualBoxBase AND implement
     
    23232334                          autoCaller.state() == Limited);
    23242335
    2325         AutoWriteLock alock (childrenLock());
     2336        AutoWriteLock chLock (childrenLock());
    23262337        mDependentChildren.push_back (aChild);
    23272338    }
     
    23322343     * Usually gets called from the child's uninit() method.
    23332344     *
    2334      * Note that once this method returns, the argument (@a aChild) is not
    2335      * guaranteed to be valid any more, so the caller of this method must not
    2336      * call its other methods.
     2345     * Keep in mind that the called (parent) object may be no longer available
     2346     * (i.e. may be deleted deleted) after this method returns, so you must not
     2347     * call any other parent's methods after that!
    23372348     *
    23382349     * @note @a aChild (unless it is in InUninit state) must be protected by
     
    23582369        AutoCaller autoCaller (this);
    23592370
    2360         /* return shortly; uninitDependentChildren() will do the job */
     2371        /* sanity */
     2372        AssertReturnVoid (autoCaller.state() == InUninit ||
     2373                          autoCaller.state() == InInit ||
     2374                          autoCaller.state() == Ready ||
     2375                          autoCaller.state() == Limited);
     2376
     2377        /* return shortly; we are strongly referenced so the object won't get
     2378         * deleted if it calls init() before uninitDependentChildren() does
     2379         * and therefore the list will still contain a valid reference that will
     2380         * be correctly processed by uninitDependentChildren() anyway */
    23612381        if (autoCaller.state() == InUninit)
    23622382            return;
    23632383
    2364         AutoWriteLock alock (childrenLock());
     2384        AutoWriteLock chLock (childrenLock());
    23652385        mDependentChildren.remove (aChild);
    23662386    }
     
    24002420         * we want to avoid a possible deadlock where we could get stuck in
    24012421         * child->uninit() blocked by AutoUninitSpan waiting for the number of
    2402          * child's callers to drop to zero, while some caller is stuck in our
    2403          * removeDependentChild() method waiting for the write lock.
     2422         * child's callers to drop to zero (or for another AutoUninitSpan to
     2423         * finish), while some other thread is stuck in our
     2424         * removeDependentChild() method called for that child and waiting for
     2425         * the childrenLock()'s write lock.
    24042426         *
    24052427         * The only safe place to not lock and keep accessing our data members
     
    24082430         * use the AutoCaller class of course). InUinint is also used as a flag
    24092431         * by removeDependentChild() that prevents touching mDependentChildren
    2410          * from outside. Therefore, we assert.
     2432         * from outside. Therefore, we assert. Note that InInit is also fine
     2433         * since no any object may access us by that time.
    24112434         */
    2412         AssertReturnVoid (autoCaller.state() == InUninit);
     2435        AssertReturnVoid (autoCaller.state() == InUninit ||
     2436                          autoCaller.state() == InInit);
    24132437
    24142438        if (mDependentChildren.size())
     
    24452469    void removeDependentChildren()
    24462470    {
    2447         AutoWriteLock alock (childrenLock());
     2471        AutoWriteLock chLock (childrenLock());
    24482472        mDependentChildren.clear();
    24492473    }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette