VirtualBox

Changeset 30331 in vbox for trunk


Ignore:
Timestamp:
Jun 21, 2010 1:43:55 PM (14 years ago)
Author:
vboxsync
Message:

Main: further event work

Location:
trunk/src/VBox/Main
Files:
3 edited

Legend:

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

    r30311 r30331  
    1616 */
    1717
     18#include <list>
     19#include <map>
     20#include <deque>
     21
    1822#include "EventImpl.h"
     23#include "AutoCaller.h"
     24#include "Logging.h"
     25
     26#include <iprt/semaphore.h>
     27#include <iprt/critsect.h>
     28#include <VBox/com/array.h>
    1929
    2030struct VBoxEvent::Data
    2131{
    2232    Data()
    23         : 
     33        :
    2434        mType(VBoxEventType_Invalid),
    25         mWaitable(FALSE)
     35        mWaitEvent(NIL_RTSEMEVENT),
     36        mWaitable(FALSE),
     37        mProcessed(FALSE)
    2638    {}
    27     VBoxEventType_T mType;
    28     BOOL            mWaitable;
     39    ComPtr<IEventSource>    mSource;
     40    VBoxEventType_T         mType;
     41    RTSEMEVENT              mWaitEvent;
     42    BOOL                    mWaitable;
     43    BOOL                    mProcessed;
    2944};
    3045
     
    4661    HRESULT rc = S_OK;
    4762
     63    m->mSource = aSource;
    4864    m->mType = aType;
    4965    m->mWaitable = aWaitable;
     66    m->mProcessed = !aWaitable;
     67
     68    do {
     69        if (aWaitable)
     70        {
     71            int vrc = ::RTSemEventCreate (&m->mWaitEvent);
     72
     73            if (RT_FAILURE(vrc))
     74            {
     75                AssertFailed ();
     76                rc = setError(E_FAIL,
     77                              tr("Internal error (%Rrc)"), vrc);
     78                break;
     79            }
     80        }
     81    } while (0);
    5082
    5183    return rc;
     
    5486void VBoxEvent::uninit()
    5587{
     88    m->mProcessed = TRUE;
    5689    m->mType = VBoxEventType_Invalid;
     90    m->mSource.setNull();
     91
     92    if (m->mWaitEvent != NIL_RTSEMEVENT)
     93    {
     94        ::RTSemEventDestroy(m->mWaitEvent);
     95    }
    5796}
    5897
    5998STDMETHODIMP VBoxEvent::COMGETTER(Type)(VBoxEventType_T *aType)
    6099{
     100    CheckComArgNotNull(aType);
     101
     102    AutoCaller autoCaller(this);
     103    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     104
    61105    // never  changes till event alive, no locking?
    62106    *aType = m->mType;
     
    66110STDMETHODIMP VBoxEvent::COMGETTER(Source)(IEventSource* *aSource)
    67111{
    68     return E_NOTIMPL;
     112    CheckComArgOutPointerValid(aSource);
     113
     114    AutoCaller autoCaller(this);
     115    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     116
     117    m->mSource.queryInterfaceTo(aSource);
     118    return S_OK;
    69119}
    70120
    71121STDMETHODIMP VBoxEvent::COMGETTER(Waitable)(BOOL *aWaitable)
    72122{
     123    CheckComArgNotNull(aWaitable);
     124
     125    AutoCaller autoCaller(this);
     126    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     127
    73128    // never  changes till event alive, no locking?
    74129    *aWaitable = m->mWaitable;
     
    79134STDMETHODIMP VBoxEvent::SetProcessed()
    80135{
    81     return E_NOTIMPL;
     136    AutoCaller autoCaller(this);
     137    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     138
     139    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     140
     141    if (m->mProcessed)
     142        return S_OK;
     143
     144    m->mProcessed = TRUE;
     145
     146    // notify waiters
     147    ::RTSemEventSignal(m->mWaitEvent);
     148
     149    return S_OK;
    82150}
    83151
    84152STDMETHODIMP VBoxEvent::WaitProcessed(LONG aTimeout, BOOL *aResult)
    85153{
    86     return E_NOTIMPL;
    87 }
    88 
     154    CheckComArgNotNull(aResult);
     155
     156    AutoCaller autoCaller(this);
     157    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     158
     159    {
     160        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     161
     162        if (m->mProcessed)
     163            return S_OK;
     164    }
     165
     166    int vrc = ::RTSemEventWait(m->mWaitEvent, aTimeout);
     167    AssertMsg(RT_SUCCESS(vrc) || vrc == VERR_TIMEOUT || vrc == VERR_INTERRUPTED,
     168              ("RTSemEventWait returned %Rrc\n", vrc));
     169
     170
     171    if (RT_SUCCESS(vrc))
     172    {
     173        AssertMsg(m->mProcessed,
     174                  ("mProcessed must be set here\n"));
     175        *aResult = m->mProcessed;
     176    }
     177    else
     178    {
     179        *aResult = FALSE;
     180    }
     181
     182    return S_OK;
     183}
     184
     185static const int FirstEvent = (int)VBoxEventType_LastWildcard + 1;
     186static const int LastEvent  = (int)VBoxEventType_Last;
     187static const int NumEvents  = LastEvent - FirstEvent;
     188
     189struct ListenerRecord;
     190typedef std::list<ListenerRecord*> EventMap[NumEvents];
     191typedef std::map<IEvent*, int32_t> PendingEventsMap;
     192typedef std::deque<ComPtr<IEvent> > PassiveQueue;
     193
     194struct ListenerRecord
     195{
     196    ComPtr<IEventListener>        mListener;
     197    BOOL                          mActive;
     198    EventSource*                  mOwner;
     199
     200    RTSEMEVENT                    mQEvent;
     201    RTCRITSECT                    mcsQLock;
     202    PassiveQueue                  mQueue;
     203
     204    ListenerRecord(IEventListener*                    aListener,
     205                   com::SafeArray<VBoxEventType_T>&   aInterested,
     206                   BOOL                               aActive,
     207                   EventSource*                       aOwner);
     208    ~ListenerRecord();
     209
     210    HRESULT process(IEvent* aEvent, BOOL aWaitable, PendingEventsMap::iterator& pit);
     211    HRESULT enqueue(IEvent* aEvent);
     212    HRESULT dequeue(IEvent* *aEvent, LONG aTimeout);
     213    HRESULT eventProcessed(IEvent * aEvent, PendingEventsMap::iterator& pit);
     214};
     215
     216typedef std::map<IEventListener*, ListenerRecord>  Listeners;
    89217
    90218struct EventSource::Data
    91219{
    92     Data()
    93         :
    94         mBogus(0)
    95     {}
    96     int32_t            mBogus;
     220    Data() {}
     221    Listeners                     mListeners;
     222    EventMap                      mEvMap;
     223    PendingEventsMap              mPendingMap;
    97224};
     225
     226static BOOL implies(VBoxEventType_T who, VBoxEventType_T what)
     227{
     228    switch (who)
     229    {
     230        case VBoxEventType_Any:
     231            return TRUE;
     232        case VBoxEventType_MachineEvent:
     233            return (what == VBoxEventType_OnMachineStateChange) || (what == VBoxEventType_OnMachineDataChange);
     234        case VBoxEventType_Invalid:
     235            return FALSE;
     236    }
     237    return who == what;
     238}
     239
     240ListenerRecord::ListenerRecord(IEventListener*                  aListener,
     241                               com::SafeArray<VBoxEventType_T>& aInterested,
     242                               BOOL                             aActive,
     243                               EventSource*                     aOwner)
     244    :
     245    mActive(aActive),
     246    mOwner(aOwner)
     247{
     248    mListener = aListener;
     249    EventMap* aEvMap = &aOwner->m->mEvMap;
     250
     251    for (size_t i = 0; i < aInterested.size(); ++i)
     252    {
     253        VBoxEventType_T interested = aInterested[i];
     254        for (int j = FirstEvent; j < LastEvent; j++)
     255        {
     256            VBoxEventType_T candidate = (VBoxEventType_T)j;
     257            if (implies(interested, candidate))
     258            {
     259                (*aEvMap)[j - FirstEvent].push_back(this);
     260            }
     261        }
     262    }
     263
     264    ::RTCritSectInitEx(&mcsQLock, 0, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL);
     265    ::RTSemEventCreate (&mQEvent);
     266}
     267
     268ListenerRecord::~ListenerRecord()
     269{
     270    /* Remove references to us from the event map */
     271    EventMap* aEvMap = &mOwner->m->mEvMap;
     272    for (int j = FirstEvent; j < LastEvent; j++)
     273    {
     274        (*aEvMap)[j - FirstEvent].remove(this);
     275    }
     276
     277    ::RTCritSectDelete(&mcsQLock);
     278    ::RTSemEventDestroy(mQEvent);
     279}
     280
     281HRESULT ListenerRecord::process(IEvent* aEvent, BOOL aWaitable, PendingEventsMap::iterator& pit)
     282{
     283    if (mActive)
     284    {
     285        HRESULT rc =  mListener->HandleEvent(aEvent);
     286        if (aWaitable)
     287            eventProcessed(aEvent, pit);
     288        return rc;
     289    }
     290    else
     291        return enqueue(aEvent);
     292}
     293
     294
     295HRESULT ListenerRecord::enqueue (IEvent* aEvent)
     296{
     297    AssertMsg(!mActive, ("must be passive\n"));
     298    ::RTCritSectEnter(&mcsQLock);
     299
     300    mQueue.push_back(aEvent);
     301    // notify waiters
     302    ::RTSemEventSignal(mQEvent);
     303
     304    ::RTCritSectLeave(&mcsQLock);
     305
     306    return S_OK;
     307}
     308
     309HRESULT ListenerRecord::dequeue (IEvent* *aEvent, LONG aTimeout)
     310{
     311    AssertMsg(!mActive, ("must be passive\n"));
     312
     313    ::RTCritSectEnter(&mcsQLock);
     314    if (mQueue.empty())
     315    {
     316        ::RTCritSectLeave(&mcsQLock);
     317        ::RTSemEventWait(mQEvent, aTimeout);
     318        ::RTCritSectEnter(&mcsQLock);
     319    }
     320    if (mQueue.empty())
     321    {
     322        *aEvent = NULL;
     323    }
     324    else
     325    {
     326        mQueue.front().queryInterfaceTo(aEvent);
     327        mQueue.pop_front();
     328    }
     329    ::RTCritSectLeave(&mcsQLock);
     330    return S_OK;
     331}
     332
     333HRESULT ListenerRecord::eventProcessed (IEvent* aEvent, PendingEventsMap::iterator& pit)
     334{
     335    if (--pit->second == 0)
     336    {
     337        aEvent->SetProcessed();
     338        mOwner->m->mPendingMap.erase(pit);
     339    }
     340
     341    Assert(pit->second >= 0);
     342    return S_OK;
     343}
    98344
    99345HRESULT EventSource::FinalConstruct()
     
    118364void EventSource::uninit()
    119365{
    120 }
    121 
    122 STDMETHODIMP EventSource::RegisterListener(IEventListener * aListener,
    123                                            ComSafeArrayIn(VBoxEventType, aInterested),
     366    m->mListeners.clear();
     367    // m->mEvMap shall be cleared at this point too by destructors
     368}
     369
     370STDMETHODIMP EventSource::RegisterListener(IEventListener * aListener,
     371                                           ComSafeArrayIn(VBoxEventType_T, aInterested),
    124372                                           BOOL             aActive)
    125373{
    126     return E_NOTIMPL;
     374    CheckComArgNotNull(aListener);
     375    CheckComArgSafeArrayNotNull(aInterested);
     376
     377    AutoCaller autoCaller(this);
     378    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     379
     380    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     381
     382    Listeners::const_iterator it = m->mListeners.find(aListener);
     383    if (it != m->mListeners.end())
     384        return setError(E_INVALIDARG,
     385                        tr("This listener already registered"));
     386
     387    com::SafeArray<VBoxEventType_T> interested(ComSafeArrayInArg (aInterested));
     388    m->mListeners.insert(
     389        Listeners::value_type(aListener,
     390                              ListenerRecord(aListener, interested, aActive, this))
     391                         );
     392
     393    return S_OK;
    127394}
    128395
    129396STDMETHODIMP EventSource::UnregisterListener(IEventListener * aListener)
    130397{
    131     return E_NOTIMPL;
     398    CheckComArgNotNull(aListener);
     399
     400    AutoCaller autoCaller(this);
     401    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     402
     403    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     404
     405    Listeners::iterator it = m->mListeners.find(aListener);
     406    HRESULT rc;
     407
     408    if (it != m->mListeners.end())
     409    {
     410        m->mListeners.erase(it);
     411        // destructor removes refs from the event map
     412        rc = S_OK;
     413    }
     414    else
     415    {
     416        rc = setError(VBOX_E_OBJECT_NOT_FOUND,
     417                      tr("Listener was never registered"));
     418    }
     419
     420    return rc;
    132421}
    133422
     
    136425                                    BOOL     *aProcessed)
    137426{
    138     return E_NOTIMPL;
     427    CheckComArgNotNull(aEvent);
     428    CheckComArgOutPointerValid(aProcessed);
     429
     430    AutoCaller autoCaller(this);
     431    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     432
     433    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     434
     435    VBoxEventType_T evType;
     436    HRESULT hrc = aEvent->COMGETTER(Type)(&evType);
     437    AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
     438
     439    BOOL aWaitable = FALSE;
     440    aEvent->COMGETTER(Waitable)(&aWaitable);
     441
     442    std::list<ListenerRecord*>& listeners = m->mEvMap[(int)evType-FirstEvent];
     443
     444    uint32_t cListeners = listeners.size();
     445    PendingEventsMap::iterator pit;
     446
     447    if (cListeners > 0 && aWaitable)
     448    {
     449        m->mPendingMap.insert(PendingEventsMap::value_type(aEvent, cListeners));
     450        // we keep it here to allow processing active listeners without pending events lookup
     451        pit = m->mPendingMap.find(aEvent);
     452    }
     453    for(std::list<ListenerRecord*>::const_iterator it = listeners.begin();
     454        it != listeners.end(); ++it)
     455    {
     456        ListenerRecord* record = *it;
     457        HRESULT cbRc;
     458
     459        // @todo: callback under (read) lock, is it good?
     460        cbRc = record->process(aEvent, aWaitable, pit);
     461        // what to do with cbRc?
     462    }
     463
     464    if (aWaitable)
     465        hrc = aEvent->WaitProcessed(aTimeout, aProcessed);
     466    else
     467        *aProcessed = TRUE;
     468
     469    return hrc;
    139470}
    140471
     
    144475                                   IEvent  * *aEvent)
    145476{
    146     return E_NOTIMPL;
     477
     478    CheckComArgNotNull(aListener);
     479
     480    AutoCaller autoCaller(this);
     481    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     482
     483    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     484
     485    Listeners::iterator it = m->mListeners.find(aListener);
     486    HRESULT rc;
     487
     488    if (it != m->mListeners.end())
     489    {
     490        rc = it->second.dequeue(aEvent, aTimeout);
     491    }
     492    else
     493    {
     494        rc = setError(VBOX_E_OBJECT_NOT_FOUND,
     495                      tr("Listener was never registered"));
     496    }
     497
     498    return rc;
    147499}
    148500
     
    150502                                         IEvent *         aEvent)
    151503{
    152     return E_NOTIMPL;
    153 }
    154 
     504    CheckComArgNotNull(aListener);
     505    CheckComArgNotNull(aEvent);
     506
     507    AutoCaller autoCaller(this);
     508    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     509
     510    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     511
     512    Listeners::iterator it = m->mListeners.find(aListener);
     513    HRESULT rc;
     514
     515    BOOL aWaitable = FALSE;
     516    aEvent->COMGETTER(Waitable)(&aWaitable);
     517
     518    if (it != m->mListeners.end())
     519    {
     520        ListenerRecord& aRecord = it->second;
     521
     522        if (aRecord.mActive)
     523            return setError(E_INVALIDARG,
     524                        tr("Only applicable to passive listeners"));
     525
     526        if (aWaitable)
     527        {
     528            PendingEventsMap::iterator pit = m->mPendingMap.find(aEvent);
     529
     530            if (pit == m->mPendingMap.end())
     531            {
     532                AssertFailed();
     533                rc = setError(VBOX_E_OBJECT_NOT_FOUND,
     534                              tr("Unknown event"));
     535            }
     536            else
     537                rc = aRecord.eventProcessed(aEvent, pit);
     538        }
     539        else
     540        {
     541            // for non-waitable events we're done
     542            rc = S_OK;
     543        }
     544    }
     545    else
     546    {
     547        rc = setError(VBOX_E_OBJECT_NOT_FOUND,
     548                      tr("Listener was never registered"));
     549    }
     550
     551    return rc;
     552}
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r30310 r30331  
    1455614556    <const name="Invalid" value="0">
    1455714557      <desc>
    14558         Invalid event.
     14558        Invalid event, must be first.
    1455914559      </desc>
    1456014560    </const>
     
    1457414574    </const>
    1457514575
     14576    <const name="LastWildcard" value="31">
     14577      <desc>
     14578        Last wildcard.
     14579      </desc>
     14580    </const>
     14581
    1457614582    <const name="OnMachineStateChange" value="32">
    1457714583      <desc>
     
    1458714593      <desc>
    1458814594        <see>IVirtualBoxCallback::onExtraDataChange</see>
     14595      </desc>
     14596    </const>
     14597
     14598    <const name="Last" value="35">
     14599      <desc>
     14600        Must be last event, used for iterations.
    1458914601      </desc>
    1459014602    </const>
  • trunk/src/VBox/Main/include/EventImpl.h

    r30311 r30331  
    100100    // IEventSource methods
    101101    STDMETHOD(RegisterListener)(IEventListener * aListener,
    102                                 ComSafeArrayIn(VBoxEventType, aInterested),
     102                                ComSafeArrayIn(VBoxEventType_T, aInterested),
    103103                                BOOL             aActive);
    104104    STDMETHOD(UnregisterListener)(IEventListener * aListener);
     
    119119
    120120    Data* m;
     121
     122    friend class ListenerRecord;
    121123};
    122124
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