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

[win-pv-devel] [PATCH 5/6] Add Suspend and Shutdown handlers



Suspend needs to re-advertise the shutdown feature
Shutdown responds to control\shutdown to issue a shutdown, reboot,
hibernate or S3 transition.
Suitable event log entries are added when these events are triggered.

Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>
---
 src/xenagent/service.cpp | 147 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/xenagent/service.h   |  10 ++++
 2 files changed, 154 insertions(+), 3 deletions(-)

diff --git a/src/xenagent/service.cpp b/src/xenagent/service.cpp
index 84b8814..3e621eb 100644
--- a/src/xenagent/service.cpp
+++ b/src/xenagent/service.cpp
@@ -32,6 +32,8 @@
 #define INITGUID
 #include <windows.h>
 #include <stdio.h>
+#include <powrprof.h>
+#include <winuser.h>
 
 #include <xeniface_ioctls.h>
 
@@ -170,7 +172,8 @@ static CXenAgent s_service;
 }
 
 CXenAgent::CXenAgent() : m_handle(NULL), m_evtlog(NULL),
-    m_devlist(GUID_INTERFACE_XENIFACE), m_device(NULL)
+    m_devlist(GUID_INTERFACE_XENIFACE), m_device(NULL),
+    m_ctxt_shutdown(NULL), m_ctxt_suspend(NULL)
 {
     m_status.dwServiceType        = SERVICE_WIN32;
     m_status.dwCurrentState       = SERVICE_START_PENDING;
@@ -181,12 +184,16 @@ CXenAgent::CXenAgent() : m_handle(NULL), m_evtlog(NULL),
     m_status.dwWaitHint           = 0;
 
     m_svc_stop = CreateEvent(FALSE, NULL, NULL, FALSE);
+    m_evt_shutdown = CreateEvent(FALSE, NULL, NULL, FALSE);
+    m_evt_suspend = CreateEvent(FALSE, NULL, NULL, FALSE);
 
     InitializeCriticalSection(&m_crit);
 }
 
 CXenAgent::~CXenAgent()
 {
+    CloseHandle(m_evt_suspend);
+    CloseHandle(m_evt_shutdown);
     CloseHandle(m_svc_stop);
 
     DeleteCriticalSection(&m_crit);
@@ -204,6 +211,13 @@ CXenAgent::~CXenAgent()
     CCritSec crit(&m_crit);
     if (m_device == NULL) {
         m_device = (CXenIfaceDevice*)dev;
+
+        // shutdown
+        m_device->StoreAddWatch("control/shutdown", m_evt_shutdown, 
&m_ctxt_shutdown);
+        m_device->StoreWrite("control/feature-shutdown", "1");
+
+        // suspend
+        m_device->SuspendRegister(m_evt_suspend, &m_ctxt_suspend);
     }
 }
 
@@ -213,6 +227,17 @@ CXenAgent::~CXenAgent()
 
     CCritSec crit(&m_crit);
     if (m_device == dev) {
+        // suspend
+        if (m_ctxt_suspend)
+            m_device->SuspendDeregister(m_ctxt_suspend);
+        m_ctxt_suspend = NULL;
+
+        // shutdown
+        m_device->StoreRemove("control/feature-shutdown");
+        if (m_ctxt_shutdown)
+            m_device->StoreRemoveWatch(m_ctxt_shutdown);
+        m_ctxt_shutdown = NULL;
+
         m_device = NULL;
     }
 }
