include/vcl/scheduler.hxx      |    6 +++++
 sfx2/qa/cppunit/view.cxx       |   23 +++++++++++++++++++++
 sfx2/source/view/lokhelper.cxx |   41 +++++++++++++++++++++++++++++---------
 vcl/source/app/scheduler.cxx   |   44 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 105 insertions(+), 9 deletions(-)

New commits:
commit e9e39e45f0daed52276377321088aa4d49b112b6
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Feb 14 14:20:21 2025 +0100
Commit:     Michael Meeks <michael.me...@collabora.com>
CommitDate: Fri Feb 14 16:02:46 2025 +0100

    cool#11064 vcl lok: expose info about the scheduler
    
    A LOK client can interrupt the vcl main loop in its 'any input'
    callback. When making that decision, it's useful in case it can know
    what's the priority of the most urgent job, for example it may want core
    to still finish high priority tasks, but not idle ones.
    
    Add a LOK API to expose this info. Keep it minimal, so it's realistic to
    call this frequently from a LOK client.
    
    Change-Id: Id51668eb8156067e60d6fd0f33606c65858008a9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181668
    Reviewed-by: Michael Meeks <michael.me...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/include/vcl/scheduler.hxx b/include/vcl/scheduler.hxx
index 1b63404139bf..b407037eb581 100644
--- a/include/vcl/scheduler.hxx
+++ b/include/vcl/scheduler.hxx
@@ -23,6 +23,10 @@
 #include <vcl/dllapi.h>
 
 struct ImplSchedulerContext;
+namespace tools
+{
+class JsonWriter;
+}
 
 class VCL_DLLPUBLIC Scheduler final
 {
@@ -81,6 +85,8 @@ public:
     static void       SetDeterministicMode(bool bDeterministic);
     /// Return the current state of deterministic mode.
     static bool       GetDeterministicMode();
+
+    static void dumpAsJSON(tools::JsonWriter& rJsonWriter);
 };
 
 #endif // INCLUDED_VCL_SCHEDULER_HXX
diff --git a/sfx2/qa/cppunit/view.cxx b/sfx2/qa/cppunit/view.cxx
index 9a380db1a1d0..b8e5e645600a 100644
--- a/sfx2/qa/cppunit/view.cxx
+++ b/sfx2/qa/cppunit/view.cxx
@@ -218,6 +218,29 @@ CPPUNIT_TEST_FIXTURE(Sfx2ViewTest, testSignatureSerialize)
     // provided parameters.
     CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getSignatureCount());
 }
+
+CPPUNIT_TEST_FIXTURE(Sfx2ViewTest, testScheduler)
+{
+    // Given an empty document:
+    mxComponent = loadFromDesktop("private:factory/swriter", 
"com.sun.star.text.TextDocument");
+
+    // When asking for the state of the scheduler:
+    tools::JsonWriter aWriter;
+    SfxLokHelper::getCommandValues(aWriter, ".uno:Scheduler");
+    OString aJson = aWriter.finishAndGetAsOString();
+
+    // Then make sure we get an int priority:
+    CPPUNIT_ASSERT(SfxLokHelper::supportsCommand(u"Scheduler"));
+    std::stringstream aStream{ std::string(aJson) };
+    boost::property_tree::ptree aTree;
+    boost::property_tree::read_json(aStream, aTree);
+    auto it = aTree.find("mostUrgentPriority");
+    // Without the accompanying fix in place, this test would have failed, 
this JSON key was
+    // missing.
+    CPPUNIT_ASSERT(it != aTree.not_found());
+    // This returns TaskPriority::HIGH_IDLE, but just make sure we get an int.
+    it->second.get_value<int>();
+}
 #endif
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index 77d39d22f2e0..cff43e6de576 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -43,6 +43,7 @@
 #include <tools/json_writer.hxx>
 #include <svl/cryptosign.hxx>
 #include <tools/urlobj.hxx>
+#include <vcl/scheduler.hxx>
 
 #include <boost/property_tree/json_parser.hpp>
 
@@ -994,7 +995,8 @@ void SfxLokHelper::addCertificates(const 
std::vector<std::string>& rCerts)
 
 bool SfxLokHelper::supportsCommand(std::u16string_view rCommand)
 {
-    static const std::initializer_list<std::u16string_view> vSupport = { 
u"Signature" };
+    static const std::initializer_list<std::u16string_view> vSupport
+        = { u"Signature", u"Scheduler" };
 
     return std::find(vSupport.begin(), vSupport.end(), rCommand) != 
vSupport.end();
 }
@@ -1028,14 +1030,11 @@ std::map<OUString, OUString> 
SfxLokHelper::parseCommandParameters(std::u16string
     return aMap;
 }
 
