diff options
Diffstat (limited to '')
-rw-r--r-- | framework/inc/threadhelp/gate.hxx | 149 | ||||
-rw-r--r-- | framework/inc/threadhelp/transactionguard.hxx | 51 | ||||
-rw-r--r-- | framework/inc/threadhelp/transactionmanager.hxx | 128 |
3 files changed, 328 insertions, 0 deletions
diff --git a/framework/inc/threadhelp/gate.hxx b/framework/inc/threadhelp/gate.hxx new file mode 100644 index 000000000..627a3a7cb --- /dev/null +++ b/framework/inc/threadhelp/gate.hxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_FRAMEWORK_INC_THREADHELP_GATE_HXX +#define INCLUDED_FRAMEWORK_INC_THREADHELP_GATE_HXX + +#include <osl/mutex.hxx> +#include <osl/conditn.hxx> + +namespace framework{ + +/*-************************************************************************************************************ + @short implement a gate to block multiple threads at the same time or unblock all + @descr A gate can be used as a negative-condition! You can open a "door" - wait() will not block ... + or you can close it - wait() blocks till open() is called again. + Then all currently waiting threads are running immediately - but new ones are blocked! + + @attention To prevent us against wrong using, the default ctor, copy ctor and the =operator are marked private! + + @devstatus ready to use +*//*-*************************************************************************************************************/ +class Gate +{ + + // public methods + + public: + + /*-**************************************************************************************************** + @short ctor + @descr These initialize the object right as an open gate. + *//*-*****************************************************************************************************/ + Gate() + : m_bClosed ( false ) + { + open(); + } + + /*-**************************************************************************************************** + @short dtor + @descr Is user forget it - we open the gate ... + blocked threads can running ... but I don't know + if it's right - we are destroyed yet!? + *//*-*****************************************************************************************************/ + ~Gate() + { + open(); + } + /*-**************************************************************************************************** + @short copy-ctor + @descr Forbid copy construction + *//*-*****************************************************************************************************/ + Gate(const Gate&) = delete; + /*-**************************************************************************************************** + @short copy-assignment + @descr Forbid copy assigning + *//*-*****************************************************************************************************/ + Gate& operator=(const Gate&) = delete; + + /*-**************************************************************************************************** + @short open the gate + @descr A wait() call will not block then. + + @seealso method close() + *//*-*****************************************************************************************************/ + void open() + { + // We must safe access to our internal member! + ::osl::MutexGuard aLock( m_aAccessLock ); + // Set condition -> wait don't block any longer -> gate is open + m_aPassage.set(); + // Check if operation was successful! + // Check returns false if condition isn't set => m_bClosed will be true then => we must return false; opening failed + m_bClosed = !m_aPassage.check(); + } + + /*-**************************************************************************************************** + @short close the gate + @descr A wait() call will block then. + + @seealso method open() + *//*-*****************************************************************************************************/ + void close() + { + // We must safe access to our internal member! + ::osl::MutexGuard aLock( m_aAccessLock ); + // Reset condition -> wait blocks now -> gate is closed + m_aPassage.reset(); + // Check if operation was successful! + // Check returns false if condition was reset => m_bClosed will be true then => we can return true; closing ok + m_bClosed = !m_aPassage.check(); + } + + /*-**************************************************************************************************** + @short must be called to pass the gate + @descr If gate "open" => wait() will not block. + If gate "closed" => wait() will block till somewhere open it again. + + @seealso method wait() + @seealso method open() + + *//*-*****************************************************************************************************/ + void wait() + { + // We must safe access to our internal member! + ::osl::ClearableMutexGuard aLock( m_aAccessLock ); + // If gate not closed - caller can pass it. + if( m_bClosed ) + { + // Then we must release used access lock - + // because next call will block... + // and if we hold the access lock nobody else can use this object without a deadlock! + aLock.clear(); + // Wait for opening gate... + m_aPassage.wait(); + } + } + + // private member + + private: + + ::osl::Mutex m_aAccessLock; + ::osl::Condition m_aPassage; + bool m_bClosed; + +}; // class Gate + +} // namespace framework + +#endif // INCLUDED_FRAMEWORK_INC_THREADHELP_GATE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/inc/threadhelp/transactionguard.hxx b/framework/inc/threadhelp/transactionguard.hxx new file mode 100644 index 000000000..2c4366cde --- /dev/null +++ b/framework/inc/threadhelp/transactionguard.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_FRAMEWORK_INC_THREADHELP_TRANSACTIONGUARD_HXX +#define INCLUDED_FRAMEWORK_INC_THREADHELP_TRANSACTIONGUARD_HXX + +#include <threadhelp/transactionmanager.hxx> + +namespace framework{ + +class TransactionGuard +{ + public: + TransactionGuard( TransactionManager& rManager, EExceptionMode eMode ) + : m_pManager( &rManager ) + { + m_pManager->registerTransaction( eMode ); + } + + ~TransactionGuard() + { + m_pManager->unregisterTransaction(); + } + TransactionGuard(const TransactionGuard&) = delete; + TransactionGuard& operator=(const TransactionGuard&) = delete; + + private: + TransactionManager* m_pManager; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/inc/threadhelp/transactionmanager.hxx b/framework/inc/threadhelp/transactionmanager.hxx new file mode 100644 index 000000000..9dbdc3b38 --- /dev/null +++ b/framework/inc/threadhelp/transactionmanager.hxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_FRAMEWORK_INC_THREADHELP_TRANSACTIONMANAGER_HXX +#define INCLUDED_FRAMEWORK_INC_THREADHELP_TRANSACTIONMANAGER_HXX + +#include <config_options.h> +#include <threadhelp/gate.hxx> + +#include <osl/mutex.hxx> +#include <fwidllapi.h> + +namespace framework{ + +/*-************************************************************************************************************ + @descr Describe different states of a feature of following implementation. + During lifetime of an object different working states occur: + initialization - working - closing - closed + If you wish to implement thread safe classes you should use this feature to protect + your code against calls at wrong time. e.g. you are not full initialized but somewhere + call an interface method (initialize phase means startup time from creating object till + calling specified first method e.g. XInitialization::initialize()!) then you should refuse + this call. The same for closing/disposing the object! +*//*-*************************************************************************************************************/ +enum EWorkingMode +{ + E_INIT , // We stand in an init method -> some calls are accepted - some ones are rejected + E_WORK , // Object is ready for working -> all calls are accepted + E_BEFORECLOSE, // We stand in a close method -> some calls are accepted - some ones are rejected + E_CLOSE // Object is dead! -> all calls are rejected! +}; + +/*-************************************************************************************************************ + @descr A transaction object should support throwing exceptions if user used it at wrong working mode. + e.g. We can throw a DisposedException if user try to work and our mode is E_CLOSE! + But sometimes he doesn't need this feature - will handle it by himself. + Then we must differ between some exception-modi: + E_HARDEXCEPTIONS We throw exceptions for all working modes different from E_WORK! + E_SOFTEXCEPTIONS We throw exceptions for all working modes different from E_WORK AND E_INCLOSE! + This mode is useful for impl-methods which should be callable from dispose() method! + + e.g. void dispose() + { + m_aTransactionManager.setWorkingMode( E_BEFORECLOSE ); + ... + impl_setA( 0 ); + ... + m_aTransactionManager.setWorkingMode( E_CLOSE ); + } + + void impl_setA( int nA ) + { + ERejectReason EReason; + TransactionGuard aTransactionGuard( m_aTransactionManager, E_SOFTEXCEPTIONS, eReason ); + + m_nA = nA; + } + + Normally (if E_HARDEXCEPTIONS was used!) creation of guard + will throw an exception ... but using of E_SOFTEXCEPTIONS suppress it + and member "A" can be set. +*//*-*************************************************************************************************************/ +enum EExceptionMode +{ + E_HARDEXCEPTIONS, + E_SOFTEXCEPTIONS +}; + +/*-************************************************************************************************************ + @short implement a transaction manager to support non breakable interface methods + @descr Use it to support non breakable interface methods without using any thread + synchronization like e.g. mutex, rw-lock! + That protect your code against wrong calls at wrong time ... e.g. calls after disposing an object! + Use combination of EExceptionMode and ERejectReason to detect rejected requests + and react for it. You can enable automatically throwing of exceptions too. + + @devstatus draft +*//*-*************************************************************************************************************/ +class UNLESS_MERGELIBS(FWI_DLLPUBLIC) TransactionManager +{ + + // public methods + + public: + + TransactionManager ( ); + ~TransactionManager ( ); + TransactionManager(const TransactionManager&) = delete; + TransactionManager& operator=(const TransactionManager&) = delete; + void setWorkingMode ( EWorkingMode eMode ); + EWorkingMode getWorkingMode ( ) const; + /// @throws css::uno::RuntimeException + /// @throws css::lang::DisposedException + void registerTransaction ( EExceptionMode eMode ); + /// @throws css::uno::RuntimeException + /// @throws css::lang::DisposedException + void unregisterTransaction ( ); + + private: + + mutable ::osl::Mutex m_aAccessLock; /// regulate access on internal member of this instance + Gate m_aBarrier; /// used to block transactions requests during change or work mode + EWorkingMode m_eWorkingMode; /// current working mode of object which use this manager (used to reject calls at wrong time) + sal_Int32 m_nTransactionCount; /// every transaction request is registered by this counter + +}; // class TransactionManager + +} // namespace framework + +#endif // INCLUDED_FRAMEWORK_INC_THREADHELP_TRANSACTIONMANAGER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |