summaryrefslogtreecommitdiff
path: root/include/comphelper
diff options
context:
space:
mode:
authorMichael Stahl <mstahl@redhat.com>2016-07-26 23:42:36 +0200
committerMichael Stahl <mstahl@redhat.com>2016-07-29 10:05:47 +0000
commita2095b151409f0fb57aa8feaa4c6282f84040245 (patch)
tree08d70dc7853bb2eafa69bf3cb8c9eceb7df2e5fd /include/comphelper
parentb3b7669e7fb74b04d925f21a7f0b048434eeffa3 (diff)
comphelper,vcl: let DeInitVCL() join some AsyncEventNotifier threads
comphelper::AsyncEventNotifier is an amazing class that dispatches events in separate threads, no doubt implemented during times of exuberant optimism about the tractability of shared-state multi-threading. Unfortunately the authors forgot to think about how all those awesome threads will be joined, so if they are somehow blocked, then it may well happen that the events are dispatched when the main thread is already in DeInitVCL, and the objects required for the dispatching already smell somewhat funny. This happens quite reproducibly when changing dbaccess' ModelMethodGuard to lock the SolarMutex too, then CppunitTest_dbaccess_RowSetClones crashes in DeInitVCL() because one AsyncEventNotifier thread was blocked until then by SolarMutexGuard, and this test never Yields once its document is loaded. Try to fix this by joining the "DocumentEventNotifier" threads from DeInitVCL() itself. Since there's no rtl::WeakReference to go with rtl::Reference, refactor the AsyncEventNotifier and create a new AsyncEventNotifierAutoJoin that has to be used with std::shared_ptr and std::weak_ptr. Change-Id: I50a0749795acb04b0776e543f7125767b697ea35 Reviewed-on: https://gerrit.libreoffice.org/27581 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Michael Stahl <mstahl@redhat.com>
Diffstat (limited to 'include/comphelper')
-rw-r--r--include/comphelper/asyncnotification.hxx72
1 files changed, 61 insertions, 11 deletions
diff --git a/include/comphelper/asyncnotification.hxx b/include/comphelper/asyncnotification.hxx
index 2f33c236283c..a8439f8d36e7 100644
--- a/include/comphelper/asyncnotification.hxx
+++ b/include/comphelper/asyncnotification.hxx
@@ -95,25 +95,20 @@ namespace comphelper
events in the queue. As soon as you add an event, the thread is woken up, processes the event,
and sleeps again.
*/
- class COMPHELPER_DLLPUBLIC AsyncEventNotifier: public salhelper::Thread
+ class COMPHELPER_DLLPUBLIC AsyncEventNotifierBase
{
friend struct EventNotifierImpl;
- private:
+ protected:
std::unique_ptr<EventNotifierImpl> m_xImpl;
- SAL_DLLPRIVATE virtual ~AsyncEventNotifier();
+ SAL_DLLPRIVATE virtual ~AsyncEventNotifierBase();
// Thread
- SAL_DLLPRIVATE virtual void execute() override;
+ SAL_DLLPRIVATE virtual void execute();
public:
- /** constructs a notifier thread
-
- @param name the thread name, see ::osl_setThreadName; must not be
- null
- */
- AsyncEventNotifier(char const * name);
+ AsyncEventNotifierBase();
/** terminates the thread
@@ -123,7 +118,7 @@ namespace comphelper
itself, it will return immediately, and the thread will be terminated as soon as
the current notification is finished.
*/
- virtual void SAL_CALL terminate() override;
+ virtual void SAL_CALL terminate();
/** adds an event to the queue, together with the instance which is responsible for
processing it
@@ -143,6 +138,60 @@ namespace comphelper
void removeEventsForProcessor( const ::rtl::Reference< IEventProcessor >& _xProcessor );
};
+ /** This class is usable with rtl::Reference.
+ As always, the thread must be joined somewhere.
+ */
+ class COMPHELPER_DLLPUBLIC AsyncEventNotifier
+ : public AsyncEventNotifierBase
+ , public salhelper::Thread
+ {
+
+ private:
+ SAL_DLLPRIVATE virtual ~AsyncEventNotifier();
+
+ SAL_DLLPRIVATE virtual void execute() override;
+
+ public:
+ /** constructs a notifier thread
+
+ @param name the thread name, see ::osl_setThreadName; must not be
+ null
+ */
+ AsyncEventNotifier(char const* name);
+
+ virtual void SAL_CALL terminate() override;
+ };
+
+ /** This is a hack (when proper joining is not possible), use of which
+ should be avoided by good design.
+ */
+ class COMPHELPER_DLLPUBLIC AsyncEventNotifierAutoJoin
+ : public AsyncEventNotifierBase
+ , private osl::Thread
+ {
+
+ private:
+ SAL_DLLPRIVATE AsyncEventNotifierAutoJoin(char const* name);
+
+ SAL_DLLPRIVATE virtual void SAL_CALL run() override;
+ SAL_DLLPRIVATE virtual void SAL_CALL onTerminated() override;
+
+ public:
+ // only public so shared_ptr finds it
+ SAL_DLLPRIVATE virtual ~AsyncEventNotifierAutoJoin();
+
+ static std::shared_ptr<AsyncEventNotifierAutoJoin>
+ newAsyncEventNotifierAutoJoin(char const* name);
+
+ virtual void SAL_CALL terminate() override;
+
+ using osl::Thread::join;
+ using osl::Thread::operator new;
+ using osl::Thread::operator delete; // clang really wants this?
+
+ static void launch(std::shared_ptr<AsyncEventNotifierAutoJoin> const&);
+ };
+
//= EventHolder
@@ -166,6 +215,7 @@ namespace comphelper
inline const EventObjectType& getEventObject() const { return m_aEvent; }
};
+ COMPHELPER_DLLPUBLIC void JoinAsyncEventNotifiers();
} // namespace comphelper