summaryrefslogtreecommitdiff
path: root/comphelper
diff options
context:
space:
mode:
authorSascha Ballach <sab@openoffice.org>2003-01-22 14:18:07 +0000
committerSascha Ballach <sab@openoffice.org>2003-01-22 14:18:07 +0000
commitd1ceaf72031728dd87ff56df592a65f88a866f2d (patch)
tree7f13f88c571dfd2812db0511e0a0677a7abe7cb6 /comphelper
parent0986e76cf941c8134eceb60965798bc5b5273c77 (diff)
#106337#; make notification synchron
Diffstat (limited to 'comphelper')
-rw-r--r--comphelper/source/misc/accessibleeventnotifier.cxx426
1 files changed, 67 insertions, 359 deletions
diff --git a/comphelper/source/misc/accessibleeventnotifier.cxx b/comphelper/source/misc/accessibleeventnotifier.cxx
index 2fd5f79f53cd..32ab2995ee5e 100644
--- a/comphelper/source/misc/accessibleeventnotifier.cxx
+++ b/comphelper/source/misc/accessibleeventnotifier.cxx
@@ -2,9 +2,9 @@
*
* $RCSfile: accessibleeventnotifier.cxx,v $
*
- * $Revision: 1.1 $
+ * $Revision: 1.2 $
*
- * last change: $Author: fs $ $Date: 2002-12-06 12:56:46 $
+ * last change: $Author: sab $ $Date: 2003-01-22 15:18:07 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
@@ -85,184 +85,8 @@ namespace comphelper
//= AccessibleEventNotifier
//=====================================================================
//---------------------------------------------------------------------
- ::osl::Mutex AccessibleEventNotifier::s_aMutex;
- AccessibleEventNotifier* AccessibleEventNotifier::s_pNotifier = NULL;
-
- //---------------------------------------------------------------------
- AccessibleEventNotifier::AccessibleEventNotifier( )
- :m_bTerminateRequested( sal_False )
- {
- // no events so far
- m_aEventGuard.reset();
- }
-
- //---------------------------------------------------------------------
- AccessibleEventNotifier::~AccessibleEventNotifier( )
- {
- OSL_ENSURE( m_aClients.empty() && m_aDisposedClients.empty(),
- "AccessibleEventNotifier::~AccessibleEventNotifier: not correctly terminated - resource leak!" );
- }
-
- //---------------------------------------------------------------------
- namespace
- {
- static void lcl_copyInterfaceContainer( const ::cppu::OInterfaceContainerHelper& _rSource, ::cppu::OInterfaceContainerHelper& _rDest )
- {
- _rDest.clear();
- Sequence< Reference< XInterface > > aInterfaces( _rSource.getElements() );
-
- const Reference< XInterface >* pInterfaces = aInterfaces.getConstArray();
- const Reference< XInterface >* pInterfacesEnd = pInterfaces + aInterfaces.getLength();
- for ( ; pInterfaces != pInterfacesEnd; ++pInterfaces )
- _rDest.addInterface( *pInterfaces );
- }
- }
- //---------------------------------------------------------------------
- void SAL_CALL AccessibleEventNotifier::run()
- {
- sal_Bool bTerminate = sal_False;
-
- do
- {
- // notify the events we have in the queue
- // --- <mutex_lock> -------------------------------------------
- {
- ::osl::MutexGuard aGuard( s_aMutex );
-
- // continue with all events we have so far
- while ( !m_aEvents.empty() )
- {
- // the first event in the queue
- ClientEvent aEvent = m_aEvents.front();
- m_aEvents.pop_front();
-
- // special handling for "disposing"
- if ( aEvent.second.EventId < 0 )
- {
- // look up in the map for "disposed clients"
- ClientMap::iterator aPos = m_aDisposedClients.find( aEvent.first );
- OSL_ENSURE( m_aDisposedClients.end() != aPos,
- "AccessibleEventNotifier::run: could not find this client!" );
-
- if ( m_aDisposedClients.end() != aPos )
- {
- EventObject aDisposalEvent;
- aDisposalEvent.Source = aEvent.second.Source;
-
- // want to call the listeners with a released mutex
- // thus we have to copy the container, so that we can savely use the copy while
- // our mutex is released
-
- ::cppu::OInterfaceContainerHelper aCopy( s_aMutex );
- lcl_copyInterfaceContainer( *aPos->second, aCopy );
-
- // we do not need the entry in the "disposed clients" map anymore
- // because the "disposed" event is the _last_ one to be fired for a client
- delete aPos->second;
- m_aDisposedClients.erase( aPos );
-
- // now do the notification, and do it with the _copy_ after releasing the mutex
- // --- <mutex_release> ------------------------
- {
- MutexRelease aReleaseOnce( s_aMutex );
- aCopy.disposeAndClear( aDisposalEvent );
-
- // clear the aDisposalEvent while our mutex is _not_ acquired
- // this ensures that we do not - by accident - release the last reference
- // of the foreign component while our mutex is locked
- aDisposalEvent.Source.clear();
- }
- // --- </mutex_release> -----------------------
-
- // cleanup the thread if we do not have clients anymore
- implCleanupNotifier( );
- }
- }
- else
- {
- // look up the client for this event
- ClientMap::iterator aClientPos;
- if ( implLookupClient( aEvent.first, aClientPos ) )
- {
- // copy the listener sequence. We do _not_ want to call into the listeners
- // with our mutex locked
- Sequence< Reference< XInterface > > aListeners( aClientPos->second->getElements() );
- // default handling: loop through all listeners, and notify them
-
- const Reference< XInterface >* pListeners = aListeners.getConstArray();
- const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength();
-
- // --- <mutex_release> ------------------------
- {
- // release the mutex within this block
- MutexRelease aReleaseOnce( s_aMutex );
-
- while ( pListeners != pListenersEnd )
- {
- try
- {
- static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( aEvent.second );
- }
- catch( const Exception& e )
- {
- e;
- // silent this
- // no assertion, because a broken access remote bridge or something like this
- // can cause this exception
- }
- ++pListeners;
- }
- }
- // --- </mutex_release> -----------------------
- }
- else
- OSL_ENSURE( sal_False, "AccessibleEventNotifier::run: invalid client id found for accessible event!" );
- }
-
- // --- <mutex_release> --------------------------------
- {
- MutexRelease aReleaseOnce( s_aMutex );
- // clear the event
- // do this with our own mutex released, as clearing the event includes releasing the reference
- // to the css.lang.EventObject.Source - in case this release is non-trivial (i.e. the last
- // reference to the object), we certainly do _not_ want to do this while our
- // mutex is locked
- aEvent = ClientEvent();
- }
- // --- </mutex_release> -------------------------------
- }
-
- // reset the condition - will be set as soon as a new event arrives
- m_aEventGuard.reset();
- }
- // --- </mutex_lock> ------------------------------------------
-
- // wait (sleep) 'til a new event arrives
- m_aEventGuard.wait();
-
- // --- <mutex_lock> -------------------------------------------
- {
- ::osl::MutexGuard aGuard( s_aMutex );
- bTerminate = m_bTerminateRequested;
- }
- // --- </mutex_lock> ------------------------------------------
- }
- while ( !bTerminate );
- }
-
- //---------------------------------------------------------------------
- void SAL_CALL AccessibleEventNotifier::terminate()
- {
- AccessibleEventNotifier_BASE::terminate();
- // base class does not call onTerminated - just in case we want to do any cleanup there ...
- onTerminated();
- }
-
- //---------------------------------------------------------------------
- void SAL_CALL AccessibleEventNotifier::onTerminated()
- {
- delete this;
- }
+ ::osl::Mutex AccessibleEventNotifier::s_aMutex;
+ AccessibleEventNotifier::ClientMap AccessibleEventNotifier::s_aClients;
//---------------------------------------------------------------------
AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId()
@@ -275,8 +99,8 @@ namespace comphelper
// Note that the following relies on the fact the elements in the map are traveled with
// ascending keys (aka client ids)
- for ( ClientMap::const_iterator aLookup = m_aClients.begin();
- aLookup != m_aClients.end();
+ for ( ClientMap::const_iterator aLookup = s_aClients.begin();
+ aLookup != s_aClients.end();
++aLookup
)
{
@@ -285,15 +109,8 @@ namespace comphelper
if ( nCurrent - nBiggestUsedId > 1 )
{ // found a "gap"
- TClientId nCandidate = nBiggestUsedId + 1;
-
- // ensure that the id is really free - it's possible that the id is still in the "disposed clients"
- // map
- if ( m_aDisposedClients.end() == m_aDisposedClients.find( nCandidate ) )
- { // yep, it's really available
- nFreeId = nCandidate;
- break;
- }
+ nFreeId = nBiggestUsedId + 1;
+ break;
}
nBiggestUsedId = nCurrent;
@@ -302,7 +119,7 @@ namespace comphelper
if ( !nFreeId )
nFreeId = nBiggestUsedId + 1;
- OSL_ENSURE( m_aClients.end() == m_aClients.find( nFreeId ),
+ OSL_ENSURE( s_aClients.end() == s_aClients.find( nFreeId ),
"AccessibleEventNotifier::generateId: algorithm broken!" );
return nFreeId;
@@ -312,30 +129,19 @@ namespace comphelper
AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( )
{
::osl::MutexGuard aGuard( s_aMutex );
- if ( !s_pNotifier )
- { // the first client -> create the thread
-
- // create the thread object
- s_pNotifier = new AccessibleEventNotifier;
-
- // run the thread
- s_pNotifier->create();
- // note that the thread will start running, and the first thing it will do is stopping
- // in run, waiting for the mutex
- }
// generate a new client id
- TClientId nNewClientId = s_pNotifier->generateId( );
+ TClientId nNewClientId = generateId( );
// the event listeners for the new client
EventListeners* pNewListeners = new EventListeners( s_aMutex );
// note that we're using our own mutex here, so the listener containers for all
// our clients share this same mutex.
- // Shouldn't be any problem: the only situation where this is used is when the
- // thread is firing events, and there the mutex is locked, anyway.
+ // this is a reminiscense to the days where the notifier was asynchronous. Today this is
+ // completely nonsense, and potentially slowing down the Office me thinks ...
// add the client
- s_pNotifier->m_aClients.insert( ClientMap::value_type( nNewClientId, pNewListeners ) );
+ s_aClients.insert( ClientMap::value_type( nNewClientId, pNewListeners ) );
// outta here
return nNewClientId;
@@ -344,151 +150,49 @@ namespace comphelper
//---------------------------------------------------------------------
sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos )
{
- OSL_ENSURE( s_pNotifier, "AccessibleEventNotifier::implLookupClient: illegal call: thread not running!" );
- if ( !s_pNotifier )
- return sal_False;
-
// look up this client
- _rPos = s_pNotifier->m_aClients.find( _nClient );
- OSL_ENSURE( s_pNotifier->m_aClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" );
+ _rPos = s_aClients.find( _nClient );
+ OSL_ENSURE( s_aClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" );
- return ( s_pNotifier->m_aClients.end() != _rPos );
- }
-
- //---------------------------------------------------------------------
- void AccessibleEventNotifier::implRemoveEventsForClient( const TClientId _nClient,
- ::std::vector< Reference< XInterface > >& _rEnsureAlive )
- {
- OSL_ENSURE( s_pNotifier, "AccessibleEventNotifier::implRemoveEventsForClient: invalid call, save your documents before it crashes!" );
-
- EventQueue::iterator aEventLoop = s_pNotifier->m_aEvents.begin();
- while ( aEventLoop != s_pNotifier->m_aEvents.end() )
- {
- if ( _nClient == aEventLoop->first )
- {
- // this is an event queued for the same client
- // -> remove it from the queue
- EventQueue::iterator aErasePos( aEventLoop );
- ++aEventLoop;
-
- // keep the object alive until we can free our own mutex
- _rEnsureAlive.push_back( aErasePos->second.Source );
-
- // erase the event
- s_pNotifier->m_aEvents.erase( aErasePos );
- }
- else
- ++aEventLoop;
- }
- }
-
- //---------------------------------------------------------------------
- void AccessibleEventNotifier::implCleanupNotifier( )
- {
- OSL_PRECOND( s_pNotifier, "AccessibleEventNotifier::implCleanupNotifier: invalid call!" );
-
- if ( s_pNotifier->m_aClients.empty() && s_pNotifier->m_aDisposedClients.empty() )
- {
- // killing me softly ....
-
- // tell the instance it should terminate
- s_pNotifier->m_bTerminateRequested = sal_True;
-
- // awake it
- // (it is sleeping currently - if it were not, it would be in the section
- // guarded by s_aMutex (see <method>run</method>), which is impossible as
- // our thread here has this mutex currently ...
- s_pNotifier->m_aEventGuard.set();
-
- // reset the notifier holder - thus, the thread may continue to run the few microseconds
- // it will need to finally terminate, but if in the meantime new clients
- // are registered, we will not burden this (terminating) notifier with it,
- // but create a new one.
- // Note that the instance will delete itself in onTerminated
- s_pNotifier = NULL;
- }
-
- OSL_POSTCOND( !s_pNotifier || !s_pNotifier->m_aClients.empty() || !s_pNotifier->m_aDisposedClients.empty(),
- "AccessibleEventNotifier::implCleanupNotifier: post condition violated!" );
+ return ( s_aClients.end() != _rPos );
}
//---------------------------------------------------------------------
void AccessibleEventNotifier::revokeClient( const TClientId _nClient )
{
- // below, we will destroy some AccessibleEventObject instances
- // their Source member refers a foreign component (the broadcaster), which we
- // will release with this destruction. In case that is the _last_ release, it
- // would be potentially deadly if we call it while our own mutex is locked.
- // So we ensure that all these objects are alive _until_ our mutex is released.
-
- ::std::vector< Reference< XInterface > > aEnsureAlive;
-
- // ----- <mutex_lock> ---------------------------------------------
- {
- ::osl::MutexGuard aGuard( s_aMutex );
-
- ClientMap::iterator aClientPos;
- if ( !implLookupClient( _nClient, aClientPos ) )
- // already asserted in implLookupClient
- return;
-
- // remove it from the clients map
- delete aClientPos->second;
- s_pNotifier->m_aClients.erase( aClientPos );
-
- // remove any other events which are pending for this client
- implRemoveEventsForClient( _nClient, aEnsureAlive );
+ ::osl::MutexGuard aGuard( s_aMutex );
- // cleanup the thread if we do not have clients anymore
- implCleanupNotifier( );
- }
- // ----- </mutex_lock> ---------------------------------------------
+ ClientMap::iterator aClientPos;
+ if ( !implLookupClient( _nClient, aClientPos ) )
+ // already asserted in implLookupClient
+ return;
- // here, aEnsureAlive is cleared, and here it doesn't matter anymore if it's the last
- // reference to the contained components, as our mutex is not locked here ....
+ // remove it from the clients map
+ delete aClientPos->second;
+ s_aClients.erase( aClientPos );
}
//---------------------------------------------------------------------
void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient,
const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) )
{
- ::std::vector< Reference< XInterface > > aEnsureAlive;
+ ::osl::MutexGuard aGuard( s_aMutex );
- // ----- <mutex_lock> ---------------------------------------------
- {
- ::osl::MutexGuard aGuard( s_aMutex );
+ ClientMap::iterator aClientPos;
+ if ( !implLookupClient( _nClient, aClientPos ) )
+ // already asserted in implLookupClient
+ return;
- ClientMap::iterator aClientPos;
- if ( !implLookupClient( _nClient, aClientPos ) )
- // already asserted in implLookupClient
- return;
+ // notify the "disposing" event for this client
+ EventObject aDisposalEvent;
+ aDisposalEvent.Source = _rxEventSource;
- // move the client from the "regular clients" to the "disposed clients" map
- // from then on, no events for this client will be accepted anymore
- #ifdef _DEBUG
- ::std::pair< ClientMap::iterator, bool > aInsertResult =
- #endif
- s_pNotifier->m_aDisposedClients.insert( ClientMap::value_type( _nClient, aClientPos->second ) );
- OSL_ENSURE( aInsertResult.second, "AccessibleEventNotifier::revokeClientNotifyDisposing: client was already disposed!" );
- // is this asserts, then there already was an entry for _nClient in m_aDisposedClients, which means
- // somebody already called notifyDisposing with this id
- s_pNotifier->m_aClients.erase( aClientPos );
-
- // before we add the "disposing" event to the queue, we remove all other events for this client
- implRemoveEventsForClient( _nClient, aEnsureAlive );
-
- // push back a "disposing" event for this client
- AccessibleEventObject aDisposalEvent;
- aDisposalEvent.Source = _rxEventSource;
- aDisposalEvent.EventId = -1; // this indicates "disposal"
-
- // add the event to the queue
- implPushBackEvent( _nClient, aDisposalEvent );
- }
- // ----- </mutex_lock> --------------------------------------------
+ // now do the notification
+ aClientPos->second->disposeAndClear( aDisposalEvent );
- // here, aEnsureAlive is cleared, and here it doesn't matter anymore if it's the last
- // reference to the contained components, as our mutex is not locked here ....
+ // we do not need the entry in the clients map anymore
+ delete aClientPos->second;
+ s_aClients.erase( aClientPos );
}
//---------------------------------------------------------------------
@@ -542,38 +246,42 @@ namespace comphelper
//---------------------------------------------------------------------
void AccessibleEventNotifier::addEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent ) SAL_THROW( ( ) )
{
- ::osl::MutexGuard aGuard( s_aMutex );
-
- ClientMap::iterator aClientPos;
- if ( !implLookupClient( _nClient, aClientPos ) )
- // already asserted in implLookupClient
- return;
+ Sequence< Reference< XInterface > > aListeners;
- // add the event to the queue
- implPushBackEvent( _nClient, _rEvent );
- }
+ // --- <mutex lock> -------------------------------
+ {
+ ::osl::MutexGuard aGuard( s_aMutex );
- //---------------------------------------------------------------------
- void AccessibleEventNotifier::implPushBackEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent )
- {
- OSL_PRECOND( s_pNotifier, "AccessibleEventNotifier::implPushBackEvent: invalid call!" );
+ ClientMap::iterator aClientPos;
+ if ( !implLookupClient( _nClient, aClientPos ) )
+ // already asserted in implLookupClient
+ return;
- // add the event to the queue
- s_pNotifier->m_aEvents.push_back( ClientEvent( _nClient, _rEvent ) );
+ // since we're synchronous, again, we want to notify immediately
+ aListeners = aClientPos->second->getElements();
+ }
+ // --- </mutex lock> ------------------------------
- // wake up the thread
- s_pNotifier->m_aEventGuard.set();
+ // default handling: loop through all listeners, and notify them
+ const Reference< XInterface >* pListeners = aListeners.getConstArray();
+ const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength();
+ while ( pListeners != pListenersEnd )
+ {
+ try
+ {
+ static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( _rEvent );
+ }
+ catch( const Exception& e )
+ {
+ e;
+ // silent this
+ // no assertion, because a broken access remote bridge or something like this
+ // can cause this exception
+ }
+ ++pListeners;
+ }
}
//.........................................................................
} // namespace comphelper
//.........................................................................
-
-
-/*************************************************************************
- * history:
- * $Log: not supported by cvs2svn $
- *
- * Revision 1.0 05.12.2002 11:05:26 fs
- ************************************************************************/
-