VirtualBox

vbox的更動 61774 路徑 trunk/src/VBox/Main


忽略:
時間撮記:
2016-6-20 下午09:45:58 (8 年 以前)
作者:
vboxsync
訊息:

ListenerRecord::enqueue: Don't try signal semaphore or even queue the event if we've been shut down already. Hope the latter is a good idea...
Attempted to deal with event sem lifetime races between shutdown and enqueue, and between shutdown and wait.

檔案:
修改 1 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Main/src-all/EventImpl.cpp

    r60765 r61774  
    598598private:
    599599    ComPtr<IEventListener>        mListener;
    600     BOOL                          mActive;
     600    BOOL const                    mActive;
    601601    EventSource                  *mOwner;
    602602
    603603    RTSEMEVENT                    mQEvent;
    604     int32_t volatile              mWaitCnt;
     604    int32_t volatile              mQEventBusyCnt;
    605605    RTCRITSECT                    mcsQLock;
    606606    PassiveQueue                  mQueue;
     
    749749                               BOOL aActive,
    750750                               EventSource *aOwner) :
    751     mActive(aActive), mOwner(aOwner), mWaitCnt(0), mRefCnt(0)
     751    mActive(aActive), mOwner(aOwner), mQEventBusyCnt(0), mRefCnt(0)
    752752{
    753753    mListener = aListener;
     
    859859    uint64_t sinceRead = RTTimeMilliTS() - mLastRead;
    860860    size_t queueSize = mQueue.size();
    861     if ((queueSize > 1000) || ((queueSize > 500) && (sinceRead > 60 * 1000)))
     861    if (queueSize > 1000 || (queueSize > 500 && sinceRead > 60 * 1000))
    862862    {
    863863        ::RTCritSectLeave(&mcsQLock);
     
    866866
    867867
     868    RTSEMEVENT hEvt = mQEvent;
    868869    if (queueSize != 0 && mQueue.back() == aEvent)
    869870        /* if same event is being pushed multiple times - it's reusable event and
    870871           we don't really need multiple instances of it in the queue */
    871         (void)aEvent;
    872     else
     872        hEvt = NIL_RTSEMEVENT;
     873    else if (hEvt != NIL_RTSEMEVENT) /* don't bother queuing after shutdown */
     874    {
    873875        mQueue.push_back(aEvent);
     876        ASMAtomicIncS32(&mQEventBusyCnt);
     877    }
    874878
    875879    ::RTCritSectLeave(&mcsQLock);
    876880
    877     // notify waiters
    878     ::RTSemEventSignal(mQEvent);
     881    // notify waiters unless we've been shut down.
     882    if (hEvt != NIL_RTSEMEVENT)
     883    {
     884        ::RTSemEventSignal(hEvt);
     885        ASMAtomicDecS32(&mQEventBusyCnt);
     886    }
    879887
    880888    return S_OK;
     
    895903    mLastRead = RTTimeMilliTS();
    896904
     905    /*
     906     * If waiting both desired and necessary, then try grab the event
     907     * semaphore and mark it busy.  If it's NIL we've been shut down already.
     908     */
     909    if (aTimeout != 0 && mQueue.empty())
     910    {
     911        RTSEMEVENT hEvt = mQEvent;
     912        if (hEvt != NIL_RTSEMEVENT)
     913        {
     914            ASMAtomicIncS32(&mQEventBusyCnt);
     915            ::RTCritSectLeave(&mcsQLock);
     916
     917            // release lock while waiting, listener will not go away due to above holder
     918            aAlock.release();
     919
     920            ::RTSemEventWait(hEvt, aTimeout);
     921            ASMAtomicDecS32(&mQEventBusyCnt);
     922
     923            // reacquire lock
     924            aAlock.acquire();
     925            ::RTCritSectEnter(&mcsQLock);
     926        }
     927    }
     928
    897929    if (mQueue.empty())
    898     {
    899         ::RTCritSectLeave(&mcsQLock);
    900         // Speed up common case
    901         if (aTimeout == 0)
    902         {
    903             *aEvent = NULL;
    904             return S_OK;
    905         }
    906         // release lock while waiting, listener will not go away due to above holder
    907         aAlock.release();
    908 
    909         // In order to safely shutdown, count all waiting threads here.
    910         ASMAtomicIncS32(&mWaitCnt);
    911         ::RTSemEventWait(mQEvent, aTimeout);
    912         ASMAtomicDecS32(&mWaitCnt);
    913 
    914         // reacquire lock
    915         aAlock.acquire();
    916         ::RTCritSectEnter(&mcsQLock);
    917     }
    918     if (mQueue.empty())
    919     {
    920930        *aEvent = NULL;
    921     }
    922931    else
    923932    {
     
    925934        mQueue.pop_front();
    926935    }
     936
    927937    ::RTCritSectLeave(&mcsQLock);
    928938    return S_OK;
     
    945955    if (mQEvent != NIL_RTSEMEVENT)
    946956    {
    947         RTSEMEVENT tmp = mQEvent;
     957        /* Grab the event semaphore.  Must do this while owning the CS or we'll
     958           be racing user wanting to use the handle. */
     959        ::RTCritSectEnter(&mcsQLock);
     960        RTSEMEVENT hEvt = mQEvent;
    948961        mQEvent = NIL_RTSEMEVENT;
    949 
    950         /* On Darwin it is known that RTSemEventDestroy() returns 0 while
    951          * corresponding thread remains to be blocked after that. In order to prevent
    952          * undesireble freeze on shutdown, this workaround is used. */
    953         Log(("Wait for %d waiters to release.\n", ASMAtomicReadS32(&mWaitCnt)));
    954         while (ASMAtomicReadS32(&mWaitCnt) > 0)
    955         {
    956             ::RTSemEventSignal(tmp);
    957 
    958             /* Are we already done? */
    959             if (ASMAtomicReadS32(&mWaitCnt) == 0)
    960                 break;
    961 
    962             RTThreadSleep(10);
    963         }
    964         Log(("All waiters just released the lock.\n"));
    965 
    966         ::RTSemEventDestroy(tmp);
     962        ::RTCritSectLeave(&mcsQLock);
     963
     964        /*
     965         * Signal waiters and wait for them and any other signallers to stop using the sempahore.
     966         *
     967         * Note! RTSemEventDestroy does not necessarily guarantee that waiting threads are
     968         *       out of RTSemEventWait or even woken up when it returns.  Darwin is (or was?)
     969         *       an example of this, the result was undesirable freezes on shutdown.
     970         */
     971        int32_t cBusy = ASMAtomicReadS32(&mQEventBusyCnt);
     972        if (cBusy > 0)
     973        {
     974            Log(("Wait for %d waiters+signalers to release.\n", cBusy));
     975            while (cBusy-- > 0)
     976                ::RTSemEventSignal(hEvt);
     977
     978            for (uint32_t cLoops = 0;; cLoops++)
     979            {
     980                RTThreadSleep(RT_MIN(8, cLoops));
     981                if (ASMAtomicReadS32(&mQEventBusyCnt) <= 0)
     982                    break;
     983                ::RTSemEventSignal(hEvt); /* (Technically unnecessary, but just in case.) */
     984            }
     985            Log(("All waiters+signalers just released the lock.\n"));
     986        }
     987
     988        ::RTSemEventDestroy(hEvt);
    967989    }
    968990}
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

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