-void SfxLokHelper::getCommandValues(tools::JsonWriter& rJsonWriter, 
std::string_view rCommand)
+namespace
+{
+/// Implements getCommandValues(".uno:Signature").
+void GetSignature(tools::JsonWriter& rJsonWriter, std::string_view rCommand)
 {
-    static constexpr OString aSignature(".uno:Signature"_ostr);
-    if (!o3tl::starts_with(rCommand, aSignature))
-    {
-        return;
-    }
-
     SfxObjectShell* pObjectShell = SfxObjectShell::Current();
     if (!pObjectShell)
     {
@@ -1053,7 +1052,7 @@ void SfxLokHelper::getCommandValues(tools::JsonWriter& 
rJsonWriter, std::string_
     }
     pObjectShell->SignDocumentContentUsingCertificate(aSigningContext);
     // Set commandName, this is a reply to a request.
-    rJsonWriter.put("commandName", aSignature);
+    rJsonWriter.put("commandName", ".uno:Signature");
     auto aCommandValues = rJsonWriter.startNode("commandValues");
     rJsonWriter.put("signatureTime", aSigningContext.m_nSignatureTime);
 
@@ -1064,6 +1063,30 @@ void SfxLokHelper::getCommandValues(tools::JsonWriter& 
rJsonWriter, std::string_
     rJsonWriter.put("digest", aBuffer.makeStringAndClear());
 }
 
+/// Implements getCommandValues(".uno:Scheduler").
+void GetScheduler(tools::JsonWriter& rJsonWriter)
+{
+    Scheduler::dumpAsJSON(rJsonWriter);
+}
+}
+
+void SfxLokHelper::getCommandValues(tools::JsonWriter& rJsonWriter, 
std::string_view rCommand)
+{
+    static constexpr OString aSignature(".uno:Signature"_ostr);
+    static constexpr OString aScheduler(".uno:Scheduler"_ostr);
+    if (o3tl::starts_with(rCommand, aSignature))
+    {
+        GetSignature(rJsonWriter, rCommand);
+        return;
+    }
+
+    if (o3tl::starts_with(rCommand, aScheduler))
+    {
+        GetScheduler(rJsonWriter);
+        return;
+    }
+}
+
 void SfxLokHelper::notifyUpdate(SfxViewShell const* pThisView, int nType)
 {
     if (DisableCallbacks::disabled() || !pThisView)
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
index e6893055f633..bb5436a3a04f 100644
--- a/vcl/source/app/scheduler.cxx
+++ b/vcl/source/app/scheduler.cxx
@@ -38,6 +38,7 @@
 #include <saltimer.hxx>
 #include <salinst.hxx>
 #include <comphelper/profilezone.hxx>
+#include <tools/json_writer.hxx>
 #include <schedulerimpl.hxx>
 
 namespace {
@@ -271,6 +272,49 @@ bool Scheduler::GetDeterministicMode()
     return g_bDeterministicMode;
 }
 
+void Scheduler::dumpAsJSON(tools::JsonWriter& rJsonWriter)
+{
+    // Similar to Scheduler::CallbackTaskScheduling(), figure out the most 
urgent priority, but
+    // don't actually invoke any task.
+    int nMostUrgentPriority = -1;
+    ImplSVData* pSVData = ImplGetSVData();
+    ImplSchedulerContext& rSchedCtx = pSVData->maSchedCtx;
+    if (!rSchedCtx.mbActive || rSchedCtx.mnTimerPeriod == InfiniteTimeoutMs)
+    {
+        rJsonWriter.put("mostUrgentPriority", nMostUrgentPriority);
+        return;
+    }
+
+    sal_uInt64 nTime = tools::Time::GetSystemTicks();
+    if (nTime < rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod - 1)
+    {
+        rJsonWriter.put("mostUrgentPriority", nMostUrgentPriority);
+        return;
+    }
+
+    for (int nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
+    {
+        ImplSchedulerData* pSchedulerData = 
rSchedCtx.mpFirstSchedulerData[nTaskPriority];
+        while (pSchedulerData)
+        {
+            Task* pTask = pSchedulerData->mpTask;
+            if (pTask && pTask->IsActive())
+            {
+                // Const, doesn't modify the task.
+                sal_uInt64 nReadyPeriod = pTask->UpdateMinPeriod(nTime);
+                if (nReadyPeriod == ImmediateTimeoutMs)
+                {
+                    nMostUrgentPriority = nTaskPriority;
+                    rJsonWriter.put("mostUrgentPriority", nMostUrgentPriority);
+                    return;
+                }
+            }
+            pSchedulerData = pSchedulerData->mpNext;
+        }
+    }
+    rJsonWriter.put("mostUrgentPriority", nMostUrgentPriority);
+}
+
 inline void Scheduler::UpdateSystemTimer( ImplSchedulerContext &rSchedCtx,
                                           const sal_uInt64 nMinPeriod,
                                           const bool bForce, const sal_uInt64 
nTime )

Reply via email to