[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 4/4] XenAgent: Add options to time sync code


  • To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Paul Durrant <xadimgnik@xxxxxxxxx>
  • Date: Thu, 1 Feb 2024 17:57:34 +0000
  • Delivery-date: Thu, 01 Feb 2024 17:57:42 +0000
  • List-id: Developer list for the Windows PV Drivers subproject <win-pv-devel.lists.xenproject.org>

On 31/01/2024 08:12, Owen Smith wrote:
Adds registry overrided to control how and when XenAgent will update the
system time.
"TimeSyncMode" is a bit-field with the following options:
   0b0000 = do not update system time
   0b0001 = update after resume from suspend
   0b0010 = update periodically
   0b0100 = update when xeniface device detected (including on service start)
   Default is 0b0001 (after resume).

"TimeSyncInterval" is the number of minutes between attempts to update
   system time. This only applies if "TimeSyncMode" contains 0b0010
   Default is 30 minutes.

Signed-off-by: Owen Smith <owen.smith@xxxxxxxxx>
---
  src/xenagent/service.cpp        |   6 +-
  src/xenagent/xenifacedevice.cpp | 144 +++++++++++++++++++++++++++++---
  src/xenagent/xenifacedevice.h   |  15 +++-
  3 files changed, 149 insertions(+), 16 deletions(-)

diff --git a/src/xenagent/service.cpp b/src/xenagent/service.cpp
index ec32ecc..3e30bb0 100644
--- a/src/xenagent/service.cpp
+++ b/src/xenagent/service.cpp
@@ -198,7 +198,7 @@ void CXenAgent::OnPowerEvent(DWORD evt, LPVOID data)
bool CXenAgent::ServiceMainLoop()
  {
-    DWORD   timeout = 30 * 60 * 1000;
+    DWORD   timeout = 1 * 60 * 1000;
      HANDLE  events[] = { m_svc_stop,
                           m_xeniface.m_evt_shutdown,
                           m_xeniface.m_evt_suspend,
@@ -221,7 +221,7 @@ bool CXenAgent::ServiceMainLoop()
case WAIT_OBJECT_0+2:
          ResetEvent(m_xeniface.m_evt_suspend);
-        m_xeniface.CheckXenTime();
+        m_xeniface.CheckXenTime(XENIFACE_TIMESYNC_RESUME);
          m_xeniface.CheckSuspend();
          return true; // continue loop
@@ -239,7 +239,7 @@ bool CXenAgent::ServiceMainLoop()
          return true; // continue loop
case WAIT_TIMEOUT:
-        m_xeniface.CheckXenTime();
+        m_xeniface.CheckXenTime(XENIFACE_TIMESYNC_PERIODIC);
          __fallthrough;
      case WAIT_IO_COMPLETION:
          m_xeniface.CheckSuspend();
diff --git a/src/xenagent/xenifacedevice.cpp b/src/xenagent/xenifacedevice.cpp
index 223d6e9..ffada25 100644
--- a/src/xenagent/xenifacedevice.cpp
+++ b/src/xenagent/xenifacedevice.cpp
@@ -43,6 +43,13 @@
  #define DEFAULT_SHUTDOWN_RETRIES        5
  #define DEFAULT_SHUTDOWN_RETRY_TIME     60
+#define XENAGENT_TIMESYNC_INTERVAL_DEFAULT 30
+
+#define XENAGENT_SERVICE_KEY            
"SYSTEM\\CurrentControlSet\\Services\\xenagent"
+#define XENAGENT_TIMESYNC_MODE          "TimeSyncMode"
+#define XENAGENT_TIMESYNC_INTERVAL      "TimeSyncInterval"
+#define XENAGENT_TIMESYNC_LAST          "LastSyncFiletime"
+
  CXenIfaceDevice::CXenIfaceDevice(const wchar_t* path) : CDevice(path)
  {}
@@ -222,7 +229,7 @@ CXenIfaceDeviceList::CXenIfaceDeviceList(CXenAgent* agent) : CDeviceList(GUID_IN AdvertiseFeatures(device, true); - SetXenTime(device);
+    SetXenTime(device, XENIFACE_TIMESYNC_ADDED);
  }
/*virtual*/ void CXenIfaceDeviceList::OnDeviceRemoved(CDevice* dev)
@@ -352,7 +359,7 @@ void CXenIfaceDeviceList::CheckShutdownRetry()
      RequestSystemShutdown();
  }
-void CXenIfaceDeviceList::CheckXenTime()
+void CXenIfaceDeviceList::CheckXenTime(DWORD reason)
  {
      CCritSec crit(&m_crit);
      CXenIfaceDevice* device = (CXenIfaceDevice*)GetFirstDevice();
@@ -360,7 +367,7 @@ void CXenIfaceDeviceList::CheckXenTime()
      if (device == NULL)
          return;
- SetXenTime(device);
+    SetXenTime(device, reason);
  }
void CXenIfaceDeviceList::CheckSuspend()
@@ -543,28 +550,30 @@ void CXenIfaceDeviceList::AcquireShutdownPrivilege()
      CloseHandle(token);
  }
