[win32] Move call to SetSuspendState/InitiateShutdown out from main thread.
authorAnton Fedchin <afedchin@ruswizards.com>
Mon, 3 Aug 2015 15:47:02 +0000 (18:47 +0300)
committerAnton Fedchin <afedchin@ruswizards.com>
Tue, 4 Aug 2015 19:15:37 +0000 (22:15 +0300)
Calling SetSuspend in main thread prevents to receiving WM_POWERBROADCAST message on Suspend/Hibernate. This restores receiving WM_POWERBROADCAST message.

xbmc/powermanagement/windows/Win32PowerSyscall.cpp
xbmc/powermanagement/windows/Win32PowerSyscall.h
xbmc/win32/WIN32Util.cpp

index 09787ca..cbc9842 100644 (file)
 bool CWin32PowerSyscall::m_OnResume = false;
 bool CWin32PowerSyscall::m_OnSuspend = false;
 
+bool CWin32PowerStateWorker::QueryStateChange(PowerState state)
+{
+  if (!IsRunning())
+    return false;
+
+  if (m_state.exchange(state) != state)
+  {
+    m_queryEvent.Set();
+    return true;
+  }
+
+  return false;
+}
+
+void CWin32PowerStateWorker::Process(void)
+{
+  while (!m_bStop)
+  {
+    if (AbortableWait(m_queryEvent, -1) == WAIT_SIGNALED)
+    {
+      CWIN32Util::PowerManagement(m_state.load());
+      m_state.exchange(POWERSTATE_NONE);
+      m_queryEvent.Reset();
+    }
+  }
+}
 
 CWin32PowerSyscall::CWin32PowerSyscall()
 {
+  m_worker.Create();
+}
+
+CWin32PowerSyscall::~CWin32PowerSyscall()
+{
+  if (m_worker.IsRunning())
+    m_worker.StopThread();
 }
 
 bool CWin32PowerSyscall::Powerdown()
 {
-  return CWIN32Util::PowerManagement(POWERSTATE_SHUTDOWN);
+  return m_worker.QueryStateChange(POWERSTATE_SHUTDOWN);
 }
 bool CWin32PowerSyscall::Suspend()
 {
-  // On Vista+, we don't receive the PBT_APMSUSPEND message as we have fired the suspend mode
-  // Set the flag manually
-  CWin32PowerSyscall::SetOnSuspend();
-
-  return CWIN32Util::PowerManagement(POWERSTATE_SUSPEND);
+  return m_worker.QueryStateChange(POWERSTATE_SUSPEND);
 }
 bool CWin32PowerSyscall::Hibernate()
 {
-  // On Vista+, we don't receive the PBT_APMSUSPEND message as we have fired the suspend mode
-  // Set the flag manually
-  CWin32PowerSyscall::SetOnSuspend();
-
-  return CWIN32Util::PowerManagement(POWERSTATE_HIBERNATE);
+  return m_worker.QueryStateChange(POWERSTATE_HIBERNATE);
 }
 bool CWin32PowerSyscall::Reboot()
 {
-  return CWIN32Util::PowerManagement(POWERSTATE_REBOOT);
+  return m_worker.QueryStateChange(POWERSTATE_REBOOT);
 }
 
 bool CWin32PowerSyscall::CanPowerdown()
index 95d4027..f2f0dd7 100644 (file)
 #ifndef _WIN32_POWER_SYSCALL_H_
 #define _WIN32_POWER_SYSCALL_H_
 #include "powermanagement/IPowerSyscall.h"
+#include "powermanagement/PowerManager.h"
+#include "threads/Event.h"
+#include "threads/Thread.h"
+#include <atomic>
+
+class CWin32PowerStateWorker : public CThread
+{
+public:
+  CWin32PowerStateWorker() : CThread("CWin32PowerStateWorker"), m_queryEvent(true), m_state(POWERSTATE_NONE) {}
+  bool QueryStateChange(PowerState State);
+
+protected:
+  virtual void Process(void);
+  virtual void OnStartup() { SetPriority(THREAD_PRIORITY_IDLE); };
+
+private:
+  std::atomic<PowerState> m_state;
+  CEvent                  m_queryEvent;
+};
 
 class CWin32PowerSyscall : public CAbstractPowerSyscall
 {
 public:
   CWin32PowerSyscall();
+  ~CWin32PowerSyscall();
 
   virtual bool Powerdown();
   virtual bool Suspend();
@@ -48,6 +68,7 @@ public:
   static bool IsSuspending() { return m_OnSuspend; }
 
 private:
+  CWin32PowerStateWorker m_worker;
 
   static bool m_OnResume;
   static bool m_OnSuspend;
index 86d62fa..d166bc2 100644 (file)
@@ -216,18 +216,15 @@ bool CWIN32Util::PowerManagement(PowerState State)
       return false;
   }
 
-  // process OnSleep() events. This is called in main thread.
-  g_powerManager.ProcessEvents();
-
   switch (State)
   {
   case POWERSTATE_HIBERNATE:
     CLog::Log(LOGINFO, "Asking Windows to hibernate...");
-    return SetSuspendState(true,true,false) == TRUE;
+    return SetSuspendState(true, true, false) == TRUE;
     break;
   case POWERSTATE_SUSPEND:
     CLog::Log(LOGINFO, "Asking Windows to suspend...");
-    return SetSuspendState(false,true,false) == TRUE;
+    return SetSuspendState(false, true, false) == TRUE;
     break;
   case POWERSTATE_SHUTDOWN:
     CLog::Log(LOGINFO, "Shutdown Windows...");