summaryrefslogtreecommitdiff
path: root/vcl/inc/headless
diff options
context:
space:
mode:
authorMichael Stahl <mstahl@redhat.com>2018-02-23 13:19:01 +0100
committerMichael Stahl <mstahl@redhat.com>2018-02-26 13:44:00 +0100
commit0efd06de8fca4036c4132b2745a11273b1755df2 (patch)
treea3c6094ed42b59aecc700e3b44f8e0867fcdb489 /vcl/inc/headless
parent238c6a45e02c8a0a3f462ab493c5d58b3d8f075f (diff)
vcl: fix hangs in SvpSalInstance
Since commit cb8bfa9a32799bcde4e960fa56e388d5f7b2a928 the main thread will read from the timer pipe until it is empty. But evidently this introduces the problem that the poll() in another thread will not return, as the file descriptor will no longer be readable; see https://paste.debian.net/1011306/ for a reproducer of that rather under-documented poll behaviour. So other threads can get stuck forever in poll, and then the main thread can block in poll too with no other thread to wake it up. This is the problem that plagues UITest_writerperfect_epubexport. The timer pipe is difficult to fix, since the main thread can block on either the poll or the subsequent AcquireYieldMutex(). So replace the timer pipe with a condition etc. that is mostly copied from the OSX AquaSalInstance/SalYieldMutex implementation. The main thread now does something different than the other threads, and blocks on a condition_variable with a timeout, while other threads still block on acquiring the mutex. Non-main threads can poke the main thread to do a DoYield() on their behalf, and then get the result back with a blocking read from a pipe, all while holding the YieldMutex. This requires some fudging of the YieldMutex so that the main thread can borrow the ownership temporarily. Unfortunately SvpSalInstance, in addition to being directly instantiable for --headless, has a whole bunch of subclasses: * HeadlessSalInstance * AndroidSalInstance * IosSalInstance * GtkInstance (in the gtk3 case) * KDE5SalInstance Of these GtkInstance overrides everything related to the DoYield/SalYieldMutex implementation, but the others will be affected by the change. This commit will probably break IOS due to me not understanding the point of the undocumented random #ifdef IOS in svpinst.cxx. Change-Id: I1bbb143952dda89579e97ac32cd147e5b987573c Reviewed-on: https://gerrit.libreoffice.org/50237 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Michael Stahl <mstahl@redhat.com>
Diffstat (limited to 'vcl/inc/headless')
-rw-r--r--vcl/inc/headless/svpinst.hxx48
1 files changed, 43 insertions, 5 deletions
diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx
index ba80960326dc..6027b2b4d683 100644
--- a/vcl/inc/headless/svpinst.hxx
+++ b/vcl/inc/headless/svpinst.hxx
@@ -22,6 +22,7 @@
#include <osl/mutex.hxx>
#include <osl/thread.hxx>
+#include <osl/conditn.hxx>
#include <salinst.hxx>
#include <salwtype.hxx>
#include <saltimer.hxx>
@@ -30,6 +31,7 @@
#include <unx/genprn.h>
#include <list>
+#include <condition_variable>
#include <time.h>
@@ -56,19 +58,55 @@ public:
class SvpSalFrame;
class GenPspGraphics;
+enum class SvpRequest
+{
+ NONE,
+ MainThreadDispatchOneEvent,
+ MainThreadDispatchAllEvents,
+};
+
+class SvpSalYieldMutex : public SalYieldMutex
+{
+private:
+ // note: these members might as well live in SvpSalInstance, but there is
+ // at least one subclass of SvpSalInstance (GTK3) that doesn't use them.
+ friend class SvpSalInstance;
+ // members for communication from main thread to non-main thread
+ int m_FeedbackFDs[2];
+ osl::Condition m_NonMainWaitingYieldCond;
+ // members for communication from non-main thread to main thread
+ bool m_bNoYieldLock = false; // accessed only on main thread
+ std::mutex m_WakeUpMainMutex; // guard m_wakeUpMain & m_Request
+ std::condition_variable m_WakeUpMainCond;
+ bool m_wakeUpMain = false;
+ SvpRequest m_Request = SvpRequest::NONE;
+
+protected:
+ virtual void doAcquire( sal_uInt32 nLockCount ) override;
+ virtual sal_uInt32 doRelease( bool bUnlockAll ) override;
+
+public:
+ SvpSalYieldMutex();
+ virtual ~SvpSalYieldMutex() override;
+
+ virtual bool IsCurrentThread() const override;
+
+};
+
SalInstance* svp_create_SalInstance();
+// NOTE: the functions IsMainThread, DoYield and Wakeup *require* the use of
+// SvpSalYieldMutex; if a subclass uses something else it must override these
+// (Wakeup is only called by SvpSalTimer and SvpSalFrame)
class VCL_DLLPUBLIC SvpSalInstance : public SalGenericInstance, public SalUserEventList
{
timeval m_aTimeout;
sal_uLong m_nTimeoutMS;
- int m_pTimeoutFDS[2];
-
- void DoReleaseYield( int nTimeoutMS );
+ oslThreadIdentifier m_MainThread;
virtual void TriggerUserEventProcessing() override;
virtual void ProcessEvent( SalUserEvent aEvent ) override;
- void Wakeup();
+ void Wakeup(SvpRequest request = SvpRequest::NONE);
public:
static SvpSalInstance* s_pDefaultInstance;
@@ -132,7 +170,7 @@ public:
// and timer
virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents) override;
virtual bool AnyInput( VclInputFlags nType ) override;
- virtual bool IsMainThread() const override { return true; }
+ virtual bool IsMainThread() const override;
// may return NULL to disable session management
virtual SalSession* CreateSalSession() override;