diff options
author | Tor Lillqvist <tml@collabora.com> | 2022-12-29 12:16:25 +0200 |
---|---|---|
committer | Tor Lillqvist <tml@collabora.com> | 2023-01-02 17:57:16 +0000 |
commit | 91526a2f53d5c7a703b9fc5fbc1728ee50854cc1 (patch) | |
tree | e2dd5ccb8972427fe2563e6e635c26281f97c044 | |
parent | 777df29e306be375c48c586855376bc25f4b85f4 (diff) |
Use std synchronisation APIs instead of a pipe
The immediate reason for this is that pipes are broken in the
Emscripten runtime, see
https://github.com/emscripten-core/emscripten/issues/13214. But if we
can drop the use of a pipe for other platforms, too, why not.
Without this, when attemting to run Collabora Online as WASM, I get:
Aborted(Assertion failed: nRet == 1, at: .../vcl/headless/svpinst.cxx,538,DoYield)
It is quite possible that the code could be simplified drastically. I
only replaced the use of a pipe with hopefully equivalent use of a
queue, a condition variable, and a mutex.
Change-Id: I9259ba36afeabce6474a1aec827d01bcbbd4412b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144944
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
Tested-by: Jenkins
-rw-r--r-- | vcl/headless/svpinst.cxx | 82 | ||||
-rw-r--r-- | vcl/inc/headless/svpinst.hxx | 9 |
2 files changed, 22 insertions, 69 deletions
diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx index 5a86826423e3..19eef8997689 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -22,9 +22,6 @@ #include <mutex> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> #include <pthread.h> #include <sys/time.h> #include <poll.h> @@ -76,14 +73,13 @@ do { \ #define DBG_TESTSVPYIELDMUTEX() ((void)0) #endif -#if !defined(ANDROID) && !defined(IOS) +#if !defined(ANDROID) && !defined(IOS) && !defined(EMSCRIPTEN) static void atfork_child() { if (SvpSalInstance::s_pDefaultInstance != nullptr) { - SvpSalInstance::s_pDefaultInstance->CloseWakeupPipe(false); - SvpSalInstance::s_pDefaultInstance->CreateWakeupPipe(false); + SvpSalInstance::s_pDefaultInstance->CloseWakeupPipe(); } } @@ -97,10 +93,9 @@ SvpSalInstance::SvpSalInstance( std::unique_ptr<SalYieldMutex> pMutex ) m_nTimeoutMS = 0; m_MainThread = osl::Thread::getCurrentIdentifier(); - CreateWakeupPipe(true); if( s_pDefaultInstance == nullptr ) s_pDefaultInstance = this; -#if !defined(ANDROID) && !defined(IOS) +#if !defined(ANDROID) && !defined(IOS) && !defined(EMSCRIPTEN) pthread_atfork(nullptr, nullptr, atfork_child); #endif } @@ -109,62 +104,16 @@ SvpSalInstance::~SvpSalInstance() { if( s_pDefaultInstance == this ) s_pDefaultInstance = nullptr; - CloseWakeupPipe(true); + CloseWakeupPipe(); } -void SvpSalInstance::CloseWakeupPipe(bool log) +void SvpSalInstance::CloseWakeupPipe() { SvpSalYieldMutex *const pMutex(dynamic_cast<SvpSalYieldMutex*>(GetYieldMutex())); if (!pMutex) return; - if (pMutex->m_FeedbackFDs[0] != -1) - { - if (log) - { - SAL_INFO("vcl.headless", "CloseWakeupPipe: Closing inherited feedback pipe: [" << pMutex->m_FeedbackFDs[0] << "," << pMutex->m_FeedbackFDs[1] << "]"); - } - close (pMutex->m_FeedbackFDs[0]); - close (pMutex->m_FeedbackFDs[1]); - pMutex->m_FeedbackFDs[0] = pMutex->m_FeedbackFDs[1] = -1; - } -} - -void SvpSalInstance::CreateWakeupPipe(bool log) -{ - SvpSalYieldMutex *const pMutex(dynamic_cast<SvpSalYieldMutex*>(GetYieldMutex())); - if (!pMutex) - return; - if (pipe (pMutex->m_FeedbackFDs) == -1) - { - if (log) - { - SAL_WARN("vcl.headless", "Could not create feedback pipe: " << strerror(errno)); - std::abort(); - } - } - else - { - if (log) - { - SAL_INFO("vcl.headless", "CreateWakeupPipe: Created feedback pipe: [" << pMutex->m_FeedbackFDs[0] << "," << pMutex->m_FeedbackFDs[1] << "]"); - } - - int flags; - - // set close-on-exec descriptor flag. - if ((flags = fcntl (pMutex->m_FeedbackFDs[0], F_GETFD)) != -1) - { - flags |= FD_CLOEXEC; - (void) fcntl(pMutex->m_FeedbackFDs[0], F_SETFD, flags); - } - if ((flags = fcntl (pMutex->m_FeedbackFDs[1], F_GETFD)) != -1) - { - flags |= FD_CLOEXEC; - (void) fcntl(pMutex->m_FeedbackFDs[1], F_SETFD, flags); - } - - // retain the default blocking I/O for feedback pipe - } + while (!pMutex->m_FeedbackPipe.empty()) + pMutex->m_FeedbackPipe.pop(); } void SvpSalInstance::TriggerUserEventProcessing() @@ -328,9 +277,6 @@ void SvpSalInstance::ProcessEvent( SalUserEvent aEvent ) SvpSalYieldMutex::SvpSalYieldMutex() { -#ifndef IOS - m_FeedbackFDs[0] = m_FeedbackFDs[1] = -1; -#endif } SvpSalYieldMutex::~SvpSalYieldMutex() @@ -367,11 +313,11 @@ void SvpSalYieldMutex::doAcquire(sal_uInt32 const nLockCount) m_bNoYieldLock = true; bool const bEvents = pInst->DoYield(false, request == SvpRequest::MainThreadDispatchAllEvents); m_bNoYieldLock = false; - if (write(m_FeedbackFDs[1], &bEvents, sizeof(bool)) != sizeof(bool)) { - SAL_WARN("vcl.headless", "Could not write: " << strerror(errno)); - std::abort(); + std::lock_guard lock(m_FeedbackMutex); + m_FeedbackPipe.push(bEvents); } + m_FeedbackCV.notify_all(); } } while (true); @@ -534,8 +480,12 @@ bool SvpSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) : SvpRequest::MainThreadDispatchOneEvent); // blocking read (for synchronisation) - auto const nRet = read(pMutex->m_FeedbackFDs[0], &bWasEvent, sizeof(bool)); - assert(nRet == 1); (void) nRet; + { + std::unique_lock lock(pMutex->m_FeedbackMutex); + pMutex->m_FeedbackCV.wait(lock, [pMutex] { return !pMutex->m_FeedbackPipe.empty(); }); + bWasEvent = pMutex->m_FeedbackPipe.front(); + pMutex->m_FeedbackPipe.pop(); + } if (!bWasEvent && bWait) { // block & release YieldMutex until the main thread does something diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx index e9aada5bc001..efe32761f5c1 100644 --- a/vcl/inc/headless/svpinst.hxx +++ b/vcl/inc/headless/svpinst.hxx @@ -29,6 +29,8 @@ #include <unx/genprn.h> #include <condition_variable> +#include <mutex> +#include <queue> #include <sys/time.h> @@ -66,7 +68,9 @@ private: // 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]; + std::mutex m_FeedbackMutex; + std::queue<bool> m_FeedbackPipe; + std::condition_variable m_FeedbackCV; osl::Condition m_NonMainWaitingYieldCond; // members for communication from non-main thread to main thread bool m_bNoYieldLock = false; // accessed only on main thread @@ -104,8 +108,7 @@ public: SvpSalInstance( std::unique_ptr<SalYieldMutex> pMutex ); virtual ~SvpSalInstance() override; - void CloseWakeupPipe(bool log); - void CreateWakeupPipe(bool log); + void CloseWakeupPipe(); void Wakeup(SvpRequest request = SvpRequest::NONE); void StartTimer( sal_uInt64 nMS ); |