-void CXenIfaceDeviceList::SetXenTime(CXenIfaceDevice* device)
+void CXenIfaceDeviceList::SetXenTime(CXenIfaceDevice* device, DWORD reason)
  {
-    bool local;
+    XENIFACE_SHARED_TIME now;
- FILETIME now = { 0 };
-    if (!device->SharedInfoGetTime(&now, &local))
+    if (!device->SharedInfoGetTime(&now.time, &now.local))
+        return;
+
+    if (!CheckXenTimeEnabled(reason, &now))
          return;
SYSTEMTIME cur = { 0 };
-    if (local)
+    if (now.local)
          GetLocalTime(&cur);
      else
          GetSystemTime(&cur);
SYSTEMTIME sys = { 0 };
-    if (!FileTimeToSystemTime(&now, &sys))
+    if (!FileTimeToSystemTime(&now.time, &sys))
          return;
if (memcmp(&cur, &sys, sizeof(SYSTEMTIME)) == 0)
          return;
- CXenAgent::Log("RTC is in %s\n", local ? "local time" : "UTC");
+    CXenAgent::Log("RTC is in %s\n", now.local ? "local time" : "UTC");
      CXenAgent::Log("Time Now = %d/%d/%d %d:%02d:%02d.%d\n",
                     cur.wYear, cur.wMonth, cur.wDay,
                     cur.wHour, cur.wMinute, cur.wSecond, cur.wMilliseconds);
@@ -572,8 +581,121 @@ void CXenIfaceDeviceList::SetXenTime(CXenIfaceDevice* 
device)
                     sys.wYear, sys.wMonth, sys.wDay,
                     sys.wHour, sys.wMinute, sys.wSecond, sys.wMilliseconds);
- if (local)
+    if (now.local)
          SetLocalTime(&sys);
      else
          SetSystemTime(&sys);
  }
