[Libreoffice-commits] online.git: Branch 'distro/collabora/collabora-online-4' - 7 commits - common/MessageQueue.hpp kit/ForKit.cpp kit/Kit.cpp kit/TestStubs.cpp net/Socket.hpp test/helpers.hpp test/Makefile.am test/test.cpp

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Fri May 10 16:37:38 UTC 2019


 common/MessageQueue.hpp |   16 ++++
 kit/ForKit.cpp          |    6 +
 kit/Kit.cpp             |  182 ++++++++++++++++++++++++++++++++++++++----------
 kit/TestStubs.cpp       |   21 +++++
 net/Socket.hpp          |   10 +-
 test/Makefile.am        |    2 
 test/helpers.hpp        |   21 +++--
 test/test.cpp           |    4 -
 8 files changed, 212 insertions(+), 50 deletions(-)

New commits:
commit 95ceb19aa49e27bc0f7aaa50c88b614673df4123
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri May 10 17:25:18 2019 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri May 10 17:25:31 2019 +0100

    test: better zombie handling for more recent kernels.
    
    Change-Id: I2ae0bcc4c42100ee08ee3fcf68cb7022f38aed7b

diff --git a/test/test.cpp b/test/test.cpp
index 5ee19cf12..9745dda00 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -198,10 +198,10 @@ std::vector<int> getProcPids(const char* exec_filename, bool ignoreZombies = tru
                     {
                         switch (tokens[2].c_str()[0])
                         {
-                            // Dead marker for old and new kernels.
+                        // Dead & zombie markers for old and new kernels.
                         case 'x':
                         case 'X':
-                            // Don't ignore zombies.
+                        case 'Z':
                             break;
                         default:
                             pids.push_back(pid);
commit 4308f138d7c0f3392103b66d08d8fcbc35531b8e
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri May 10 16:45:01 2019 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri May 10 16:45:01 2019 +0100

    unipoll: restore missing asserts & some cleanup.
    
    Change-Id: I4277b5e044ead54d91bc834ea05bec649a608678

diff --git a/common/MessageQueue.hpp b/common/MessageQueue.hpp
index d281fcedf..66a3131c3 100644
--- a/common/MessageQueue.hpp
+++ b/common/MessageQueue.hpp
@@ -83,7 +83,7 @@ public:
     Payload pop()
     {
         std::unique_lock<std::mutex> lock(_mutex);
-        if (!_queue.size())
+        if (_queue.empty())
             return Payload();
         return get_impl();
     }
@@ -92,7 +92,7 @@ public:
     bool isEmpty()
     {
         std::unique_lock<std::mutex> lock(_mutex);
-        return _queue.size() == 0;
+        return _queue.empty();
     }
 
     /// Thread safe removal of all the pending messages.
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 505d95e86..dbab15d08 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -375,7 +375,7 @@ void ServerSocket::dumpState(std::ostream& os)
 void SocketDisposition::execute()
 {
     // We should have hard ownership of this socket.
-    // assert(_socket->getThreadOwner() == std::this_thread::get_id());
+    assert(_socket->getThreadOwner() == std::this_thread::get_id());
     if (_socketMove)
     {
         // Drop pretentions of ownership before _socketMove.
diff --git a/net/Socket.hpp b/net/Socket.hpp
index c73ace9ec..2fcc124d7 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -470,7 +470,7 @@ public:
                     Log::to_string(_owner) << " (" << Util::getThreadId() <<
                     ") but called from " << std::this_thread::get_id() << ", stop: " << _stop);
 
-        // assert(_stop || sameThread);
+        assert(_stop || sameThread);
     }
 
     /// Poll the sockets for available data to read or buffer to write.
commit cca1b968cc68cfd68b7cf4d6417bfbb0302c385d
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Mon May 6 20:02:52 2019 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri May 10 15:42:19 2019 +0100

    tests: re-factor PNG save to allow easy re-use elsewhere.
    
    Change-Id: Ic24f67d9a078ae49fa4ac187cc924fe36f482879

diff --git a/test/helpers.hpp b/test/helpers.hpp
index ccd29824d..0ee9f451d 100644
--- a/test/helpers.hpp
+++ b/test/helpers.hpp
@@ -586,6 +586,20 @@ inline void sendText(std::shared_ptr<LOOLWebSocket>& socket, const std::string&
     }
 }
 
+inline void saveTileAs(const std::vector<char> &tileResponse,
+                       const std::string &filename,
+                       const std::string &testname)
+{
+    const std::string firstLine = LOOLProtocol::getFirstLine(tileResponse);
+    std::vector<char> res(tileResponse.begin() + firstLine.size() + 1, tileResponse.end());
+    std::stringstream streamRes;
+    std::copy(res.begin(), res.end(), std::ostream_iterator<char>(streamRes));
+    std::fstream outStream(filename, std::ios::out);
+    outStream.write(res.data(), res.size());
+    outStream.close();
+    TST_LOG("Saved [" << firstLine << "] to [" << filename << "]");
+}
+
 inline std::vector<char> getTileAndSave(std::shared_ptr<LOOLWebSocket>& socket,
                                         const std::string& req,
                                         const std::string& filename,
@@ -603,12 +617,7 @@ inline std::vector<char> getTileAndSave(std::shared_ptr<LOOLWebSocket>& socket,
     std::copy(res.begin(), res.end(), std::ostream_iterator<char>(streamRes));
 
     if (!filename.empty())
-    {
-        std::fstream outStream(filename, std::ios::out);
-        outStream.write(res.data(), res.size());
-        outStream.close();
-        TST_LOG("Saved [" << firstLine << "] to [" << filename << "]");
-    }
+        saveTileAs(tile, filename, testname);
 
     return res;
 }
commit b3149b9c1b67ca775933d13a36ed84057c24c3f9
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat May 4 14:51:14 2019 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri May 10 15:42:19 2019 +0100

    Unipoll: terminate repeated polling loop on wakeup.
    
    Wakeup wakes up the nested SocketPoll::poll nicely, but that's no
    use if we immediately ignore that and re-poll, so shorten the
    timeout in this case.
    
    Change-Id: I927d2375b92c9ce6c6ebe3f0ab33e2863894e2ef

diff --git a/common/MessageQueue.hpp b/common/MessageQueue.hpp
index 91fbe5096..d281fcedf 100644
--- a/common/MessageQueue.hpp
+++ b/common/MessageQueue.hpp
@@ -88,6 +88,13 @@ public:
         return get_impl();
     }
 
+    /// Anything in the queue ?
+    bool isEmpty()
+    {
+        std::unique_lock<std::mutex> lock(_mutex);
+        return _queue.size() == 0;
+    }
+
     /// Thread safe removal of all the pending messages.
     void clear()
     {
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 4a47259fa..dfa80055e 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -1992,15 +1992,18 @@ private:
     }
 
 public:
+    bool hasQueued()
+    {
+        return !_tileQueue->isEmpty();
+    }
+
     void drainQueue(const std::chrono::steady_clock::time_point &now)
     {
         try
         {
-            while (true)
+            while (hasQueued())
             {
                 const TileQueue::Payload input = _tileQueue->pop();
-                if (input.size() <= 0)
-                    break;
 
                 LOG_TRC("Kit Recv " << LOOLProtocol::getAbbreviatedMessage(input));
 
@@ -2338,77 +2341,99 @@ void documentViewCallback(const int type, const char* payload, void* data)
     Document::ViewCallback(type, payload, data);
 }
 
-/// Called by LOK main-loop the central location for data processing.
-int pollCallback(void* pData, int timeoutUs)
+class KitSocketPoll : public SocketPoll
 {
-    if (!pData)
-        return 0;
-
-    if (TerminationFlag)
+    std::chrono::steady_clock::time_point _pollEnd;
+public:
+    KitSocketPoll() :
+        SocketPoll("kit")
     {
-        LOG_TRC("Termination of unipoll mainloop flagged");
-        return -1;
     }
 
-    // The maximum number of extra events to process beyond the first.
-    int maxExtraEvents = 15;
-    int eventsSignalled = 0;
-
-    int timeoutMs = timeoutUs / 1000;
+    // process pending message-queue events.
+    void drainQueue(const std::chrono::steady_clock::time_point &now)
+    {
+        if (document)
+            document->drainQueue(now);
+    }
 
-    SocketPoll* pSocketPoll = reinterpret_cast<SocketPoll*>(pData);
-    if (timeoutMs < 0)
+    // called from inside poll, inside a wakeup
+    void wakeupHook()
     {
-        // Flush at most 1 + maxExtraEvents, or return when nothing left.
-        while (pSocketPoll->poll(0) > 0 && maxExtraEvents-- > 0)
-            ++eventsSignalled;
+        _pollEnd = std::chrono::steady_clock::now();
     }
-    else
+
+    // a LOK compatible poll function merging the functions.
+    // returns the number of events signalled
+    int kitPoll(int timeoutUs)
     {
-        const auto startTime = std::chrono::steady_clock::now();
-        do
+        if (TerminationFlag)
+        {
+            LOG_TRC("Termination of unipoll mainloop flagged");
+            return -1;
+        }
+
+        // The maximum number of extra events to process beyond the first.
+        int maxExtraEvents = 15;
+        int eventsSignalled = 0;
+
+        int timeoutMs = timeoutUs / 1000;
+
+        if (timeoutMs < 0)
+        {
+            // Flush at most 1 + maxExtraEvents, or return when nothing left.
+            while (poll(0) > 0 && maxExtraEvents-- > 0)
+                ++eventsSignalled;
+        }
+        else
         {
             // Flush at most maxEvents+1, or return when nothing left.
-            if (pSocketPoll->poll(timeoutMs) <= 0)
-                break;
+            _pollEnd = std::chrono::steady_clock::now() + std::chrono::microseconds(timeoutUs);
+            do
+            {
+                if (poll(timeoutMs) <= 0)
+                    break;
 
-            const auto now = std::chrono::steady_clock::now();
-            const auto elapsedTimeMs
-                = std::chrono::duration_cast<std::chrono::milliseconds>(now - startTime)
-                .count();
-            if (elapsedTimeMs >= timeoutMs)
-                break;
+                const auto now = std::chrono::steady_clock::now();
+                drainQueue(now);
 
-            timeoutMs -= elapsedTimeMs;
-            ++eventsSignalled;
+                timeoutMs = std::chrono::duration_cast<std::chrono::milliseconds>(_pollEnd - now).count();
+                ++eventsSignalled;
+            }
+            while (timeoutMs > 0 && !TerminationFlag && maxExtraEvents-- > 0);
         }
-        while (!TerminationFlag && maxExtraEvents-- > 0);
-    }
 
-    if (document)
-        document->drainQueue(std::chrono::steady_clock::now());
+        drainQueue(std::chrono::steady_clock::now());
 
 #if !MOBILEAPP
-    if (document && document->purgeSessions() == 0)
-    {
-        LOG_INF("Last session discarded. Setting TerminationFlag");
-        TerminationFlag = true;
-        return -1;
-    }
+        if (document && document->purgeSessions() == 0)
+        {
+            LOG_INF("Last session discarded. Setting TerminationFlag");
+            TerminationFlag = true;
+            return -1;
+        }
 #endif
+        // Report the number of events we processsed.
+        return eventsSignalled;
+    }
+};
 
-    // Report the number of events we processsed.
-    return eventsSignalled;
+/// Called by LOK main-loop the central location for data processing.
+int pollCallback(void* pData, int timeoutUs)
+{
+    if (!pData)
+        return 0;
+    else
+        return reinterpret_cast<KitSocketPoll*>(pData)->kitPoll(timeoutUs);
 }
 
 /// Called by LOK main-loop
 void wakeCallback(void* pData)
 {
-    if (pData)
-    {
-        SocketPoll* pSocketPoll = reinterpret_cast<SocketPoll*>(pData);
-        pSocketPoll->wakeup();
-    }
+    if (!pData)
+        return;
+    else
+        return reinterpret_cast<KitSocketPoll*>(pData)->wakeup();
 }
 
 #ifndef BUILDING_TESTS
@@ -2707,7 +2732,7 @@ void lokit_main(
 
 #endif // MOBILEAPP
 
-        SocketPoll mainKit("kit");
+        KitSocketPoll mainKit;
         mainKit.runOnClientThread(); // We will do the polling on this thread.
 
         std::shared_ptr<SocketHandlerInterface> websocketHandler =
commit c9c5a752f9e5c5ca9e85a13da1e84cf9a464cce1
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri May 3 18:05:48 2019 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri May 10 15:42:19 2019 +0100

    unipoll: process lots of events at once.
    
    Change-Id: I8b0a37d114a55e5d64d7e5dd7df6c494971087ca

diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 3e9c0633e..4a47259fa 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -2351,9 +2351,7 @@ int pollCallback(void* pData, int timeoutUs)
     }
 
     // The maximum number of extra events to process beyond the first.
-    //FIXME: When processing more than one event, full-document
-    //FIXME: invalidations happen (for some reason), so disable for now.
-    int maxExtraEvents = 0;
+    int maxExtraEvents = 15;
     int eventsSignalled = 0;
 
     int timeoutMs = timeoutUs / 1000;
@@ -2384,7 +2382,7 @@ int pollCallback(void* pData, int timeoutUs)
             timeoutMs -= elapsedTimeMs;
             ++eventsSignalled;
         }
-        while (maxExtraEvents-- > 0);
+        while (!TerminationFlag && maxExtraEvents-- > 0);
     }
 
     if (document)
commit 0aaab95708868d7fad0d1801b40aa7e8f09adef5
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri May 3 17:05:52 2019 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri May 10 15:42:19 2019 +0100

    Unipoll: move event processing into the same thread.
    
    Change-Id: I15aff3b5f18201eca915da94dbaa05148026e244

diff --git a/common/MessageQueue.hpp b/common/MessageQueue.hpp
index d0a7e8054..91fbe5096 100644
--- a/common/MessageQueue.hpp
+++ b/common/MessageQueue.hpp
@@ -79,6 +79,15 @@ public:
         return get_impl();
     }
 
