summaryrefslogtreecommitdiff
path: root/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'extensions')
-rw-r--r--extensions/source/update/check/updatecheck.cxx151
-rw-r--r--extensions/source/update/check/updatecheck.hxx15
-rw-r--r--extensions/source/update/check/updatecheckjob.cxx28
3 files changed, 150 insertions, 44 deletions
diff --git a/extensions/source/update/check/updatecheck.cxx b/extensions/source/update/check/updatecheck.cxx
index e7309e4a4725..348ef35faaca 100644
--- a/extensions/source/update/check/updatecheck.cxx
+++ b/extensions/source/update/check/updatecheck.cxx
@@ -215,12 +215,15 @@ class UpdateCheckThread : public WorkerThread
public:
UpdateCheckThread( osl::Condition& rCondition,
- const uno::Reference<uno::XComponentContext>& xContext );
+ const uno::Reference<uno::XComponentContext>& xContext,
+ rtl::Reference<UpdateCheck> const & controller );
virtual void SAL_CALL join() override;
virtual void SAL_CALL terminate() override;
virtual void cancel() override;
+ void cancelAsSoonAsPossible();
+
protected:
virtual ~UpdateCheckThread() override;
@@ -266,6 +269,8 @@ protected:
private:
const uno::Reference<uno::XComponentContext> m_xContext;
uno::Reference<deployment::XUpdateInformationProvider> m_xProvider;
+ rtl::Reference<UpdateCheck> m_controller;
+ bool m_cancelAsSoonAsPossible;
};
@@ -273,7 +278,7 @@ class ManualUpdateCheckThread : public UpdateCheckThread
{
public:
ManualUpdateCheckThread( osl::Condition& rCondition, const uno::Reference<uno::XComponentContext>& xContext ) :
- UpdateCheckThread(rCondition, xContext) {};
+ UpdateCheckThread(rCondition, xContext, {}) {};
virtual void SAL_CALL run() override;
};
@@ -334,9 +339,12 @@ private:
UpdateCheckThread::UpdateCheckThread( osl::Condition& rCondition,
- const uno::Reference<uno::XComponentContext>& xContext ) :
+ const uno::Reference<uno::XComponentContext>& xContext,
+ rtl::Reference<UpdateCheck> const & controller ) :
m_aCondition(rCondition),
- m_xContext(xContext)
+ m_xContext(xContext),
+ m_controller(controller),
+ m_cancelAsSoonAsPossible(false)
{
createSuspended();
@@ -382,6 +390,13 @@ UpdateCheckThread::cancel()
xProvider->cancel();
}
+void UpdateCheckThread::cancelAsSoonAsPossible() {
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_cancelAsSoonAsPossible = true;
+ }
+ m_aCondition.set();
+}
bool
UpdateCheckThread::runCheck( bool & rbExtensionsChecked )
@@ -442,6 +457,12 @@ UpdateCheckThread::run()
// Initial wait to avoid doing further time consuming tasks during start-up
aResult = m_aCondition.wait(&tv);
+ {
+ osl::MutexGuard g(m_aMutex);
+ if (m_cancelAsSoonAsPossible) {
+ goto done;
+ }
+ }
try {
bool bExtensionsChecked = false;
@@ -494,6 +515,12 @@ UpdateCheckThread::run()
// This can not be > 32 Bit for now ..
tv.Seconds = static_cast< sal_Int32 > (next - systime.Seconds);
aResult = m_aCondition.wait(&tv);
+ {
+ osl::MutexGuard g(m_aMutex);
+ if (m_cancelAsSoonAsPossible) {
+ goto done;
+ }
+ }
continue;
}
}
@@ -516,6 +543,12 @@ UpdateCheckThread::run()
tv.Seconds = nRetryInterval[n-1];
aResult = m_aCondition.wait(&tv);
+ {
+ osl::MutexGuard g(m_aMutex);
+ if (m_cancelAsSoonAsPossible) {
+ goto done;
+ }
+ }
}
else // reset retry counter
{
@@ -529,6 +562,11 @@ UpdateCheckThread::run()
// Silently catch all errors
TOOLS_WARN_EXCEPTION("extensions.update", "Caught exception, thread terminated" );
}
+
+done:
+ if (m_controller.is()) {
+ m_controller->notifyUpdateCheckFinished();
+ }
}
@@ -705,6 +743,7 @@ UpdateCheck::UpdateCheck()
, m_pThread(nullptr)
, m_bHasExtensionUpdate(false)
, m_bShowExtUpdDlg(false)
+ , m_updateCheckRunning(false)
{
}
@@ -714,7 +753,7 @@ void
UpdateCheck::initialize(const uno::Sequence< beans::NamedValue >& rValues,
const uno::Reference<uno::XComponentContext>& xContext)
{
- osl::MutexGuard aGuard(m_aMutex);
+ std::scoped_lock aGuard(m_aMutex);
if( NOT_INITIALIZED == m_eState )
{
@@ -812,12 +851,12 @@ UpdateCheck::initialize(const uno::Sequence< beans::NamedValue >& rValues,
void
UpdateCheck::cancel()
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
WorkerThread *pThread = m_pThread;
UpdateState eUIState = getUIState(m_aUpdateInfo);
- aGuard.clear();
+ aGuard.unlock();
if( nullptr != pThread )
pThread->cancel();
@@ -829,10 +868,10 @@ UpdateCheck::cancel()
void
UpdateCheck::download()
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
UpdateInfo aInfo(m_aUpdateInfo);
State eState = m_eState;
- aGuard.clear();
+ aGuard.unlock();
if (aInfo.Sources.empty())
{
@@ -848,7 +887,7 @@ UpdateCheck::download()
shutdownThread(true);
{
- osl::MutexGuard aGuard2(m_aMutex);
+ std::scoped_lock aGuard2(m_aMutex);
enableDownload(true);
}
setUIState(UPDATESTATE_DOWNLOADING);
@@ -864,7 +903,7 @@ UpdateCheck::download()
void
UpdateCheck::install()
{
- osl::MutexGuard aGuard(m_aMutex);
+ std::scoped_lock aGuard(m_aMutex);
const uno::Reference< c3s::XSystemShellExecute > xShellExecute = c3s::SystemShellExecute::create( m_xContext );
@@ -908,13 +947,13 @@ UpdateCheck::install()
void
UpdateCheck::pause()
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
if( nullptr != m_pThread )
m_pThread->suspend();
rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext);
- aGuard.clear();
+ aGuard.unlock();
rModel->storeDownloadPaused(true);
setUIState(UPDATESTATE_DOWNLOAD_PAUSED);
@@ -924,13 +963,13 @@ UpdateCheck::pause()
void
UpdateCheck::resume()
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
if( nullptr != m_pThread )
m_pThread->resume();
rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext);
- aGuard.clear();
+ aGuard.unlock();
rModel->storeDownloadPaused(false);
setUIState(UPDATESTATE_DOWNLOADING);
@@ -940,26 +979,49 @@ UpdateCheck::resume()
void
UpdateCheck::closeAfterFailure()
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
if ( ( m_eState == DISABLED ) || ( m_eState == CHECK_SCHEDULED ) )
{
const UpdateState eUIState = getUIState( m_aUpdateInfo );
- aGuard.clear();
+ aGuard.unlock();
setUIState( eUIState, true );
}
}
+void UpdateCheck::notifyUpdateCheckFinished() {
+ std::scoped_lock l(m_aMutex);
+ m_updateCheckRunning = false;
+ m_updateCheckFinished.notify_all();
+}
+
+void UpdateCheck::waitForUpdateCheckFinished() {
+ UpdateCheckThread * thread;
+ {
+ std::scoped_lock l(m_aMutex);
+ thread = dynamic_cast<UpdateCheckThread *>(m_pThread);
+ }
+ if (thread != nullptr) {
+ thread->cancelAsSoonAsPossible();
+ }
+ for (;;) {
+ std::unique_lock lock(m_aMutex);
+ if (!m_updateCheckRunning) {
+ return;
+ }
+ m_updateCheckFinished.wait(lock);
+ }
+}
void
UpdateCheck::shutdownThread(bool join)
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
// copy thread object pointer to stack
osl::Thread *pThread = m_pThread;
m_pThread = nullptr;
- aGuard.clear();
+ aGuard.unlock();
if( nullptr != pThread )
{
@@ -978,7 +1040,10 @@ void
UpdateCheck::enableAutoCheck(bool enable)
{
if( enable )
- m_pThread = new UpdateCheckThread(m_aCondition, m_xContext);
+ {
+ m_updateCheckRunning = true;
+ m_pThread = new UpdateCheckThread(m_aCondition, m_xContext, this);
+ }
m_eState = enable ? CHECK_SCHEDULED : DISABLED;
}
@@ -1013,7 +1078,7 @@ UpdateCheck::enableDownload(bool enable, bool paused)
bool
UpdateCheck::downloadTargetExists(const OUString& rFileName)
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler());
UpdateState eUIState = UPDATESTATE_DOWNLOADING;
@@ -1045,7 +1110,7 @@ UpdateCheck::downloadTargetExists(const OUString& rFileName)
shutdownThread(false);
enableDownload(false);
- aGuard.clear();
+ aGuard.unlock();
setUIState(eUIState);
}
@@ -1055,7 +1120,7 @@ UpdateCheck::downloadTargetExists(const OUString& rFileName)
bool UpdateCheck::checkDownloadDestination( const OUString& rFileName )
{
- osl::MutexGuard aGuard(m_aMutex);
+ std::scoped_lock aGuard(m_aMutex);
rtl::Reference< UpdateHandler > aUpdateHandler( getUpdateHandler() );
@@ -1073,9 +1138,9 @@ bool UpdateCheck::checkDownloadDestination( const OUString& rFileName )
void
UpdateCheck::downloadStalled(const OUString& rErrorMessage)
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler());
- aGuard.clear();
+ aGuard.unlock();
aUpdateHandler->setErrorMessage(rErrorMessage);
setUIState(UPDATESTATE_ERROR_DOWNLOADING);
@@ -1085,9 +1150,9 @@ UpdateCheck::downloadStalled(const OUString& rErrorMessage)
void
UpdateCheck::downloadProgressAt(sal_Int8 nPercent)
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler());
- aGuard.clear();
+ aGuard.unlock();
aUpdateHandler->setProgress(nPercent);
setUIState(UPDATESTATE_DOWNLOADING);
@@ -1099,7 +1164,7 @@ UpdateCheck::downloadStarted(const OUString& rLocalFileName, sal_Int64 nFileSize
{
if ( nFileSize > 0 )
{
- osl::MutexGuard aGuard(m_aMutex);
+ std::scoped_lock aGuard(m_aMutex);
rtl::Reference< UpdateCheckConfig > aModel(UpdateCheckConfig::get(m_xContext));
aModel->storeLocalFileName(rLocalFileName, nFileSize);
@@ -1115,7 +1180,7 @@ UpdateCheck::downloadStarted(const OUString& rLocalFileName, sal_Int64 nFileSize
void
UpdateCheck::downloadFinished(const OUString& rLocalFileName)
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
// no more retries
m_pThread->terminate();
@@ -1123,7 +1188,7 @@ UpdateCheck::downloadFinished(const OUString& rLocalFileName)
m_aImageName = getImageFromFileName(rLocalFileName);
UpdateInfo aUpdateInfo(m_aUpdateInfo);
- aGuard.clear();
+ aGuard.unlock();
setUIState(UPDATESTATE_DOWNLOAD_AVAIL);
// Bring-up release note for position 2 ..
@@ -1139,7 +1204,7 @@ UpdateCheck::cancelDownload()
{
shutdownThread(true);
- osl::MutexGuard aGuard(m_aMutex);
+ std::scoped_lock aGuard(m_aMutex);
enableDownload(false);
rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext);
@@ -1163,7 +1228,7 @@ UpdateCheck::cancelDownload()
void
UpdateCheck::showDialog(bool forceCheck)
{
- osl::ResettableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
bool update_found = !m_aUpdateInfo.BuildId.isEmpty();
bool bSetUIState = ! m_aUpdateHandler.is();
@@ -1200,9 +1265,9 @@ UpdateCheck::showDialog(bool forceCheck)
if( bSetUIState )
{
- aGuard.clear();
+ aGuard.unlock();
setUIState(eDialogState, true); // suppress bubble as Dialog will be visible soon
- aGuard.reset();
+ aGuard.lock();
}
getUpdateHandler()->setVisible();
@@ -1224,7 +1289,7 @@ UpdateCheck::showDialog(bool forceCheck)
void
UpdateCheck::setUpdateInfo(const UpdateInfo& aInfo)
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
bool bSuppressBubble = aInfo.BuildId == m_aUpdateInfo.BuildId;
m_aUpdateInfo = aInfo;
@@ -1287,7 +1352,7 @@ UpdateCheck::setUpdateInfo(const UpdateInfo& aInfo)
rModel->clearUpdateFound();
}
- aGuard.clear();
+ aGuard.unlock();
setUIState(eUIState, bSuppressBubble);
}
@@ -1336,7 +1401,7 @@ void UpdateCheck::handleMenuBarUI( const rtl::Reference< UpdateHandler >& rUpdat
void UpdateCheck::setUIState(UpdateState eState, bool suppressBubble)
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
if( ! m_xMenuBarUI.is() &&
(DISABLED != m_eState) &&
@@ -1360,7 +1425,7 @@ void UpdateCheck::setUIState(UpdateState eState, bool suppressBubble)
UpdateInfo aUpdateInfo(m_aUpdateInfo);
OUString aImageName(m_aImageName);
- aGuard.clear();
+ aGuard.unlock();
handleMenuBarUI( aUpdateHandler, eState, suppressBubble );
@@ -1485,7 +1550,7 @@ void UpdateCheck::showExtensionDialog()
rtl::Reference<UpdateHandler>
UpdateCheck::getUpdateHandler()
{
- osl::MutexGuard aGuard(m_aMutex);
+ std::scoped_lock aGuard(m_aMutex);
if( ! m_aUpdateHandler.is() )
m_aUpdateHandler = new UpdateHandler(m_xContext, this);
@@ -1497,7 +1562,7 @@ UpdateCheck::getUpdateHandler()
uno::Reference< task::XInteractionHandler >
UpdateCheck::getInteractionHandler() const
{
- osl::MutexGuard aGuard(m_aMutex);
+ std::scoped_lock aGuard(m_aMutex);
uno::Reference< task::XInteractionHandler > xHandler;
@@ -1511,7 +1576,7 @@ UpdateCheck::getInteractionHandler() const
bool
UpdateCheck::isDialogShowing() const
{
- osl::MutexGuard aGuard(m_aMutex);
+ std::scoped_lock aGuard(m_aMutex);
return m_aUpdateHandler.is() && m_aUpdateHandler->isVisible();
};
@@ -1519,7 +1584,7 @@ UpdateCheck::isDialogShowing() const
void
UpdateCheck::autoCheckStatusChanged(bool enabled)
{
- osl::ClearableMutexGuard aGuard(m_aMutex);
+ std::unique_lock aGuard(m_aMutex);
if( (CHECK_SCHEDULED == m_eState) && !enabled )
shutdownThread(false);
@@ -1528,7 +1593,7 @@ UpdateCheck::autoCheckStatusChanged(bool enabled)
{
enableAutoCheck(enabled);
UpdateState eState = getUIState(m_aUpdateInfo);
- aGuard.clear();
+ aGuard.unlock();
setUIState(eState);
}
};
diff --git a/extensions/source/update/check/updatecheck.hxx b/extensions/source/update/check/updatecheck.hxx
index e50fa3859b0c..fbadbe82a03e 100644
--- a/extensions/source/update/check/updatecheck.hxx
+++ b/extensions/source/update/check/updatecheck.hxx
@@ -20,6 +20,11 @@
#ifndef INCLUDED_EXTENSIONS_SOURCE_UPDATE_CHECK_UPDATECHECK_HXX
#define INCLUDED_EXTENSIONS_SOURCE_UPDATE_CHECK_UPDATECHECK_HXX
+#include <sal/config.h>
+
+#include <condition_variable>
+#include <mutex>
+
#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/task/XInteractionHandler.hpp>
@@ -118,6 +123,10 @@ public:
void resume() override;
void closeAfterFailure() override;
+ void notifyUpdateCheckFinished();
+
+ void waitForUpdateCheckFinished();
+
private:
// Schedules or cancels next automatic check for updates
@@ -153,9 +162,10 @@ private:
State m_eState;
UpdateState m_eUpdateState;
- mutable osl::Mutex m_aMutex;
+ mutable std::recursive_mutex m_aMutex;
WorkerThread *m_pThread;
osl::Condition m_aCondition;
+ osl::Condition m_NotInWaitState;
UpdateInfo m_aUpdateInfo;
OUString m_aImageName;
@@ -166,6 +176,9 @@ private:
css::uno::Reference<css::beans::XPropertySet> m_xMenuBarUI;
css::uno::Reference<css::uno::XComponentContext> m_xContext;
+ bool m_updateCheckRunning = false;
+ std::condition_variable_any m_updateCheckFinished;
+
friend class UpdateCheckInitData;
};
diff --git a/extensions/source/update/check/updatecheckjob.cxx b/extensions/source/update/check/updatecheckjob.cxx
index d457269e9ca6..6da52c02fab6 100644
--- a/extensions/source/update/check/updatecheckjob.cxx
+++ b/extensions/source/update/check/updatecheckjob.cxx
@@ -25,6 +25,9 @@
#include "updateprotocol.hxx"
#include <memory>
+#include <mutex>
+#include <utility>
+
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/implementationentry.hxx>
#include <cppuhelper/supportsservice.hxx>
@@ -60,6 +63,9 @@ private:
uno::Sequence<beans::NamedValue> m_xParameters;
bool m_bShowDialog;
bool m_bTerminating;
+
+ std::mutex m_mutex;
+ rtl::Reference<UpdateCheck> m_controller;
};
class UpdateCheckJob :
@@ -125,6 +131,16 @@ void SAL_CALL InitUpdateCheckJobThread::run()
try {
rtl::Reference< UpdateCheck > aController( UpdateCheck::get() );
+ // At least for the automatic ("onFirstVisibleTask", i.e., !m_bShowDialog) check, wait for
+ // m_controller during setTerminating, to prevent m_controller from still having threads
+ // running during exit (ideally, we would make sure that all threads are joined before exit,
+ // but the UpdateCheck logic is rather convoluted, so play it safe for now and only address
+ // the automatic update check that is known to cause issues during `make check`, not the
+ // manually triggered update check scenario):
+ if (!m_bShowDialog) {
+ std::scoped_lock l(m_mutex);
+ m_controller = aController;
+ }
aController->initialize( m_xParameters, m_xContext );
if ( m_bShowDialog )
@@ -132,12 +148,24 @@ void SAL_CALL InitUpdateCheckJobThread::run()
} catch (const uno::Exception &) {
// fdo#64962 - don't bring the app down on some unexpected exception.
TOOLS_WARN_EXCEPTION("extensions.update", "Caught init update exception, thread terminated" );
+ {
+ std::scoped_lock l(m_mutex);
+ m_controller.clear();
+ }
}
}
void InitUpdateCheckJobThread::setTerminating() {
m_bTerminating = true;
m_aCondition.set();
+ rtl::Reference<UpdateCheck> controller;
+ {
+ std::scoped_lock l(m_mutex);
+ std::swap(controller, m_controller);
+ }
+ if (controller.is()) {
+ controller->waitForUpdateCheckFinished();
+ }
}
UpdateCheckJob::~UpdateCheckJob()