VirtualBox

Changeset 33295 in vbox for trunk/src


Ignore:
Timestamp:
Oct 21, 2010 10:46:46 AM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
66863
Message:

Main: support aggregation of multiple event sources into one,
to allow listen on multiple event sources without heavy polling
(pretty much what select() do with fds)

Location:
trunk/src/VBox
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxShell/vboxshell.py

    r33266 r33295  
    405405    listener = console.eventSource.createListener()
    406406    registered = False
    407     sources = [console.keyboard.eventSource, console.mouse.eventSource]
     407    # we create an aggregated event source to listen for multiple event types
     408    agg = console.eventSource.createAggregator([console.keyboard.eventSource, console.mouse.eventSource])
    408409    demo = open(file, 'w')
    409410    header="VM="+console.machine.name+"\n"
     
    413414        dur = 100000
    414415    try:
    415         for es in sources:
    416             es.registerListener(listener, [ctx['global'].constants.VBoxEventType_Any], False)
     416        agg.registerListener(listener, [ctx['global'].constants.VBoxEventType_Any], False)
    417417        registered = True
    418418        end = time.time() + dur
    419419        while  time.time() < end:
    420             for es in sources:
    421                 ev = es.getEvent(listener, 0)
    422                 if ev:
    423                     handleEventImpl(ev)
    424                     # keyboard/mouse events aren't waitable, so no need for eventProcessed
     420            ev = agg.getEvent(listener, 0)
     421            if ev:
     422                handleEventImpl(ev)
     423                # keyboard/mouse events aren't waitable, so no need for eventProcessed
    425424    # We need to catch all exceptions here, otherwise listener will never be unregistered
    426425    except:
     
    429428    demo.close()
    430429    if listener and registered:
    431         for es in sources:
    432             es.unregisterListener(listener)
     430        agg.unregisterListener(listener)
    433431
    434432
  • trunk/src/VBox/Main/EventImpl.cpp

    r33265 r33295  
    833833
    834834    if (queueSize != 0 && mQueue.back() == aEvent)
    835         /* if same event is being pushed multiple times - it's reusable event and 
     835        /* if same event is being pushed multiple times - it's reusable event and
    836836           we don't really need multiple instances of it in the queue */
    837837        (void)aEvent;
     
    851851                                 AutoLockBase& aAlock)
    852852{
    853     AssertMsg(!mActive, ("must be passive\n"));
     853    if (mActive)
     854        return VBOX_E_INVALID_OBJECT_STATE;
    854855
    855856    // retain listener record
     
    11011102                      tr("Listener was never registered"));
    11021103
     1104    if (rc == VBOX_E_INVALID_OBJECT_STATE)
     1105        return setError(rc, tr("Listener must be passive"));
     1106
    11031107    return rc;
    11041108}
     
    12011205};
    12021206
     1207/* Proxy listener class, used to aggregate multiple event sources into one */
     1208class ATL_NO_VTABLE ProxyEventListener :
     1209    public VirtualBoxBase,
     1210    VBOX_SCRIPTABLE_IMPL(IEventListener)
     1211{
     1212    ComPtr<IEventSource> mSource;
     1213public:
     1214
     1215    VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(ProxyEventListener, IEventListener)
     1216
     1217    DECLARE_NOT_AGGREGATABLE(ProxyEventListener)
     1218
     1219    DECLARE_PROTECT_FINAL_CONSTRUCT()
     1220
     1221    BEGIN_COM_MAP(ProxyEventListener)
     1222        COM_INTERFACE_ENTRY(ISupportErrorInfo)
     1223        COM_INTERFACE_ENTRY(IEventListener)
     1224        COM_INTERFACE_ENTRY(IDispatch)
     1225    END_COM_MAP()
     1226
     1227    ProxyEventListener()
     1228    {}
     1229    ~ProxyEventListener()
     1230    {}
     1231
     1232    HRESULT FinalConstruct()
     1233    {
     1234        return S_OK;
     1235    }
     1236    void FinalRelease()
     1237    {}
     1238
     1239    HRESULT init(IEventSource* aSource)
     1240    {
     1241        mSource = aSource;
     1242        return S_OK;
     1243    }
     1244
     1245    // IEventListener methods
     1246    STDMETHOD(HandleEvent)(IEvent * aEvent)
     1247    {
     1248        BOOL fProcessed = FALSE;
     1249        if (mSource)
     1250            return mSource->FireEvent(aEvent, 0, &fProcessed);
     1251        else
     1252            return S_OK;
     1253    }
     1254};
     1255
     1256class ATL_NO_VTABLE EventSourceAggregator :
     1257    public VirtualBoxBase,
     1258    VBOX_SCRIPTABLE_IMPL(IEventSource)
     1259{
     1260    typedef std::list <ComPtr<IEventSource> > EventSourceList;
     1261    /* key is weak reference */
     1262    typedef std::map<IEventListener*, ComPtr<IEventListener> > ProxyListenerMap;
     1263
     1264    EventSourceList           mEventSources;
     1265    ProxyListenerMap          mListenerProxies;
     1266    ComObjPtr<EventSource>    mSource;
     1267
     1268public:
     1269
     1270    VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(EventSourceAggregator, IEventSource)
     1271
     1272    DECLARE_NOT_AGGREGATABLE(EventSourceAggregator)
     1273
     1274    DECLARE_PROTECT_FINAL_CONSTRUCT()
     1275
     1276    BEGIN_COM_MAP(EventSourceAggregator)
     1277        COM_INTERFACE_ENTRY(ISupportErrorInfo)
     1278        COM_INTERFACE_ENTRY(IEventSource)
     1279        COM_INTERFACE_ENTRY(IDispatch)
     1280    END_COM_MAP()
     1281
     1282    EventSourceAggregator()
     1283    {}
     1284    ~EventSourceAggregator()
     1285    {}
     1286
     1287    HRESULT FinalConstruct()
     1288    {
     1289        return S_OK;
     1290    }
     1291    void FinalRelease()
     1292    {
     1293        mEventSources.clear();
     1294        mListenerProxies.clear();
     1295        mSource->uninit();
     1296    }
     1297
     1298    // internal public
     1299    HRESULT init(ComSafeArrayIn(IEventSource *, aSources));
     1300
     1301    // IEventSource methods
     1302    STDMETHOD(CreateListener)(IEventListener ** aListener);
     1303    STDMETHOD(CreateAggregator)(ComSafeArrayIn(IEventSource*, aSubordinates),
     1304                                IEventSource **               aAggregator);
     1305    STDMETHOD(RegisterListener)(IEventListener * aListener,
     1306                                ComSafeArrayIn(VBoxEventType_T, aInterested),
     1307                                BOOL             aActive);
     1308    STDMETHOD(UnregisterListener)(IEventListener * aListener);
     1309    STDMETHOD(FireEvent)(IEvent * aEvent,
     1310                         LONG     aTimeout,
     1311                         BOOL     *aProcessed);
     1312    STDMETHOD(GetEvent)(IEventListener * aListener,
     1313                        LONG      aTimeout,
     1314                        IEvent  * *aEvent);
     1315    STDMETHOD(EventProcessed)(IEventListener * aListener,
     1316                              IEvent *         aEvent);
     1317
     1318  protected:
     1319    HRESULT createProxyListener(IEventListener * aListener,
     1320                                IEventListener * *aProxy);
     1321    HRESULT getProxyListener   (IEventListener * aListener,
     1322                                IEventListener * *aProxy);
     1323    HRESULT removeProxyListener(IEventListener * aListener);
     1324};
     1325
    12031326#ifdef VBOX_WITH_XPCOM
     1327NS_DECL_CLASSINFO(ProxyEventListener)
     1328NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ProxyEventListener, IEventListener)
    12041329NS_DECL_CLASSINFO(PassiveEventListener)
    12051330NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PassiveEventListener, IEventListener)
     
    12101335NS_DECL_CLASSINFO(EventSource)
    12111336NS_IMPL_THREADSAFE_ISUPPORTS1_CI(EventSource, IEventSource)
     1337NS_DECL_CLASSINFO(EventSourceAggregator)
     1338NS_IMPL_THREADSAFE_ISUPPORTS1_CI(EventSourceAggregator, IEventSource)
    12121339#endif
     1340
    12131341
    12141342STDMETHODIMP EventSource::CreateListener(IEventListener ** aListener)
     
    12271355    return S_OK;
    12281356}
     1357
     1358
     1359STDMETHODIMP EventSource::CreateAggregator(ComSafeArrayIn(IEventSource*, aSubordinates),
     1360                                           IEventSource **               aResult)
     1361{
     1362    CheckComArgOutPointerValid(aResult);
     1363
     1364    AutoCaller autoCaller(this);
     1365    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1366
     1367    ComObjPtr<EventSourceAggregator> agg;
     1368
     1369    HRESULT rc = agg.createObject();
     1370    ComAssertMsgRet(SUCCEEDED(rc), ("Could not create aggregator (%Rrc)", rc),
     1371                    E_FAIL);
     1372
     1373    rc = agg->init(ComSafeArrayInArg(aSubordinates));
     1374    if (FAILED(rc))
     1375        return rc;
     1376
     1377
     1378    agg.queryInterfaceTo(aResult);
     1379    return S_OK;
     1380}
     1381
     1382HRESULT  EventSourceAggregator::init(ComSafeArrayIn(IEventSource*, aSourcesIn))
     1383{
     1384    HRESULT rc;
     1385
     1386    AutoInitSpan autoInitSpan(this);
     1387    AssertReturn(autoInitSpan.isOk(), E_FAIL);
     1388
     1389    rc = mSource.createObject();
     1390    ComAssertMsgRet(SUCCEEDED(rc), ("Could not create source (%Rrc)", rc),
     1391                    E_FAIL);
     1392    rc = mSource->init((IEventSource*)this);
     1393    ComAssertMsgRet(SUCCEEDED(rc), ("Could not init source (%Rrc)", rc),
     1394                    E_FAIL);
     1395
     1396    com::SafeIfaceArray<IEventSource> aSources(ComSafeArrayInArg (aSourcesIn));
     1397
     1398    uint32_t cSize = aSources.size();
     1399
     1400    for (uint32_t i=0; i<cSize; i++)
     1401    {
     1402        if (aSources[i] != NULL)
     1403            mEventSources.push_back(aSources[i]);
     1404    }
     1405
     1406    /* Confirm a successful initialization */
     1407    autoInitSpan.setSucceeded();
     1408
     1409    return rc;
     1410}
     1411
     1412STDMETHODIMP EventSourceAggregator::CreateListener(IEventListener ** aListener)
     1413{
     1414    return mSource->CreateListener(aListener);
     1415}
     1416
     1417STDMETHODIMP EventSourceAggregator::CreateAggregator(ComSafeArrayIn(IEventSource*, aSubordinates),
     1418                                                     IEventSource **               aResult)
     1419{
     1420    return mSource->CreateAggregator(ComSafeArrayInArg(aSubordinates), aResult);
     1421}
     1422
     1423STDMETHODIMP EventSourceAggregator::RegisterListener(IEventListener * aListener,
     1424                                                     ComSafeArrayIn(VBoxEventType_T, aInterested),
     1425                                                     BOOL             aActive)
     1426{
     1427    CheckComArgNotNull(aListener);
     1428    CheckComArgSafeArrayNotNull(aInterested);
     1429
     1430    AutoCaller autoCaller(this);
     1431    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1432
     1433    HRESULT rc;
     1434
     1435    ComPtr<IEventListener> proxy;
     1436    rc = createProxyListener(aListener, proxy.asOutParam());
     1437    if (FAILED(rc))
     1438        return rc;
     1439
     1440    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1441    for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end();
     1442         ++it)
     1443    {
     1444        ComPtr<IEventSource> es = *it;
     1445        /* Register active proxy listener on real event source */
     1446        rc = es->RegisterListener(proxy, ComSafeArrayInArg(aInterested), TRUE);
     1447    }
     1448    /* And add real listener on our event source */
     1449    rc = mSource->RegisterListener(aListener, ComSafeArrayInArg(aInterested), aActive);
     1450
     1451    rc = S_OK;
     1452
     1453    return rc;
     1454}
     1455
     1456STDMETHODIMP EventSourceAggregator::UnregisterListener(IEventListener * aListener)
     1457{
     1458    CheckComArgNotNull(aListener);
     1459
     1460    AutoCaller autoCaller(this);
     1461    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1462
     1463    HRESULT rc = S_OK;
     1464
     1465    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1466
     1467    ComPtr<IEventListener> proxy;
     1468    rc = getProxyListener(aListener, proxy.asOutParam());
     1469    if (FAILED(rc))
     1470        return rc;
     1471
     1472    for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end();
     1473         ++it)
     1474    {
     1475        ComPtr<IEventSource> es = *it;
     1476        rc = es->UnregisterListener(proxy);
     1477    }
     1478    rc = mSource->UnregisterListener(aListener);
     1479
     1480    return removeProxyListener(aListener);
     1481
     1482}
     1483
     1484STDMETHODIMP EventSourceAggregator::FireEvent(IEvent * aEvent,
     1485                                              LONG     aTimeout,
     1486                                              BOOL     *aProcessed)
     1487{
     1488    CheckComArgNotNull(aEvent);
     1489    CheckComArgOutPointerValid(aProcessed);
     1490
     1491    AutoCaller autoCaller(this);
     1492    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1493
     1494    HRESULT rc = S_OK;
     1495    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1496    /* Aggresgator event source shalln't have direct event firing, but we may
     1497       wish to support aggregation chains */
     1498    for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end();
     1499         ++it)
     1500    {
     1501        ComPtr<IEventSource> es = *it;
     1502        rc = es->FireEvent(aEvent, aTimeout, aProcessed);
     1503    }
     1504
     1505    return S_OK;
     1506}
     1507
     1508STDMETHODIMP EventSourceAggregator::GetEvent(IEventListener * aListener,
     1509                                             LONG             aTimeout,
     1510                                             IEvent  **       aEvent)
     1511{
     1512    return mSource->GetEvent(aListener, aTimeout, aEvent);
     1513}
     1514
     1515STDMETHODIMP EventSourceAggregator::EventProcessed(IEventListener * aListener,
     1516                                                   IEvent *         aEvent)
     1517{
     1518    return mSource->EventProcessed(aListener, aEvent);
     1519}
     1520
     1521HRESULT EventSourceAggregator::createProxyListener(IEventListener * aListener,
     1522                                                   IEventListener * *aProxy)
     1523{
     1524    ComObjPtr<ProxyEventListener> proxy;
     1525
     1526    HRESULT rc = proxy.createObject();
     1527    ComAssertMsgRet(SUCCEEDED(rc), ("Could not create proxy (%Rrc)", rc),
     1528                    E_FAIL);
     1529
     1530    rc = proxy->init(mSource);
     1531    if (FAILED(rc))
     1532        return rc;
     1533
     1534    ProxyListenerMap::const_iterator it = mListenerProxies.find(aListener);
     1535    if (it != mListenerProxies.end())
     1536        return setError(E_INVALIDARG,
     1537                        tr("This listener already registered"));
     1538
     1539    mListenerProxies.insert(ProxyListenerMap::value_type(aListener, proxy));
     1540
     1541    proxy.queryInterfaceTo(aProxy);
     1542    return S_OK;
     1543}
     1544
     1545HRESULT EventSourceAggregator::getProxyListener(IEventListener * aListener,
     1546                                                IEventListener * *aProxy)
     1547{
     1548    ProxyListenerMap::const_iterator it = mListenerProxies.find(aListener);
     1549    if (it == mListenerProxies.end())
     1550        return setError(E_INVALIDARG,
     1551                        tr("This listener never registered"));
     1552
     1553    (*it).second.queryInterfaceTo(aProxy);
     1554    return S_OK;
     1555}
     1556
     1557HRESULT EventSourceAggregator::removeProxyListener(IEventListener * aListener)
     1558{
     1559    ProxyListenerMap::iterator it = mListenerProxies.find(aListener);
     1560    if (it == mListenerProxies.end())
     1561        return setError(E_INVALIDARG,
     1562                        tr("This listener never registered"));
     1563
     1564    mListenerProxies.erase(it);
     1565    return S_OK;
     1566}
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r33294 r33295  
    1410114101  <interface
    1410214102     name="IEventSource" extends="$unknown"
    14103      uuid="3c670618-f727-4fe9-94d2-8243f489a033"
     14103     uuid="9b6e1aee-35f3-4f4d-b5bb-ed0ecefd8538"
    1410414104     wsmap="managed"
    1410514105     >
     
    1412114121    </method>
    1412214122
     14123    <method name="createAggregator">
     14124      <desc>
     14125        Creates a aggregator event source, collecting events from multiple source.
     14126        This way single listener can collect events from multiple sources, using
     14127        getEvent() of this aggregator.
     14128      </desc>
     14129      <param name="subordinates" type="IEventSource" dir="in" safearray="yes">
     14130        <desc>
     14131          Subordinate event source this one aggregatres.
     14132        </desc>
     14133      </param>
     14134      <param name="result" type="IEventSource" dir="return"/>
     14135    </method>
     14136
    1412314137    <method name="registerListener">
    1412414138      <desc>
     
    1412814142          To avoid system overload, the VirtualBox server process checks if passive event
    1412914143          listeners call <link to="IEventSource::getEvent"/> frequently enough. In the
    14130           current implementation, if more than 100 pending events are detected for a passive
     14144          current implementation, if more than 500 pending events are detected for a passive
    1413114145          event listener, it is forcefully unregistered by the system, and further
    1413214146          <link to="#getEvent" /> calls will return @c VBOX_E_OBJECT_NOT_FOUND.
Note: See TracChangeset for help on using the changeset viewer.

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