+    /// Get a message without waiting
+    Payload pop()
+    {
+        std::unique_lock<std::mutex> lock(_mutex);
+        if (!_queue.size())
+            return Payload();
+        return get_impl();
+    }
+
     /// Thread safe removal of all the pending messages.
     void clear()
     {
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index b243f2669..3e9c0633e 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -858,7 +858,7 @@ public:
 /// per process. But for security reasons don't.
 /// However, we could have a loolkit instance
 /// per user or group of users (a trusted circle).
-class Document : public Runnable, public DocumentManagerInterface
+class Document : public DocumentManagerInterface
 {
 public:
     /// We have two types of password protected documents
@@ -898,7 +898,10 @@ public:
                 "] and id [" << _docId << "].");
         assert(_loKit);
 
-        _callbackThread.start(*this);
+#if !MOBILEAPP
+        _lastMemStatsTime = std::chrono::steady_clock::now();
+        sendTextFrame(Util::getMemoryStats(ProcSMapsFile));
+#endif
     }
 
     ~Document()
@@ -912,12 +915,11 @@ public:
         _stop = true;
 
         _tileQueue->put("eof");
-        _callbackThread.join();
     }
 
     const std::string& getUrl() const { return _url; }
 
-    /// Post the message in the correct thread.
+    /// Post the message - in the unipoll world we're in the right thread anyway
     bool postMessage(const std::shared_ptr<std::vector<char>>& message, const WSOpCode code) const
     {
         LOG_TRC("postMessage called with: " << getAbbreviatedMessage(message->data(), message->size()));
@@ -927,7 +929,7 @@ public:
             return false;
         }
 