+
+static FORCEINLINE LONG64
+TimeDiff(FILETIME* old, FILETIME* now)
+{
+    ULONG64     ftOld;
+    ULONG64     ftNow;
+    LONG64      ftDiff;
+
+    ftOld = ((ULONG64)old->dwHighDateTime) << 32 |
+             (ULONG64)old->dwLowDateTime;
+
+    ftNow = ((ULONG64)now->dwHighDateTime) << 32 |
+             (ULONG64)now->dwLowDateTime;
+
+    ftDiff = (LONG64)(ftNow - ftOld);
+    //From 100NS to whole minutes.
+    ftDiff /= (10 * 1000 * 1000 * 60);
+    return ftDiff;
+}
+
+bool CXenIfaceDeviceList::CheckXenTimeEnabled(DWORD reason, 
PXENIFACE_SHARED_TIME now)
+{
+    HKEY                    key;
+    LONG                    lResult;
+    DWORD                   type;
+    DWORD                   size;
+    DWORD                   mode;
+    bool                    enabled;
+
+    enabled = (reason == XENIFACE_TIMESYNC_RESUME);
+
+    lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                           XENAGENT_SERVICE_KEY,
+                           0,
+                           KEY_READ,
+                           &key);
+    if (lResult != ERROR_SUCCESS)
+        goto fail1;
+
+    size = sizeof(DWORD);
+    lResult = RegQueryValueEx(key,
+                              XENAGENT_TIMESYNC_MODE,
+                              NULL,
+                              &type,
+                              (LPBYTE)&mode,
+                              &size);
+    if (lResult != ERROR_SUCCESS)
+        goto fail2;
+
+    if (type != REG_DWORD ||
+        size != sizeof(DWORD))
+        goto fail3;
+
+    // mode is bit-flags, test for reason's bit
+    enabled = (mode & reason) != 0;
+
+    if (reason == XENIFACE_TIMESYNC_PERIODIC && enabled) {
+        DWORD                   interval;
+        XENIFACE_SHARED_TIME    last;
+
+        // check interval has expired
+        size = sizeof(DWORD);
+        lResult = RegQueryValueEx(key,
+                                  XENAGENT_TIMESYNC_INTERVAL,
+                                  NULL,
+                                  &type,
+                                  (LPBYTE)&interval,
+                                  &size);
+        if (lResult != ERROR_SUCCESS ||
+            type != REG_DWORD ||
+            size != sizeof(DWORD))
+            interval = XENAGENT_TIMESYNC_INTERVAL_DEFAULT;
+
+        size = sizeof(XENIFACE_SHARED_TIME);
+        lResult = RegQueryValueEx(key,
+                                  XENAGENT_TIMESYNC_LAST,
+                                  NULL,
+                                  &type,
+                                  (LPBYTE)&last,
+                                  &size);
+        if (lResult == ERROR_SUCCESS ||
+            type == REG_BINARY ||
+            size == sizeof(XENIFACE_SHARED_TIME)) {
+            // check if time is within interval -> dont update time
+            if ((last.local == now->local) &&
+                (TimeDiff(&last.time, &now->time) < interval)) {
+                enabled = false;
+            }
+        }
+    }
+
+    if (enabled) {
+        lResult = RegSetValueEx(key,
+                                XENAGENT_TIMESYNC_LAST,
+                                0,
+                                REG_BINARY,
+                                (LPBYTE)&now,
+                                sizeof(XENIFACE_SHARED_TIME));
+        if (lResult != ERROR_SUCCESS)
+            CXenAgent::Log("SetLastUpdateTime failed %08x\n", lResult);
+    }
+
+    RegCloseKey(key);
+
+    return enabled;
+
+fail3:
+fail2:
+    RegCloseKey(key);
+
+fail1:
+    return enabled;
+}
\ No newline at end of file
diff --git a/src/xenagent/xenifacedevice.h b/src/xenagent/xenifacedevice.h
index 5a1aecf..4878db0 100644
--- a/src/xenagent/xenifacedevice.h
+++ b/src/xenagent/xenifacedevice.h
@@ -37,6 +37,16 @@
  #include <string>
  #include "devicelist.h"
+#define XENIFACE_TIMESYNC_NONE 0
+#define XENIFACE_TIMESYNC_RESUME        1
+#define XENIFACE_TIMESYNC_PERIODIC      2
+#define XENIFACE_TIMESYNC_ADDED         4

Given that these are flags it would be nice to define them as shifts, to make it clearer. I can do that.

Acked-by: Paul Durrant <paul@xxxxxxx>

+
+typedef struct _XENIFACE_SHARED_TIME {
+    FILETIME    time;
+    bool        local;
+} XENIFACE_SHARED_TIME, *PXENIFACE_SHARED_TIME;
+
  class CXenIfaceDevice : public CDevice
  {
  public:
@@ -86,7 +96,7 @@ public:
      void Log(const char* message);
      bool CheckShutdown();
      void CheckShutdownRetry();
-    void CheckXenTime();
+    void CheckXenTime(DWORD reason);
      void CheckSuspend();
      bool CheckSlateMode(std::string& mode);
      void LogIfRebootPending();
@@ -99,7 +109,8 @@ private:
      void AdvertiseFeatures(CXenIfaceDevice* device, bool add);
      void RequestSystemShutdown();
      void AcquireShutdownPrivilege();
-    void SetXenTime(CXenIfaceDevice* device);
+    void SetXenTime(CXenIfaceDevice* device, DWORD reason);
+    bool CheckXenTimeEnabled(DWORD reason, PXENIFACE_SHARED_TIME now);
private:
      CXenAgent*  m_agent;




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.