]> xenbits.xensource.com Git - people/pauldu/xeniface.git/commitdiff
Try to make sure the agent always always handles shutdown events
authorPaul Durrant <paul.durrant@citrix.com>
Wed, 9 Nov 2016 11:37:13 +0000 (11:37 +0000)
committerPaul Durrant <paul.durrant@citrix.com>
Wed, 9 Nov 2016 11:40:10 +0000 (11:40 +0000)
It seems that on Server 2008 the agent does not reliably wake up on
shutdown watch events. This does not seem to occur on any other OS so
it is likely that this is a bug in Server 2008.

To work around the problem this patch nodifies the agent wake up once a
minute and check for a shutdown event (or a suspend event, for
completeness) and act accordingly.

Also this patch squashes the uninteresting error messages that occur
when an attempt is made to read a non-existent xenstore key.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
src/xenagent/service.cpp
src/xenagent/service.h
src/xenagent/xenifacedevice.cpp
src/xenagent/xenifacedevice.h
src/xeniface/ioctl_store.c

index 170c2dd5aea71291bb3a65fdc82d8862c327b83c..7243fa4de91c5dd8712470d0f94a830a2bd20805 100644 (file)
@@ -202,6 +202,7 @@ CXenAgent::CXenAgent() : m_handle(NULL), m_evtlog(NULL),
     m_svc_stop = CreateEvent(FALSE, NULL, NULL, FALSE);
     m_evt_shutdown = CreateEvent(FALSE, NULL, NULL, FALSE);
     m_evt_suspend = CreateEvent(FALSE, NULL, NULL, FALSE);
+    m_count = 0;
 
     InitializeCriticalSection(&m_crit);
 }
@@ -315,20 +316,24 @@ void CXenAgent::OnPowerEvent(DWORD evt, LPVOID data)
 bool CXenAgent::ServiceMainLoop()
 {
     HANDLE  events[3] = { m_svc_stop, m_evt_shutdown, m_evt_suspend };
-    DWORD   wait = WaitForMultipleObjects(3, events, FALSE, INFINITE);
+    DWORD   wait = WaitForMultipleObjectsEx(3, events, FALSE, 60000, TRUE);
 
     switch (wait) {
     case WAIT_OBJECT_0:
         return false; // exit loop
 
     case WAIT_OBJECT_0+1:
-        OnShutdown();
-        return true; // continue loop
+        return !CheckShutdown();
 
     case WAIT_OBJECT_0+2:
-        OnSuspend();
+        CheckSuspend();
         return true; // continue loop
 
+    case WAIT_IO_COMPLETION:
+    case WAIT_TIMEOUT:
+        CheckSuspend();
+        return !CheckShutdown();
+
     default:
         CXenAgent::Log("WaitForMultipleObjects failed (%08x)\n", wait);
         EventLog(EVENT_XENUSER_UNEXPECTED);
@@ -488,16 +493,17 @@ void CXenAgent::SetXenTime()
 #pragma warning(push)
 #pragma warning(disable:28159)
 
-void CXenAgent::OnShutdown()
+bool CXenAgent::CheckShutdown()
 {
     CCritSec crit(&m_crit);
     if (m_device == NULL)
-        return;
+        return false;
 
     std::string type;
-    m_device->StoreRead("control/shutdown", type);
+    if (!m_device->StoreRead("control/shutdown", type))
+        return false;
 
-    CXenAgent::Log("OnShutdown(%ws) = %s\n", m_device->Path(), type.c_str());
+    CXenAgent::Log("Shutdown(%ws) = %s\n", m_device->Path(), type.c_str());
 
     if (type == "poweroff") {
         EventLog(EVENT_XENUSER_POWEROFF);
@@ -510,6 +516,7 @@ void CXenAgent::OnShutdown()
                                       SHTDN_REASON_FLAG_PLANNED)) {
             CXenAgent::Log("InitiateSystemShutdownEx failed %08x\n", GetLastError());
         }
+        return true;
     } else if (type == "reboot") {
         EventLog(EVENT_XENUSER_REBOOT);
 
@@ -521,6 +528,7 @@ void CXenAgent::OnShutdown()
                                       SHTDN_REASON_FLAG_PLANNED)) {
             CXenAgent::Log("InitiateSystemShutdownEx failed %08x\n", GetLastError());
         }
+        return true;
     } else if (type == "s4") {
         EventLog(EVENT_XENUSER_S4);
 
@@ -529,6 +537,7 @@ void CXenAgent::OnShutdown()
         if (!SetSystemPowerState(FALSE, FALSE)) {
             CXenAgent::Log("SetSystemPowerState failed %08x\n", GetLastError());
         }
+        return true;
     } else if (type == "s3") {
         EventLog(EVENT_XENUSER_S3);
 
@@ -537,18 +546,30 @@ void CXenAgent::OnShutdown()
         if (!SetSuspendState(FALSE, TRUE, FALSE)) {
             CXenAgent::Log("SetSuspendState failed %08x\n", GetLastError());
         }
+        return true;
     }