-        _socketPoll.addCallback([=] { _websocketHandler->sendMessage(message->data(), message->size(), code); });
+        _websocketHandler->sendMessage(message->data(), message->size(), code);
         return true;
     }
 
@@ -1989,35 +1991,16 @@ private:
         return std::string();
     }
 
-    void run() override
+public:
+    void drainQueue(const std::chrono::steady_clock::time_point &now)
     {
-        Util::setThreadName("lokit_" + _docId);
-
-        LOG_DBG("Thread started.");
-#if !MOBILEAPP
-        // Update memory stats and editor every 5 seconds.
-        const int memStatsPeriodMs = 5000;
-        auto lastMemStatsTime = std::chrono::steady_clock::now();
-        sendTextFrame(Util::getMemoryStats(ProcSMapsFile));
-#endif
         try
         {
-            while (!_stop && !TerminationFlag)
+            while (true)
             {
-                const TileQueue::Payload input = _tileQueue->get(POLL_TIMEOUT_MS * 2);
-                if (input.empty())
-                {
-#if !MOBILEAPP
-                    auto duration = (std::chrono::steady_clock::now() - lastMemStatsTime);
-                    std::chrono::milliseconds::rep durationMs = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
-                    if (durationMs > memStatsPeriodMs)
-                    {
-                        sendTextFrame(Util::getMemoryStats(ProcSMapsFile));
-                        lastMemStatsTime = std::chrono::steady_clock::now();
-                    }
-#endif
-                    continue;
-                }
+                const TileQueue::Payload input = _tileQueue->pop();
+                if (input.size() <= 0)
+                    break;
 
                 LOG_TRC("Kit Recv " << LOOLProtocol::getAbbreviatedMessage(input));
 
@@ -2120,6 +2103,17 @@ private:
                     LOG_ERR("Unexpected request: [" << LOOLProtocol::getAbbreviatedMessage(input) << "].");
                 }
             }
+
+#if !MOBILEAPP
+            std::chrono::milliseconds::rep durationMs =
+                std::chrono::duration_cast<std::chrono::milliseconds>(now - _lastMemStatsTime).count();
+            // Update memory stats and editor every 5 seconds.
+            if (durationMs > 5000)
+            {
+                sendTextFrame(Util::getMemoryStats(ProcSMapsFile));
+                _lastMemStatsTime = std::chrono::steady_clock::now();
+            }
+#endif
         }
         catch (const std::exception& exc)
         {
@@ -2129,10 +2123,9 @@ private:
         {
             LOG_FTL("QueueHandler::run: Unknown exception");
         }
-
-        LOG_DBG("Thread finished.");
     }
 
