From 170aaa64acb5e6a58b72c45aba3248f04ab0b1e2 Mon Sep 17 00:00:00 2001 From: "Frank Schoenheit [fs]" Date: Thu, 16 Sep 2010 14:25:54 +0200 Subject: dba34a: #i111148# do not call setPropertyValue from within setFastPropertyValue_NoBroadcast, this is prone to deadlocks. Instead, use the newly introduced setDependentFastPropertyValue, which postpones the notifications to a more appropriate point in time --- cppuhelper/source/propshlp.cxx | 105 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 8 deletions(-) (limited to 'cppuhelper/source/propshlp.cxx') diff --git a/cppuhelper/source/propshlp.cxx b/cppuhelper/source/propshlp.cxx index fe455781a1a7..84638494f2a7 100644 --- a/cppuhelper/source/propshlp.cxx +++ b/cppuhelper/source/propshlp.cxx @@ -32,6 +32,7 @@ #include "cppuhelper/implbase1.hxx" #include "cppuhelper/weak.hxx" #include "cppuhelper/propshlp.hxx" +#include "cppuhelper/exc_hlp.hxx" #include "com/sun/star/beans/PropertyAttribute.hpp" #include "com/sun/star/lang/DisposedException.hpp" @@ -144,15 +145,20 @@ sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString & Proper class OPropertySetHelper::Impl { public: - Impl ( bool i_bIgnoreRuntimeExceptionsWhileFiring, - IEventNotificationHook *i_pFireEvents) - : m_bIgnoreRuntimeExceptionsWhileFiring( - i_bIgnoreRuntimeExceptionsWhileFiring ), - m_pFireEvents( i_pFireEvents ) - { } + Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring, + IEventNotificationHook *i_pFireEvents + ) + :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring ) + ,m_pFireEvents( i_pFireEvents ) + { + } bool m_bIgnoreRuntimeExceptionsWhileFiring; class IEventNotificationHook * const m_pFireEvents; + + ::std::vector< sal_Int32 > m_handles; + ::std::vector< Any > m_newValues; + ::std::vector< Any > m_oldValues; }; @@ -432,6 +438,57 @@ void OPropertySetHelper::removeVetoableChangeListener( } } +void OPropertySetHelper::setDependentFastPropertyValue( sal_Int32 i_handle, const ::com::sun::star::uno::Any& i_value ) +{ + //OSL_PRECOND( rBHelper.rMutex.isAcquired(), "OPropertySetHelper::setDependentFastPropertyValue: to be called with a locked mutex only!" ); + // there is no such thing as Mutex.isAcquired, sadly ... + + sal_Int16 nAttributes(0); + IPropertyArrayHelper& rInfo = getInfoHelper(); + if ( !rInfo.fillPropertyMembersByHandle( NULL, &nAttributes, i_handle ) ) + // unknown property + throw UnknownPropertyException(); + + // no need to check for READONLY-ness of the property. The method is intended to be called internally, which + // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed + // to change their value. + + Any aConverted, aOld; + sal_Bool bChanged = convertFastPropertyValue( aConverted, aOld, i_handle, i_value ); + if ( !bChanged ) + return; + + // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be + // a good idea. The caler is responsible for not invoking this for constrained properties. + OSL_ENSURE( ( nAttributes & PropertyAttribute::CONSTRAINED ) == 0, + "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained properties!" ); + (void)nAttributes; + + // actually set the new value + try + { + setFastPropertyValue_NoBroadcast( i_handle, aConverted ); + } + catch (const UnknownPropertyException& ) { throw; /* allowed to leave */ } + catch (const PropertyVetoException& ) { throw; /* allowed to leave */ } + catch (const IllegalArgumentException& ) { throw; /* allowed to leave */ } + catch (const WrappedTargetException& ) { throw; /* allowed to leave */ } + catch (const RuntimeException& ) { throw; /* allowed to leave */ } + catch (const Exception& ) + { + // not allowed to leave this meathod + WrappedTargetException aWrapped; + aWrapped.TargetException <<= ::cppu::getCaughtException(); + aWrapped.Context = static_cast< XPropertySet* >( this ); + throw aWrapped; + } + + // remember the handle/values, for the events to be fired later + m_pReserved->m_handles.push_back( i_handle ); + m_pReserved->m_newValues.push_back( aConverted ); // TODO: setFastPropertyValue notifies the unconverted value here ...? + m_pReserved->m_oldValues.push_back( aOld ); +} + // XFastPropertySet void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue ) throw(::com::sun::star::beans::UnknownPropertyException, @@ -498,7 +555,7 @@ void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle, const Any& rVa // release guard to fire events } // file a change event, if the value changed - fire( &nHandle, &rValue, &aOldVal, 1, sal_False ); + impl_fireAll( &nHandle, &rValue, &aOldVal, 1 ); } } @@ -520,6 +577,38 @@ Any OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle ) return aRet; } +//-------------------------------------------------------------------------- +void OPropertySetHelper::impl_fireAll( sal_Int32* i_handles, const Any* i_newValues, const Any* i_oldValues, sal_Int32 i_count ) +{ + ClearableMutexGuard aGuard( rBHelper.rMutex ); + if ( m_pReserved->m_handles.empty() ) + { + aGuard.clear(); + fire( i_handles, i_newValues, i_oldValues, i_count, sal_False ); + return; + } + + const size_t additionalEvents = m_pReserved->m_handles.size(); + OSL_ENSURE( additionalEvents == m_pReserved->m_newValues.size() + && additionalEvents == m_pReserved->m_oldValues.size(), + "OPropertySetHelper::impl_fireAll: inconsistency!" ); + + ::std::vector< sal_Int32 > allHandles( additionalEvents + i_count ); + ::std::copy( m_pReserved->m_handles.begin(), m_pReserved->m_handles.end(), allHandles.begin() ); + ::std::copy( i_handles, i_handles + i_count, allHandles.begin() + additionalEvents ); + + ::std::vector< Any > allNewValues( additionalEvents + i_count ); + ::std::copy( m_pReserved->m_newValues.begin(), m_pReserved->m_newValues.end(), allNewValues.begin() ); + ::std::copy( i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents ); + + ::std::vector< Any > allOldValues( additionalEvents + i_count ); + ::std::copy( m_pReserved->m_oldValues.begin(), m_pReserved->m_oldValues.end(), allOldValues.begin() ); + ::std::copy( i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents ); + + aGuard.clear(); + fire( &allHandles[0], &allNewValues[0], &allOldValues[0], additionalEvents + i_count, sal_False ); +} + //-------------------------------------------------------------------------- void OPropertySetHelper::fire ( @@ -803,7 +892,7 @@ void OPropertySetHelper::setFastPropertyValues( } // fire change events - fire( pHandles, pConvertedValues, pOldValues, n, sal_False ); + impl_fireAll( pHandles, pConvertedValues, pOldValues, n ); } catch( ... ) { -- cgit From 13ff8d534e62802a315e21200732b74d726be3ca Mon Sep 17 00:00:00 2001 From: "Frank Schoenheit [fs]" Date: Fri, 17 Sep 2010 07:47:49 +0200 Subject: dba34a: impl_fireAll: oops ... don't forget to reset handles/newValues/oldValues ... --- cppuhelper/source/propshlp.cxx | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'cppuhelper/source/propshlp.cxx') diff --git a/cppuhelper/source/propshlp.cxx b/cppuhelper/source/propshlp.cxx index 84638494f2a7..e43f93272e16 100644 --- a/cppuhelper/source/propshlp.cxx +++ b/cppuhelper/source/propshlp.cxx @@ -605,6 +605,10 @@ void OPropertySetHelper::impl_fireAll( sal_Int32* i_handles, const Any* i_newVal ::std::copy( m_pReserved->m_oldValues.begin(), m_pReserved->m_oldValues.end(), allOldValues.begin() ); ::std::copy( i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents ); + m_pReserved->m_handles.clear(); + m_pReserved->m_newValues.clear(); + m_pReserved->m_oldValues.clear(); + aGuard.clear(); fire( &allHandles[0], &allNewValues[0], &allOldValues[0], additionalEvents + i_count, sal_False ); } -- cgit