EventImpl.cpp revision 57f30daf970e747ecb8bfbc3f2c7636db876ddb3
/* $Id$ */
/** @file
* VirtualBox COM Event class implementation
*/
/*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include <list>
#include <map>
#include <deque>
#include "EventImpl.h"
#include "AutoCaller.h"
#include "Logging.h"
#include <iprt/semaphore.h>
#include <iprt/critsect.h>
{
Data()
:
{}
};
{
m = new Data;
return S_OK;
}
void VBoxEvent::FinalRelease()
{
if (m)
{
uninit();
delete m;
m = 0;
}
}
{
AutoInitSpan autoInitSpan(this);
m->mProcessed = !aWaitable;
do {
if (aWaitable)
{
if (RT_FAILURE(vrc))
{
AssertFailed ();
}
}
} while (0);
/* Confirm a successful initialization */
return rc;
}
{
if (!m)
return;
m->mProcessed = TRUE;
m->mType = VBoxEventType_Invalid;
if (m->mWaitEvent != NIL_RTSEMEVENT)
{
::RTSemEventDestroy(m->mWaitEvent);
m->mWaitEvent = NIL_RTSEMEVENT;
}
}
{
AutoCaller autoCaller(this);
// never changes till event alive, no locking?
return S_OK;
}
{
AutoCaller autoCaller(this);
return S_OK;
}
{
AutoCaller autoCaller(this);
// never changes till event alive, no locking?
return S_OK;
}
{
AutoCaller autoCaller(this);
if (m->mProcessed)
return S_OK;
m->mProcessed = TRUE;
// notify waiters
::RTSemEventSignal(m->mWaitEvent);
return S_OK;
}
{
AutoCaller autoCaller(this);
{
if (m->mProcessed)
{
return S_OK;
}
if (aTimeout == 0)
{
*aResult = m->mProcessed;
return S_OK;
}
}
("RTSemEventWait returned %Rrc\n", vrc));
if (RT_SUCCESS(vrc))
{
AssertMsg(m->mProcessed,
("mProcessed must be set here\n"));
*aResult = m->mProcessed;
}
else
{
}
return S_OK;
}
static const int LastEvent = (int)VBoxEventType_Last;
class ListenerRecord;
class ListenerRecord
{
private:
public:
~ListenerRecord();
HRESULT process(IEvent* aEvent, BOOL aWaitable, PendingEventsMap::iterator& pit, AutoLockBase& alock);
void addRef()
{
}
void release()
{
if (ASMAtomicDecS32(&mRefCnt) <= 0) delete this;
}
{
return mActive;
}
};
/* Handy class with semantics close to ComPtr, but for ListenerRecord */
class ListenerRecordHolder
{
public:
:
{
addref();
}
:
{
addref();
}
:
held(0)
{
}
{
release();
}
{
return held;
}
{
return *this;
}
private:
void addref()
{
if (held)
}
void release()
{
if (held)
}
{
if (that_p)
release();
}
};
struct EventSource::Data
{
Data() {}
};
/**
* This function defines what wildcard expands to.
*/
{
switch (who)
{
case VBoxEventType_Any:
return TRUE;
return (what == VBoxEventType_OnMachineStateChange)
|| (what == VBoxEventType_OnGuestPropertyChange);
return (what == VBoxEventType_OnSnapshotTaken)
|| (what == VBoxEventType_OnSnapshotDeleted)
|| (what == VBoxEventType_OnSnapshotChange)
;
case VBoxEventType_Invalid:
return FALSE;
}
}
:
mRefCnt(0)
{
{
for (int j = FirstEvent; j < LastEvent; j++)
{
{
}
}
}
if (!mActive)
{
::RTCritSectInit(&mcsQLock);
::RTSemEventCreate (&mQEvent);
}
}
{
/* Remove references to us from the event map */
for (int j = FirstEvent; j < LastEvent; j++)
{
}
if (!mActive)
{
::RTCritSectDelete(&mcsQLock);
}
}
HRESULT ListenerRecord::process(IEvent* aEvent, BOOL aWaitable, PendingEventsMap::iterator& pit, AutoLockBase& alock)
{
if (mActive)
{
/*
* We release lock here to allow modifying ops on EventSource inside callback.
*/
if (mListener)
{
}
if (aWaitable)
return rc;
}
else
}
{
// put an event the queue
::RTCritSectEnter(&mcsQLock);
::RTCritSectLeave(&mcsQLock);
// notify waiters
return S_OK;
}
{
::RTCritSectEnter(&mcsQLock);
{
::RTCritSectLeave(&mcsQLock);
// Speed up common case
if (aTimeout == 0)
{
return S_OK;
}
::RTCritSectEnter(&mcsQLock);
}
{
}
else
{
}
::RTCritSectLeave(&mcsQLock);
return S_OK;
}
{
{
aEvent->SetProcessed();
}
return S_OK;
}
{}
{}
{
m = new Data;
return S_OK;
}
void EventSource::FinalRelease()
{
uninit();
delete m;
}
{
AutoInitSpan autoInitSpan(this);
/* Confirm a successful initialization */
return rc;
}
void EventSource::uninit()
{
m->mListeners.clear();
// m->mEvMap shall be cleared at this point too by destructors
}
{
AutoCaller autoCaller(this);
return setError(E_INVALIDARG,
tr("This listener already registered"));
return S_OK;
}
{
AutoCaller autoCaller(this);
{
// destructor removes refs from the event map
}
else
{
tr("Listener was never registered"));
}
return rc;
}
{
AutoCaller autoCaller(this);
do {
/* See comment in EventSource::GetEvent() */
/* Anyone interested in this event? */
if (cListeners == 0)
break; // just leave the lock and update event object state
if (aWaitable)
{
// we keep iterator here to allow processing active listeners without
// pending events lookup
}
{
// keep listener record reference, in case someone will remove it while in callback
/**
* We pass lock here to allow modifying ops on EventSource inside callback
* in active mode. Note that we expect list iterator stability as 'alock'
* could be temporary released when calling event handler.
*/
// what to do with cbRc?
}
} while (0);
/* We leave the lock here */
if (aWaitable)
else
*aProcessed = TRUE;
return hrc;
}
{
AutoCaller autoCaller(this);
/**
* There's subtle dependency between this lock and one in FireEvent():
* we need to be able to access event queue in FireEvent() while waiting
* here, to make this wait preemptible, thus both take read lock (write
* lock in FireEvent() would do too, and probably is a bit stricter),
* but will interfere with .
*/
else
tr("Listener was never registered"));
return rc;
}
{
AutoCaller autoCaller(this);
{
return setError(E_INVALIDARG,
tr("Only applicable to passive listeners"));
if (aWaitable)
{
{
AssertFailed();
tr("Unknown event"));
}
else
}
else
{
// for non-waitable events we're done
}
}
else
{
tr("Listener was never registered"));
}
return rc;
}
/**
* This class serves as feasible listener implementation
* which could be used by clients not able to create local
* COM objects, but still willing to recieve event
* notifications in passive mode, such as webservices.
*/
class ATL_NO_VTABLE PassiveEventListener :
public VirtualBoxBase,
{
public:
{}
{}
{
return S_OK;
}
void FinalRelease()
{}
// IEventListener methods
{
ComAssertMsgRet(false, ("HandleEvent() of wrapper shall never be called"),
E_FAIL);
}
// for VirtualBoxSupportErrorInfoImpl
static const wchar_t *getComponentName() { return L"PassiveEventListener"; }
};
#ifdef VBOX_WITH_XPCOM
#endif
{
AutoCaller autoCaller(this);
E_FAIL);
return S_OK;
}