+
+    return false;
 }
 
 #pragma warning(pop)
 
-void CXenAgent::OnSuspend()
+void CXenAgent::CheckSuspend()
 {
     CCritSec crit(&m_crit);
     if (m_device == NULL)
         return;
 
-    CXenAgent::Log("OnSuspend(%ws)\n", m_device->Path());
+    DWORD count = 0;
+
+    if (!m_device->SuspendGetCount(&count))
+        return;
+
+    if (m_count == count)
+        return;
+
+    CXenAgent::Log("Suspend(%ws)\n", m_device->Path());
+
     EventLog(EVENT_XENUSER_UNSUSPENDED);
 
     // recreate shutdown watch, as suspending deactivated the watch
index ad9821a1bb39018dd4b0c208950d1401a0d4c6a1..765887c1049fd1743fbe877f7549f75f2a3bb1ea 100644 (file)
@@ -79,8 +79,8 @@ private: // helpers
     void AdjustXenTimeToUTC(FILETIME* time);
     bool RegCheckIsUTC(const char* path);
     void SetXenTime();
-    void OnShutdown();
-    void OnSuspend();
+    bool CheckShutdown();
+    void CheckSuspend();
 
 private: // service support
     void SetServiceStatus(DWORD state, DWORD exit = 0, DWORD hint = 0);
@@ -99,6 +99,7 @@ private: // service support
     CRITICAL_SECTION        m_crit;
     void*                   m_ctxt_shutdown;
     void*                   m_ctxt_suspend;
+    DWORD                   m_count;
 };
 
 #endif
index 98e4d2f1975a5498c93b2b6c1f5abac28f536b10..c254b9a9cf8444bbcce6b5c75f19d0c1c50f0190 100644 (file)
@@ -138,6 +138,17 @@ bool CXenIfaceDevice::SuspendDeregister(void* ctxt)
                  NULL, 0);
 }
 
+bool CXenIfaceDevice::SuspendGetCount(DWORD *count)
+{
+    DWORD out;
+    if (!Ioctl(IOCTL_XENIFACE_SUSPEND_GET_COUNT,
+                NULL, 0,
+                &out, (DWORD)sizeof(out)))
+        return false;
+    *count = out;
+    return true;
+}
+
 // sharedinfo interface
 bool CXenIfaceDevice::SharedInfoGetTime(FILETIME* time)
 {
index 163b19350dd12c960a62888149bbb88540b9b9fb..7ea2f0efd5b058368e788ca2d8de8fc2906740f1 100644 (file)
@@ -52,6 +52,7 @@ public: // store interface
 public: // suspend interface
     bool SuspendRegister(HANDLE evt, void** ctxt);
     bool SuspendDeregister(void* ctxt);
+    bool SuspendGetCount(DWORD *count);
 
 public: // sharedinfo interface
     bool SharedInfoGetTime(FILETIME* time);
index 1725e0655b2a71203002980d7860562717001a4f..b8ee07322c356e29b6ed14ab9ffe810742b3bf26 100644 (file)
@@ -102,6 +102,7 @@ IoctlStoreRead(
     NTSTATUS    status;
     PCHAR       Value;
     ULONG       Length;
+    BOOLEAN     SquashError = FALSE;
 
     status = STATUS_INVALID_BUFFER_SIZE;
     if (InLen == 0)
@@ -112,8 +113,12 @@ IoctlStoreRead(
         goto fail2;
 
     status = XENBUS_STORE(Read, &Fdo->StoreInterface, NULL, NULL, Buffer, &Value);
-    if (!NT_SUCCESS(status))
+    if (!NT_SUCCESS(status)) {
+        if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+            SquashError = TRUE;
+
         goto fail3;
+    }
 
     Length = (ULONG)strlen(Value) + 1;
 
@@ -142,11 +147,15 @@ fail4:
     XenIfaceDebugPrint(ERROR, "Fail4 (\"%s\")=(%d < %d)\n", Buffer, OutLen, Length);
     XENBUS_STORE(Free, &Fdo->StoreInterface, Value);
 fail3:
-    XenIfaceDebugPrint(ERROR, "Fail3 (\"%s\")\n", Buffer);
+    if (!SquashError)
+        XenIfaceDebugPrint(ERROR, "Fail3 (\"%s\")\n", Buffer);
 fail2:
-    XenIfaceDebugPrint(ERROR, "Fail2\n");
+    if (!SquashError)
+        XenIfaceDebugPrint(ERROR, "Fail2\n");
 fail1:
-    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
+    if (!SquashError)
+        XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
+
     return status;
 }