// this thread is signaled when the system wakes from a suspend state DWORD WINAPI ResumeThreadProc(LPVOID lpvParam) { DWORD dwStatus; HANDLE hevReady = (HANDLE) lpvParam; HANDLE hEvents[2]; BOOL fDone = FALSE; INT iPriority; SETFNAME(_T("ResumeThreadProc")); PMLOGMSG(ZONE_INIT, (_T("+%s: thread 0x%08x\r\n"), pszFname, GetCurrentThreadId())); // set the thread priority if(!GetPMThreadPriority(_T("ResumePriority256"), &iPriority)) { iPriority = DEF_RESUME_THREAD_PRIORITY; } CeSetThreadPriority(GetCurrentThread(), iPriority); // we're up and running SetEvent(hevReady); // wait for new devices to arrive hEvents[0] = ghevResume; hEvents[1] = ghevPmShutdown; while(!fDone) { dwStatus = WaitForMultipleObjects(dim(hEvents), hEvents, FALSE, INFINITE); switch(dwStatus) { case (WAIT_OBJECT_0 + 0): PMLOGMSG(ZONE_RESUME, (_T("%s: resume event signaled\r\n"), pszFname)); PlatformResumeSystem(); break; case (WAIT_OBJECT_0 + 1): PMLOGMSG(ZONE_WARN, (_T("%s: shutdown event set\r\n"), pszFname)); fDone = TRUE; break; default: PMLOGMSG(ZONE_WARN, (_T("%s: WaitForMultipleObjects() returned %d, status is %d\r\n"), pszFname, dwStatus, GetLastError())); fDone = TRUE; break; } } PMLOGMSG(ZONE_INIT | ZONE_WARN, (_T("-%s: exiting\r\n"), pszFname)); return 0; }
// this thread handles activity timer events DWORD WINAPI ActivityTimersThreadProc(LPVOID lpvParam) { DWORD dwStatus, dwNumEvents, dwWaitInterval; HANDLE hevReady = (HANDLE) lpvParam; HANDLE hEvents[MAXIMUM_WAIT_OBJECTS]; BOOL fDone = FALSE; HANDLE hevDummy = NULL; INT iPriority; const DWORD cdwTimerBaseIndex = 2; #ifndef SHIP_BUILD SETFNAME(_T("ActivityTimersThreadProc")); #endif PMLOGMSG(ZONE_INIT, (_T("+%s: thread 0x%08x\r\n"), pszFname, GetCurrentThreadId())); // set the thread priority if(!GetPMThreadPriority(_T("TimerPriority256"), &iPriority)) { iPriority = DEF_ACTIVITY_TIMER_THREAD_PRIORITY; } CeSetThreadPriority(GetCurrentThread(), iPriority); // initialize the list of activity timers if(ActivityTimerInitList() != ERROR_SUCCESS) { PMLOGMSG(ZONE_WARN, (_T("%s: ActivityTimerInitList() failed\r\n"), pszFname)); goto done; } // create a dummy event that's never signaled hevDummy = CreateEvent(NULL, FALSE, FALSE, NULL); if(hevDummy == NULL) { PMLOGMSG(ZONE_WARN, (_T("%s: Couldn't create dummy event\r\n"), pszFname)); goto done; } // set up the list of events dwNumEvents = 0; hEvents[dwNumEvents++] = ghevPmShutdown; hEvents[dwNumEvents++] = ghevTimerResume; PMLOCK(); if(gppActivityTimers[0] == NULL) { // no activity timers defined PmFree(gppActivityTimers); gppActivityTimers = NULL; } else { // copy activity timer events into the event list while(dwNumEvents < dim(hEvents) && gppActivityTimers[dwNumEvents - cdwTimerBaseIndex] != NULL) { hEvents[dwNumEvents] = gppActivityTimers[dwNumEvents - cdwTimerBaseIndex]->hevReset; dwNumEvents++; } } PMUNLOCK(); // we're up and running SetEvent(hevReady); // are there actually any timers to wait on? if(dwNumEvents <= cdwTimerBaseIndex) { // no timers defined, so we don't need this thread to wait on them. PMLOGMSG(ZONE_INIT || ZONE_WARN, (_T("%s: no activity timers defined, exiting\r\n"), pszFname)); Sleep(1000); // don't want PM initialization to fail when we exit goto done; } // wait for these events to get signaled PMLOGMSG(ZONE_TIMERS, (_T("%s: entering wait loop, %d timers total\r\n"), pszFname, dwNumEvents - cdwTimerBaseIndex)); dwWaitInterval = 0; while(!fDone) { DWORD dwTimeout = GetNextInactivityTimeout(dwWaitInterval); DWORD dwWaitStart = GetTickCount(); PMLOGMSG(ZONE_TIMERS, (_T("%s: waiting %u (0x%08x) ms for next event, wait interval was %d\r\n"), pszFname, dwTimeout, dwTimeout, dwWaitInterval)); dwStatus = WaitForMultipleObjects(dwNumEvents, hEvents, FALSE, dwTimeout); dwWaitInterval = GetTickCount() - dwWaitStart; // figure out what caused the wakeup if(dwStatus == (WAIT_OBJECT_0 + 0)) { PMLOGMSG(ZONE_WARN, (_T("%s: shutdown event set\r\n"), pszFname)); fDone = TRUE; } else if(dwStatus == (WAIT_OBJECT_0 + 1)) { DWORD dwIndex; PACTIVITY_TIMER pat; // we've resumed, so re-enable all activity timers that can be reset PMLOGMSG(ZONE_TIMERS, (_T("%s: resume event set\r\n"), pszFname)); PMLOCK(); for(dwIndex = 0; (pat = gppActivityTimers[dwIndex]) != NULL; dwIndex++) { DWORD dwEventIndex = dwIndex + cdwTimerBaseIndex; if(hEvents[dwEventIndex] == hevDummy) { hEvents[dwEventIndex] = pat->hevReset; } pat->dwTimeLeft = pat->dwTimeout + dwWaitInterval; } PMUNLOCK(); } else if(dwStatus == WAIT_TIMEOUT) { DWORD dwIndex; PACTIVITY_TIMER pat; // figure out which event(s) timed out PMLOCK(); for(dwIndex = 0; (pat = gppActivityTimers[dwIndex]) != NULL; dwIndex++) { if(pat->dwTimeLeft <= dwWaitInterval && pat->dwTimeLeft != INFINITE) { // has the timer really expired? if(WaitForSingleObject(pat->hevReset, 0) == WAIT_OBJECT_0) { // The timer was reset while we weren't looking at it, so we'll look // at it again later. Calculate the new timeout, compensating for the update // that will occur in GetNextInactivityTimeout(). PMLOGMSG(ZONE_TIMERS, (_T("%s: timer '%s' reset after timeout\r\n"), pszFname, pat->pszName)); pat->dwTimeLeft = pat->dwTimeout + dwWaitInterval; pat->dwResetCount++; } else { // the timer has really expired, update events appropriately PMLOGMSG(ZONE_TIMERS, (_T("%s: timer '%s' has expired\r\n"), pszFname, pat->pszName)); ResetEvent(pat->hevActive); SetEvent(pat->hevInactive); // start looking at the reset event for this timer again hEvents[dwIndex + cdwTimerBaseIndex] = pat->hevReset; // update counts pat->dwTimeLeft = INFINITE; pat->dwExpiredCount++; } } } PMUNLOCK(); } else if(dwStatus > (WAIT_OBJECT_0 + 0) && dwStatus < (WAIT_OBJECT_0 + dwNumEvents)) { PACTIVITY_TIMER pat; DWORD dwEventIndex = dwStatus - WAIT_OBJECT_0; PMLOCK(); // get a pointer to the timer pat = gppActivityTimers[dwEventIndex - cdwTimerBaseIndex]; // handle its events DEBUGCHK(pat != NULL); if(pat->dwTimeout == 0) { // we're not using the event, so ignore it pat->dwTimeLeft = INFINITE; } else { PMLOGMSG(ZONE_TIMERS, (_T("%s: timer '%s' reset\r\n"), pszFname, pat->pszName)); // set events appropriately ResetEvent(pat->hevInactive); SetEvent(pat->hevActive); // don't look at this event again until it's about ready to time out hEvents[dwEventIndex] = hevDummy; // update time left on the timer, compensating for the update // that will occur in GetNextInactivityTimeout(). pat->dwTimeLeft = pat->dwTimeout + dwWaitInterval; } pat->dwResetCount++; PMUNLOCK(); } else { PMLOGMSG(ZONE_WARN, (_T("%s: WaitForMultipleObjects() returned %d, status is %d\r\n"), pszFname, dwStatus, GetLastError())); fDone = TRUE; } } done: // release resources if(hevDummy != NULL) CloseHandle(hevDummy); PMLOCK(); if(gppActivityTimers != NULL) { DWORD dwIndex = 0; while(gppActivityTimers[dwIndex] != NULL) { ActivityTimerDestroy(gppActivityTimers[dwIndex]); dwIndex++; } PmFree(gppActivityTimers); gppActivityTimers = NULL; } PMUNLOCK(); PMLOGMSG(ZONE_INIT | ZONE_WARN, (_T("-%s: exiting\r\n"), pszFname)); return 0; }
DWORD WINAPI PnpThreadProc(LPVOID lpvParam) { DWORD dwStatus; HANDLE hnGeneric = NULL; HANDLE hevReady = (HANDLE) lpvParam; HANDLE hEvents[MAXIMUM_WAIT_OBJECTS]; DWORD dwNumEvents = 0; BOOL fDone = FALSE; BOOL fOk; INT iPriority; PDEVICE_LIST pdl; SETFNAME(_T("PnpThreadProc")); PMLOGMSG(ZONE_INIT, (_T("+%s: thread 0x%08x\r\n"), pszFname, GetCurrentThreadId())); // set the thread priority if(!GetPMThreadPriority(_T("PnPPriority256"), &iPriority)) { iPriority = DEF_PNP_THREAD_PRIORITY; } CeSetThreadPriority(GetCurrentThread(), iPriority); // first list entry is the exit event hEvents[dwNumEvents++] = ghevPmShutdown; // set up device notifications for(pdl = gpDeviceLists; pdl != NULL && dwNumEvents < dim(hEvents); pdl = pdl->pNext) { hEvents[dwNumEvents++] = pdl->hMsgQ; pdl->hnClass = RequestDeviceNotifications(pdl->pGuid, pdl->hMsgQ, TRUE); if(pdl->hnClass == NULL) { PMLOGMSG(ZONE_WARN, (_T("%s: RequestDeviceNotifications() failed %d\r\n"), pszFname, GetLastError())); } } DEBUGCHK(dwNumEvents > 1); // we're up and running SetEvent(hevReady); // Wait for Initalization complete. HANDLE hInit[2] = {ghevPowerManagerReady, ghevPmShutdown}; fDone = (WaitForMultipleObjects(_countof(hInit), hInit, FALSE, INFINITE)!= WAIT_OBJECT_0); // wait for new devices to arrive while(!fDone) { dwStatus = WaitForMultipleObjects(dwNumEvents, hEvents, FALSE, INFINITE); if(dwStatus == (WAIT_OBJECT_0 + 0)) { PMLOGMSG(ZONE_WARN, (_T("%s: shutdown event set\r\n"), pszFname)); fDone = TRUE; } else if(dwStatus > WAIT_OBJECT_0 && dwStatus <= (WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS)) { dwStatus -= WAIT_OBJECT_0; fOk = ProcessPnPMsgQueue(hEvents[dwStatus]); if(!fOk) { PMLOGMSG(ZONE_WARN, (_T("%s: ProcessPnPMsgQueue(0x%08x) failed\r\n"), pszFname, hEvents[dwStatus])); } } else { PMLOGMSG(ZONE_WARN, (_T("%s: WaitForMultipleObjects() returned %d, status is %d\r\n"), pszFname, dwStatus, GetLastError())); fDone = TRUE; break; } } // release resources for(pdl = gpDeviceLists; pdl != NULL; pdl = pdl->pNext) { if(pdl->hnClass != NULL) StopDeviceNotifications(pdl->hnClass); } // all done PMLOGMSG(ZONE_INIT | ZONE_WARN, (_T("-%s: exiting\r\n"), pszFname)); return 0; }
EXTERN_C VOID WINAPI PlatformManageSystemPower (HANDLE hevReady) { BOOL fDone = FALSE; HANDLE hqNotify = NULL; HMODULE hmCoreDll = NULL; SETFNAME (_T ("PlatformManageSystemPower")); PMLOGMSG (ZONE_INIT || ZONE_PLATFORM, (_T ("+%s\r\n"), pszFname)); // Initialize globals: ghevReloadActivityTimeouts = NULL; ghevRestartTimers = NULL; // Determine thread priority settings while we're suspending (in case // of priority inversion): if (!GetPMThreadPriority (_T ("PreSuspendPriority256"), &giPreSuspendPriority)) { giPreSuspendPriority = DEF_PRESUSPEND_THREAD_PRIORITY; } if (!GetPMThreadPriority (_T ("SuspendPriority256"), &giSuspendPriority)) { giSuspendPriority = DEF_SUSPEND_THREAD_PRIORITY; } // Get pointers to GWES's suspend/routine APIs. These require GWES, so the OEM may // not have them on this platform. Also get battery level APIs, which require a // battery driver and may not be present. hmCoreDll = (HMODULE) LoadLibrary (_T ("coredll.dll")); gfGwesReady = FALSE; PmInitPowerStatus (hmCoreDll); if (hmCoreDll != NULL) { gpfnGwesPowerDown = (PFN_GwesPowerDown) GetProcAddress (hmCoreDll, _T ("GwesPowerDown")); gpfnGwesPowerUp = (PFN_GwesPowerUp) GetProcAddress (hmCoreDll, _T ("GwesPowerUp")); // Do we have both GWES suspend/resume APIs? if (gpfnGwesPowerDown == NULL || gpfnGwesPowerUp == NULL) { // No, ignore GWES. gpfnGwesPowerDown = NULL; gpfnGwesPowerUp = NULL; } } // Create events: ghevReloadActivityTimeouts = CreateEvent (NULL, FALSE, FALSE, _T ("PowerManager/ReloadActivityTimeouts")); ghevRestartTimers = CreateEvent (NULL, FALSE, FALSE, NULL); if (ghevReloadActivityTimeouts == NULL || ghevRestartTimers == NULL) { PMLOGMSG (ZONE_WARN, (_T ("%s: CreateEvent() failed for system event\r\n"), pszFname)); goto done; } // Create our notification queue: hqNotify = PmPolicyCreateNotificationQueue (); if (hqNotify == NULL) { PMLOGMSG (ZONE_WARN, (_T ("%s: PmPolicyCreateNotificationQueue() failed\r\n"), pszFname)); goto done; } if (!fDone) { // Instantiate the PowerStateManager object and call its Init method: PowerStateManager *pPowerStateManager = new PowerStateManager (); if (pPowerStateManager && pPowerStateManager->Init ()) { g_pPowerStateManager = pPowerStateManager; // We're up and running: SetEvent (hevReady); g_pPowerStateManager->ThreadRun (); } else { // Power Manager initialization failed: ASSERT (FALSE); if (pPowerStateManager) delete pPowerStateManager; PMLOGMSG (ZONE_INIT || ZONE_ERROR, (_T ("%s: PowerStateManager Intialization Failed!!!\r\n"), pszFname)); } if (g_pPowerStateManager) { delete g_pPowerStateManager; g_pPowerStateManager = NULL; } } done: // Clean up before exiting: if (ghevReloadActivityTimeouts == NULL) { CloseHandle (ghevReloadActivityTimeouts); ghevReloadActivityTimeouts = NULL; } if (ghevRestartTimers != NULL) { CloseHandle (ghevRestartTimers); ghevRestartTimers = NULL; } if (hqNotify != NULL) { PmPolicyCloseNotificationQueue (hqNotify); hqNotify = NULL; } if (hmCoreDll != NULL) FreeLibrary (hmCoreDll); PMLOGMSG (ZONE_PLATFORM, (_T ("-%s: exiting\r\n"), pszFname)); }