VirtualBox

Changeset 30765 in vbox


Ignore:
Timestamp:
Jul 9, 2010 2:12:58 PM (15 years ago)
Author:
vboxsync
Message:

Main: events stability improvment

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/EventImpl.cpp

    r30739 r30765  
    6363#include <VBox/com/array.h>
    6464
     65class ListenerRecord;
     66
    6567struct VBoxEvent::Data
    6668{
     
    350352static const int NumEvents  = LastEvent - FirstEvent;
    351353
    352 class ListenerRecord;
    353 typedef std::list<ListenerRecord*> EventMap[NumEvents];
     354/**
     355 * Class replacing std::list and able to provide required stability
     356 * during iteration. It's acheived by delaying structural modifications
     357 * to the list till the moment particular element is no longer used by
     358 * current iterators.
     359 */
     360class EventMapRecord
     361{
     362private:
     363    /**
     364     * We have to be double linked, as structural modifications in list are delayed
     365     * till element removed, so we have to know our previous one to update its next
     366     */
     367    EventMapRecord* mNext;
     368    EventMapRecord* mPrev;
     369    ListenerRecord* mRef; /* must be weak reference */
     370    int32_t         mRefCnt;
     371    bool            mAlive;
     372public:
     373    EventMapRecord(ListenerRecord* aRef)
     374        :
     375        mNext(0),
     376        mPrev(0),
     377        mRef(aRef),
     378        mRefCnt(1),
     379        mAlive(true)
     380    {}
     381
     382    EventMapRecord(EventMapRecord& aOther)
     383    {
     384        mNext = aOther.mNext;
     385        mPrev = aOther.mPrev;
     386        mRef = aOther.mRef;
     387        mRefCnt = aOther.mRefCnt;
     388        mAlive = aOther.mAlive;
     389    }
     390
     391    ~EventMapRecord()
     392    {
     393        if (mNext)
     394            mNext->mPrev = mPrev;
     395        if (mPrev)
     396            mPrev->mNext = mNext;
     397    }
     398
     399    void addRef()
     400    {
     401        ASMAtomicIncS32(&mRefCnt);
     402    }
     403
     404    void release()
     405    {
     406        if (ASMAtomicDecS32(&mRefCnt) <= 0) delete this;
     407    }
     408
     409    // Called when an element is no longer needed
     410    void kill()
     411    {
     412        mAlive = false;
     413        release();
     414    }
     415
     416    ListenerRecord* ref()
     417    {
     418        return mAlive ? mRef : 0;
     419    }
     420
     421    friend class EventMapList;
     422};
     423
     424
     425class EventMapList
     426{
     427    EventMapRecord* mHead;
     428    uint32_t        mSize;
     429public:
     430    EventMapList()
     431        :
     432        mHead(0),
     433        mSize(0)
     434    {}
     435    ~EventMapList()
     436    {
     437        EventMapRecord* aCur = mHead;
     438        while (aCur)
     439        {
     440            EventMapRecord* aNext = aCur->mNext;
     441            aCur->release();
     442            aCur = aNext;
     443        }
     444    }
     445
     446    /*
     447     * Elements have to be added to the front of the list, to make sure
     448     * that iterators doesn't see newly added listeners, and iteration
     449     * will always complete.
     450     */
     451    void add(ListenerRecord* aRec)
     452    {
     453        EventMapRecord* aNew = new EventMapRecord(aRec);
     454        aNew->mNext = mHead;
     455        if (mHead)
     456            mHead->mPrev = aNew;
     457        mHead = aNew;
     458        mSize++;
     459    }
     460
     461    /*
     462     * Mark element as removed, actual removal could be delayed until
     463     * all consumers release it too. This helps to keep list stable
     464     * enough for iterators to allow long and probably intrusive callbacks.
     465     */
     466    void remove(ListenerRecord* aRec)
     467    {
     468        EventMapRecord* aCur = mHead;
     469        while (aCur)
     470        {
     471            EventMapRecord* aNext = aCur->mNext;
     472            if (aCur->ref() == aRec)
     473            {
     474                if (aCur == mHead)
     475                    mHead = aNext;
     476                aCur->kill();
     477                mSize--;
     478                // break?
     479            }
     480            aCur = aNext;
     481        }
     482    }
     483
     484    uint32_t size() const
     485    {
     486        return mSize;
     487    }
     488
     489    struct iterator
     490    {
     491      EventMapRecord* mCur;
     492
     493      iterator()
     494      : mCur(0)
     495      {}
     496
     497      explicit
     498      iterator(EventMapRecord* aCur)
     499      : mCur(aCur)
     500      {
     501          // Prevent element removal, till we're at it
     502          if (mCur)
     503              mCur->addRef();
     504      }
     505
     506      ~iterator()
     507      {
     508          if (mCur)
     509              mCur->release();
     510      }
     511
     512      ListenerRecord*
     513      operator*() const
     514      {
     515          return mCur->ref();
     516      }
     517
     518      EventMapList::iterator&
     519      operator++()
     520      {
     521          EventMapRecord* aPrev = mCur;
     522          do {
     523              mCur = mCur->mNext;
     524          } while (mCur && !mCur->mAlive);
     525
     526          // now we can safely release previous element
     527          aPrev->release();
     528
     529          // And grab the new current
     530          if (mCur)
     531              mCur->addRef();
     532
     533          return *this;
     534      }
     535
     536      bool
     537      operator==(const EventMapList::iterator& aOther) const
     538      {
     539          return mCur == aOther.mCur;
     540      }
     541
     542      bool
     543      operator!=(const EventMapList::iterator& aOther) const
     544      {
     545          return mCur != aOther.mCur;
     546      }
     547    };
     548
     549    iterator begin()
     550    {
     551        return iterator(mHead);
     552    }
     553
     554    iterator end()
     555    {
     556        return iterator(0);
     557    }
     558};
     559
     560typedef EventMapList EventMap[NumEvents];
    354561typedef std::map<IEvent*, int32_t> PendingEventsMap;
    355562typedef std::deque<ComPtr<IEvent> > PassiveQueue;
     
    394601};
    395602
    396 /* Handy class with semantics close to ComPtr, but for ListenerRecord */
    397 class ListenerRecordHolder
     603/* Handy class with semantics close to ComPtr, but for list records */
     604template<typename Held>
     605class RecordHolder
    398606{
    399607public:
    400     ListenerRecordHolder(ListenerRecord* lr)
     608    RecordHolder(Held* lr)
    401609    :
    402610    held(lr)
     
    404612        addref();
    405613    }
    406     ListenerRecordHolder(const ListenerRecordHolder& that)
     614    RecordHolder(const RecordHolder& that)
    407615    :
    408616    held(that.held)
     
    410618        addref();
    411619    }
    412     ListenerRecordHolder()
     620    RecordHolder()
    413621    :
    414622    held(0)
    415623    {
    416624    }
    417     ~ListenerRecordHolder()
     625    ~RecordHolder()
    418626    {
    419627        release();
    420628    }
    421629
    422     ListenerRecord* obj()
     630    Held* obj()
    423631    {
    424632        return held;
    425633    }
    426634
    427     ListenerRecordHolder &operator=(const ListenerRecordHolder &that)
     635    RecordHolder &operator=(const RecordHolder &that)
    428636    {
    429637        safe_assign(that.held);
     
    431639    }
    432640private:
    433     ListenerRecord* held;
     641    Held* held;
    434642
    435643    void addref()
     
    443651            held->release();
    444652    }
    445     void safe_assign (ListenerRecord *that_p)
     653    void safe_assign (Held *that_p)
    446654    {
    447655        if (that_p)
     
    452660};
    453661
    454 typedef std::map<IEventListener*, ListenerRecordHolder>  Listeners;
     662typedef std::map<IEventListener*, RecordHolder<ListenerRecord> >  Listeners;
    455663
    456664struct EventSource::Data
     
    508716            if (implies(interested, candidate))
    509717            {
    510                 (*aEvMap)[j - FirstEvent].push_back(this);
     718                (*aEvMap)[j - FirstEvent].add(this);
    511719            }
    512720        }
     
    605813    AssertMsg(!mActive, ("must be passive\n"));
    606814
     815    // retain listener record
     816    RecordHolder<ListenerRecord> holder(this);
     817
    607818    ::RTCritSectEnter(&mcsQLock);
    608     if (mQueue.empty())
    609     {
    610         // retain listener record
    611         ListenerRecordHolder holder(this);
     819    if (mQueue.empty())    {
    612820        ::RTCritSectLeave(&mcsQLock);
    613821        // Speed up common case
     
    708916
    709917        com::SafeArray<VBoxEventType_T> interested(ComSafeArrayInArg (aInterested));
    710         ListenerRecordHolder lrh(new ListenerRecord(aListener, interested, aActive, this));
     918        RecordHolder<ListenerRecord> lrh(new ListenerRecord(aListener, interested, aActive, this));
    711919        m->mListeners.insert(Listeners::value_type(aListener, lrh));
    712920    }
     
    776984        AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
    777985
    778         std::list<ListenerRecord*>& listeners = m->mEvMap[(int)evType-FirstEvent];
     986        EventMapList& listeners = m->mEvMap[(int)evType-FirstEvent];
    779987
    780988        /* Anyone interested in this event? */
     
    7951003            pit = m->mPendingMap.find(aEvent);
    7961004        }
    797         for(std::list<ListenerRecord*>::const_iterator it = listeners.begin();
     1005        for(EventMapList::iterator it = listeners.begin();
    7981006            it != listeners.end(); ++it)
    7991007        {
    8001008            HRESULT cbRc;
    8011009            // keep listener record reference, in case someone will remove it while in callback
    802             ListenerRecordHolder record(*it);
     1010            RecordHolder<ListenerRecord> record(*it);
    8031011
    8041012            /**
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