@@ -236,8 +261,124 @@ void CXenAgent::OnDeviceEvent(DWORD evt, LPVOID data)
 
 bool CXenAgent::ServiceMainLoop()
 {
-    WaitForSingleObject(m_svc_stop, INFINITE);
-    return false;
+    HANDLE  events[3] = { m_svc_stop, m_evt_shutdown, m_evt_suspend };
+    DWORD   wait = WaitForMultipleObjects(3, events, FALSE, INFINITE);
+
+    switch (wait) {
+    case WAIT_OBJECT_0:
+        return false; // exit loop
+
+    case WAIT_OBJECT_0+1:
+        OnShutdown();
+        return true; // continue loop
+
+    case WAIT_OBJECT_0+2:
+        OnSuspend();
+        return true; // continue loop
+
+    default:
+        CXenAgent::Log("WaitForMultipleObjects failed (%08x)\n", wait);
+        EventLog(EVENT_XENUSER_UNEXPECTED);
+        return true; // continue loop
+    }
+}
+
+void CXenAgent::AcquireShutdownPrivilege()
+{
+    HANDLE          token;
+    TOKEN_PRIVILEGES tp;
+
+    LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tp.Privileges[0].Luid);
+    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+    tp.PrivilegeCount = 1;
+
+    if (!OpenProcessToken(GetCurrentProcess(),
+                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+                          &token))
+        return;
+
+    AdjustTokenPrivileges(token, FALSE, &tp, NULL, 0, NULL);
+    CloseHandle(token);
+}
+
+void CXenAgent::EventLog(DWORD evt)
+{
+    if (m_evtlog) {
+        ReportEvent(m_evtlog,
+                    EVENTLOG_SUCCESS,
+                    0,
+                    evt,
+                    NULL,
+                    0,
+                    0,
+                    NULL,
+                    NULL);
+    }
+}
+
+void CXenAgent::OnShutdown()
+{
+    CCritSec crit(&m_crit);
+    if (m_device == NULL)
+        return;
+
+    std::string type;
+    m_device->StoreRead("control/shutdown", type);
+
+    CXenAgent::Log("OnShutdown(%ws) = %s\n", m_device->Path(), type.c_str());
+
+    if (type == "poweroff" || type == "halt") {
+        EventLog(EVENT_XENUSER_POWEROFF);
+
+        m_device->StoreWrite("control/shutdown", "");
+        AcquireShutdownPrivilege();
+        if (!InitiateSystemShutdownEx(NULL, NULL, 0, TRUE, FALSE,
+                                      SHTDN_REASON_MAJOR_OTHER |
+                                      SHTDN_REASON_MINOR_ENVIRONMENT |
+                                      SHTDN_REASON_FLAG_PLANNED)) {
+            CXenAgent::Log("InitiateSystemShutdownEx failed %08x\n", 
GetLastError());
+        }
+    } else if (type == "reboot") {
+        EventLog(EVENT_XENUSER_REBOOT);
+
+        m_device->StoreWrite("control/shutdown", "");
+        AcquireShutdownPrivilege();
+        if (!InitiateSystemShutdownEx(NULL, NULL, 0, TRUE, TRUE,
+                                      SHTDN_REASON_MAJOR_OTHER |
+                                      SHTDN_REASON_MINOR_ENVIRONMENT |
+                                      SHTDN_REASON_FLAG_PLANNED)) {
+            CXenAgent::Log("InitiateSystemShutdownEx failed %08x\n", 
GetLastError());
+        }
+    } else if (type == "hibernate") {
+        EventLog(EVENT_XENUSER_HIBERNATE);
+
+        m_device->StoreWrite("control/shutdown", "");
+        AcquireShutdownPrivilege();
+        if (!SetSystemPowerState(FALSE, FALSE)) {
+            CXenAgent::Log("SetSystemPowerState failed %08x\n", 
GetLastError());
+        }
+    } else if (type == "s3") {
+        EventLog(EVENT_XENUSER_S3);
+
+        m_device->StoreWrite("control/shutdown", "");
+        AcquireShutdownPrivilege();
+        if (!SetSuspendState(FALSE, TRUE, FALSE)) {
+            CXenAgent::Log("SetSuspendState failed %08x\n", GetLastError());
+        }
+    }
+}
+
+void CXenAgent::OnSuspend()
+{
+    CCritSec crit(&m_crit);
+    if (m_device == NULL)
+        return;
+
+    CXenAgent::Log("OnSuspend(%ws)\n", m_device->Path());
+    EventLog(EVENT_XENUSER_UNSUSPENDED);
+
+    m_device->StoreWrite("control/feature-shutdown", "1");
 }
 
 void CXenAgent::SetServiceStatus(DWORD state, DWORD exit /*= 0*/, DWORD hint 
/*= 0*/)
diff --git a/src/xenagent/service.h b/src/xenagent/service.h
index acc4d52..fb8a1ee 100644
--- a/src/xenagent/service.h
+++ b/src/xenagent/service.h
@@ -68,6 +68,12 @@ private: // service events
     void OnDeviceEvent(DWORD, LPVOID);
     bool ServiceMainLoop();
 
+private: // helpers
+    void AcquireShutdownPrivilege();
+    void EventLog(DWORD evt);
+    void OnShutdown();
+    void OnSuspend();
+
 private: // service support
     void SetServiceStatus(DWORD state, DWORD exit = 0, DWORD hint = 0);
     void WINAPI __ServiceMain(int argc, char** argv);
@@ -77,10 +83,14 @@ private: // service support
     SERVICE_STATUS_HANDLE   m_handle;
     HANDLE                  m_evtlog;
     HANDLE                  m_svc_stop;
+    HANDLE                  m_evt_shutdown;
+    HANDLE                  m_evt_suspend;
 
     CDeviceList             m_devlist;
     CXenIfaceDevice*        m_device;
     CRITICAL_SECTION        m_crit;
+    void*                   m_ctxt_shutdown;
+    void*                   m_ctxt_suspend;
 };
 
 #endif
-- 
1.9.4.msysgit.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel

 


Rackspace

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