+private:
     /// Return access to the lok::Office instance.
     std::shared_ptr<lok::Office> getLOKit() override
     {
@@ -2214,6 +2207,7 @@ private:
     std::map<int, int> _speedCount;
     /// For showing disconnected user info in the doc repair dialog.
     std::map<int, UserInfo> _sessionUserInfo;
+    std::chrono::steady_clock::time_point _lastMemStatsTime;
     Poco::Thread _callbackThread;
 };
 
@@ -2285,7 +2279,6 @@ protected:
 
             if (!document)
             {
-                // Creating the Document object starts a thread running Document::run().
                 document = std::make_shared<Document>(_loKit, _jailId, docKey, docId, url, _queue, _socketPoll, shared_from_this());
             }
 
@@ -2345,7 +2338,7 @@ void documentViewCallback(const int type, const char* payload, void* data)
     Document::ViewCallback(type, payload, data);
 }
 
-/// Called by LOK main-loop
+/// Called by LOK main-loop the central location for data processing.
 int pollCallback(void* pData, int timeoutUs)
 {
     if (!pData)
@@ -2394,6 +2387,9 @@ int pollCallback(void* pData, int timeoutUs)
         while (maxExtraEvents-- > 0);
     }
 
+    if (document)
+        document->drainQueue(std::chrono::steady_clock::now());
+
 #if !MOBILEAPP
     if (document && document->purgeSessions() == 0)
     {
diff --git a/kit/TestStubs.cpp b/kit/TestStubs.cpp
new file mode 100644
index 000000000..0cb32a091
--- /dev/null
+++ b/kit/TestStubs.cpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+/*
+ * Stub missing symbols required for unit tests ...
+ */
+
+#include <config.h>
+
+#include "common/Common.hpp"
+#include "ChildSession.hpp"
+
+void ChildSession::loKitCallback(const int /* type */, const std::string& /* payload */) {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/test/Makefile.am b/test/Makefile.am
index bf6d5a473..2c8a22785 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -43,10 +43,12 @@ wsd_sources = \
             ../common/Log.cpp \
             ../common/Protocol.cpp \
             ../common/Session.cpp \
+            ../common/SpookyV2.cpp \
             ../common/Util.cpp \
             ../common/MessageQueue.cpp \
             ../common/Authorization.cpp \
             ../kit/Kit.cpp \
+            ../kit/TestStubs.cpp \
             ../wsd/Auth.cpp \
             ../wsd/TileCache.cpp \
             ../wsd/TestStubs.cpp \
commit 2477cfd453413ac1886a78d04cc19cf37b2f5f5b
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Wed Apr 17 22:46:16 2019 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri May 10 15:42:19 2019 +0100

    Unipoll: integrate with the LOK mainloop in a single thread.
    
    Unfortunately processing multiple events from the Kit socket
    is causing massive document invalidations, for unknown
    reasons. As such, for now we have to process one event
    at a time, until the source of the invalidations is found
    and fixed.
    
    Without the invalidation, the average tile rendering
    roundtrip is about 3x faster than with the invalidations
    and the maximum roundrip is at least 2x faster.
    
    Change-Id: Iafbf9ccc2b80656cb71c208b598080f72d201ca2
    Reviewed-on: https://gerrit.libreoffice.org/70906
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    Signed-off-by: Michael Meeks <michael.meeks at collabora.com>

diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp
index fe5fd225a..bce34780f 100644
--- a/kit/ForKit.cpp
+++ b/kit/ForKit.cpp
@@ -528,9 +528,11 @@ int main(int argc, char** argv)
         return Application::EXIT_SOFTWARE;
     }
 
-    // Enable built in profiling dumps
+    // Set various options we need.
+    std::string options = "unipoll";
     if (Log::logger().trace())
-        ::setenv("SAL_PROFILEZONE_EVENTS", "1", 0);
+        options += ":profile_events";
+    ::setenv("SAL_LOK_OPTIONS", options.c_str(), 0);
 
     // Initialize LoKit
     if (!globalPreinit(loTemplate))
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 42b370151..b243f2669 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -2253,7 +2253,7 @@ protected:
             logger << _socketName << ": recv [";
             for (const std::string& token : tokens)
             {
-                // Don't log user-data, there are anonymized versions that get logged instead.
+                // Don't log PII, there are anonymized versions that get logged instead.
                 if (Util::startsWith(token, "jail") ||
                     Util::startsWith(token, "author") ||
                     Util::startsWith(token, "name") ||
@@ -2300,6 +2300,7 @@ protected:
             LOG_TRC("Setting TerminationFlag due to 'exit' command from parent.");
             TerminationFlag = true;
             document.reset();
+            SocketPoll::wakeupWorld();
         }
         else if (tokens[0] == "tile" || tokens[0] == "tilecombine" || tokens[0] == "canceltiles" ||
                 tokens[0] == "paintwindow" || tokens[0] == "resizewindow" ||
@@ -2344,6 +2345,78 @@ void documentViewCallback(const int type, const char* payload, void* data)
     Document::ViewCallback(type, payload, data);
 }
 
+/// Called by LOK main-loop
+int pollCallback(void* pData, int timeoutUs)
+{
+    if (!pData)
+        return 0;
+
+    if (TerminationFlag)
+    {
+        LOG_TRC("Termination of unipoll mainloop flagged");
+        return -1;
+    }
+
+    // The maximum number of extra events to process beyond the first.
+    //FIXME: When processing more than one event, full-document
+    //FIXME: invalidations happen (for some reason), so disable for now.
+    int maxExtraEvents = 0;
+    int eventsSignalled = 0;
+
+    int timeoutMs = timeoutUs / 1000;
+
+    SocketPoll* pSocketPoll = reinterpret_cast<SocketPoll*>(pData);
+    if (timeoutMs < 0)
+    {
+        // Flush at most 1 + maxExtraEvents, or return when nothing left.
+        while (pSocketPoll->poll(0) > 0 && maxExtraEvents-- > 0)
+            ++eventsSignalled;
+    }
+    else
+    {
+        const auto startTime = std::chrono::steady_clock::now();
+        do
+        {
+            // Flush at most maxEvents+1, or return when nothing left.
+            if (pSocketPoll->poll(timeoutMs) <= 0)
+                break;
+
+            const auto now = std::chrono::steady_clock::now();
+            const auto elapsedTimeMs
+                = std::chrono::duration_cast<std::chrono::milliseconds>(now - startTime)
+                .count();
+            if (elapsedTimeMs >= timeoutMs)
+                break;
+
+            timeoutMs -= elapsedTimeMs;
+            ++eventsSignalled;
+        }
+        while (maxExtraEvents-- > 0);
+    }
+
+#if !MOBILEAPP
+    if (document && document->purgeSessions() == 0)
+    {
+        LOG_INF("Last session discarded. Setting TerminationFlag");
+        TerminationFlag = true;
+        return -1;
+    }
+#endif
+
+    // Report the number of events we processsed.
+    return eventsSignalled;
+}
+
+/// Called by LOK main-loop
+void wakeCallback(void* pData)
+{
+    if (pData)
+    {
+        SocketPoll* pSocketPoll = reinterpret_cast<SocketPoll*>(pData);
+        pSocketPoll->wakeup();
+    }
+}
+
 #ifndef BUILDING_TESTS
 
 void lokit_main(
@@ -2539,13 +2612,14 @@ void lokit_main(
         std::string tmpSubdir = Util::createRandomTmpDir();
         ::setenv("TMPDIR", tmpSubdir.c_str(), 1);
 
+        LibreOfficeKit *kit;
         {
             const char *instdir = instdir_path.c_str();
             const char *userdir = userdir_url.c_str();
 #ifndef KIT_IN_PROCESS
-            LibreOfficeKit* kit = UnitKit::get().lok_init(instdir, userdir);
+            kit = UnitKit::get().lok_init(instdir, userdir);
 #else
-            LibreOfficeKit* kit = nullptr;
+            kit = nullptr;
 #ifdef FUZZER
             if (LOOLWSD::DummyLOK)
                 kit = dummy_lok_init_2(instdir, userdir);
@@ -2660,7 +2734,13 @@ void lokit_main(
         }
 #endif
 
-        while (!TerminationFlag)
+        if (!LIBREOFFICEKIT_HAS(kit, runLoop))
+        {
+            LOG_ERR("Kit is missing Unipoll API");
+            std::cout << "Fatal: out of date LibreOfficeKit - no Unipoll API\n";
+            std::_Exit(Application::EXIT_SOFTWARE);
+        }
+        else
         {
             mainKit.poll(SocketPoll::DefaultPollTimeoutMs);
 
@@ -2673,12 +2753,21 @@ void lokit_main(
 #endif
         }
 
+        LOG_INF("Kit unipoll loop run");
+
+        loKit->runLoop(pollCallback, wakeCallback, &mainKit);
+
         LOG_INF("Kit poll terminated.");
 
 #if MOBILEAPP
         SocketPoll::wakeupWorld();
 #endif
 
+        // Trap the signal handler, if invoked,
+        // to prevent exiting.
+        LOG_INF("Process finished.");
+        Log::shutdown();
+
         // Let forkit handle the jail cleanup.
     }
     catch (const Exception& exc)
diff --git a/net/Socket.cpp b/net/Socket.cpp
index dbab15d08..505d95e86 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -375,7 +375,7 @@ void ServerSocket::dumpState(std::ostream& os)
 void SocketDisposition::execute()
 {
     // We should have hard ownership of this socket.
-    assert(_socket->getThreadOwner() == std::this_thread::get_id());
+    // assert(_socket->getThreadOwner() == std::this_thread::get_id());
     if (_socketMove)
     {
         // Drop pretentions of ownership before _socketMove.
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 9f9c74c7d..c73ace9ec 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -301,7 +301,7 @@ public:
                     Log::to_string(_owner) << " but called from " <<
                     std::this_thread::get_id() << " (" << Util::getThreadId() << ").");
 
-        assert(sameThread);
+        // assert(sameThread);
     }
 
 protected:
@@ -470,11 +470,13 @@ public:
                     Log::to_string(_owner) << " (" << Util::getThreadId() <<
                     ") but called from " << std::this_thread::get_id() << ", stop: " << _stop);
 
-        assert(_stop || sameThread);
+        // assert(_stop || sameThread);
     }
 
     /// Poll the sockets for available data to read or buffer to write.
-    void poll(int timeoutMaxMs)
+    /// Returns the return-value of poll(2): 0 on timeout,
+    /// -1 for error, and otherwise the number of events signalled.
+    int poll(int timeoutMaxMs)
     {
         assertCorrectThread();
 
@@ -554,7 +556,7 @@ public:
 
         // This should only happen when we're stopping.
         if (_pollSockets.size() != size)
-            return;
+            return rc;
 
         // Fire the poll callbacks and remove dead fds.
         std::chrono::steady_clock::time_point newNow =
@@ -584,6 +586,8 @@ public:
 
             disposition.execute();
         }
+
+        return rc;
     }
 
     /// Write to a wakeup descriptor


More information about the Libreoffice-commits mailing list