#include <sys/types.h>
#include <sys/sysctl.h>
#include <notify.h>
#include "PrivateLib.h"
#include "SystemLoad.h"
#include "PMStore.h"
const bool kNoNotify = false;
const bool kYesNotify = true;
static void shareTheSystemLoad(bool shouldNotify);
static CFStringRef systemLoadKey = NULL;
static CFStringRef systemLoadDetailedKey = NULL;
static bool onACPower = FALSE;
static bool onBatteryPower = FALSE;
static bool batteryBelowThreshold = FALSE;
static bool coresConstrained = FALSE;
static bool forcedIdle = FALSE;
static bool plimitBelowThreshold = FALSE;
static bool thermalWarningLevel = FALSE;
static bool loggedInUser = FALSE;
static bool displayIsAsleep = FALSE;
static bool displaySleepEnabled = FALSE;
static int gNotifyToken = 0;
static int minOfThree(int a, int b, int c)
{
int result = a;
if (b < result) result = b;
if (c < result) result = c;
return result;
}
static void shareTheSystemLoad(bool shouldNotify)
{
static uint64_t lastSystemLoad = 0;
uint64_t theseSystemLoad = 0;
int userLevel = kIOSystemLoadAdvisoryLevelGreat;
int batteryLevel = kIOSystemLoadAdvisoryLevelGreat;
int powerLevel = kIOSystemLoadAdvisoryLevelGreat;
int combinedLevel = kIOSystemLoadAdvisoryLevelGreat;
if (onACPower) {
batteryLevel = kIOSystemLoadAdvisoryLevelGreat;
} else if (!batteryBelowThreshold) {
batteryLevel = kIOSystemLoadAdvisoryLevelOK;
} else {
batteryLevel = kIOSystemLoadAdvisoryLevelBad;
}
if (plimitBelowThreshold) {
powerLevel = kIOSystemLoadAdvisoryLevelOK;
}
if (coresConstrained || forcedIdle || thermalWarningLevel) {
powerLevel = kIOSystemLoadAdvisoryLevelBad;
}
if (loggedInUser) {
if (displaySleepEnabled && displayIsAsleep)
{
userLevel = kIOSystemLoadAdvisoryLevelGreat;
} else {
userLevel = kIOSystemLoadAdvisoryLevelOK;
}
}
combinedLevel = minOfThree(userLevel, batteryLevel, powerLevel);
theseSystemLoad = combinedLevel
| (userLevel << 8)
| (batteryLevel << 16)
| (powerLevel << 24);
if (theseSystemLoad != lastSystemLoad)
{
CFMutableDictionaryRef publishDetails = NULL;
CFNumberRef publishNum = NULL;
lastSystemLoad = theseSystemLoad;
notify_set_state(gNotifyToken, (uint64_t)combinedLevel);
publishNum = CFNumberCreate(0, kCFNumberSInt64Type, &theseSystemLoad);
if (publishNum)
{
PMStoreSetValue(systemLoadKey, publishNum);
CFRelease(publishNum);
publishNum = NULL;
}
publishDetails = CFDictionaryCreateMutable(0, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!publishDetails) return;
publishNum = CFNumberCreate(0, kCFNumberIntType, &userLevel);
if (publishNum) {
CFDictionarySetValue(publishDetails,
kIOSystemLoadAdvisoryUserLevelKey,
publishNum);
CFRelease(publishNum);
publishNum = 0;
}
publishNum = CFNumberCreate(0, kCFNumberIntType, &batteryLevel);
if (publishNum) {
CFDictionarySetValue(publishDetails,
kIOSystemLoadAdvisoryBatteryLevelKey,
publishNum);
CFRelease(publishNum);
publishNum = 0;
}
publishNum = CFNumberCreate(0, kCFNumberIntType, &powerLevel);
if (publishNum) {
CFDictionarySetValue(publishDetails,
kIOSystemLoadAdvisoryThermalLevelKey,
publishNum);
CFRelease(publishNum);
publishNum = 0;
}
publishNum = CFNumberCreate(0, kCFNumberIntType, &combinedLevel);
if (publishNum) {
CFDictionarySetValue(publishDetails,
kIOSystemLoadAdvisoryCombinedLevelKey,
publishNum);
CFRelease(publishNum);
publishNum = 0;
}
PMStoreSetValue(systemLoadDetailedKey, publishDetails);
CFRelease(publishDetails);
if (shouldNotify) {
notify_post(kIOSystemLoadAdvisoryNotifyName);
}
}
}
__private_extern__ void SystemLoad_prime(void)
{
systemLoadKey = SCDynamicStoreKeyCreate(
kCFAllocatorDefault,
CFSTR("%@%@"),
kSCDynamicStoreDomainState,
CFSTR("/IOKit/PowerManagement/SystemLoad"));
systemLoadDetailedKey = SCDynamicStoreKeyCreate(
kCFAllocatorDefault,
CFSTR("%@%@"),
kSCDynamicStoreDomainState,
CFSTR("/IOKit/PowerManagement/SystemLoad/Detailed"));
notify_register_check(kIOSystemLoadAdvisoryNotifyName, &gNotifyToken);
SystemLoadBatteriesHaveChanged(_batteries());
SystemLoadPrefsHaveChanged();
#if !TARGET_OS_EMBEDDED
SystemLoadUserStateHasChanged();
#endif
SystemLoadCPUPowerHasChanged(NULL);
}
__private_extern__ void SystemLoadDisplayPowerStateHasChanged(bool displayIsOff)
{
if (displayIsOff == displayIsAsleep) {
return;
}
displayIsAsleep = displayIsOff;
shareTheSystemLoad(kYesNotify);
}
__private_extern__ void SystemLoadPrefsHaveChanged(void)
{
SCDynamicStoreRef _store = _getSharedPMDynamicStore();
CFDictionaryRef liveSettings = NULL;
CFNumberRef displaySleep = NULL;
int idle;
static bool lastDisplaySleep = false;
liveSettings = SCDynamicStoreCopyValue(_store,
CFSTR(kIOPMDynamicStoreSettingsKey));
if (liveSettings)
{
displaySleep = CFDictionaryGetValue(liveSettings,
CFSTR(kIOPMDisplaySleepKey));
if (displaySleep)
{
CFNumberGetValue(displaySleep, kCFNumberIntType, &idle);
displaySleepEnabled = idle ? true:false;
if (displaySleepEnabled != lastDisplaySleep)
{
lastDisplaySleep = displaySleepEnabled;
shareTheSystemLoad(kYesNotify);
}
}
CFRelease(liveSettings);
}
return;
}
__private_extern__ void SystemLoadBatteriesHaveChanged(IOPMBattery **batt_stats)
{
static const int kBatThreshold = 40;
int count = _batteryCount();
int sumMax = 0;
int sumCurrent = 0;
int i;
onACPower = false;
onBatteryPower = false;
batteryBelowThreshold = false;
if (0 == count)
{
onACPower = true;
goto exit;
}
for (i=0; i<count; i++)
{
if( batt_stats[i]->externalConnected ) {
onACPower = true;
}
sumCurrent += batt_stats[i]->currentCap;
sumMax += batt_stats[i]->maxCap;
}
if (!onACPower)
{
onBatteryPower = true;
}
if (sumMax
&& (kBatThreshold > (100*sumCurrent)/sumMax))
{
batteryBelowThreshold = true;
}
exit:
shareTheSystemLoad(kYesNotify);
}
__private_extern__ void SystemLoadCPUPowerHasChanged(CFDictionaryRef newCPU)
{
CFDictionaryRef ourAllocatedCPU = NULL;
CFNumberRef plimitNum = NULL;
int plimit = 100; CFNumberRef cpuCountNum = NULL;
int cpuCount = 0;
static int maxCPUCount = 0;
CFNumberRef runnableTimeNum = NULL;
int runnableTime = 100; uint32_t getlevel = 0;
IOReturn ret;
if (0 == maxCPUCount) {
int result;
size_t len;
result = sysctlbyname("hw.ncpu", &maxCPUCount, &len, 0, 0);
if (-1 == result) { maxCPUCount = 0;
}
}
cpuCount = maxCPUCount;
ret = IOPMGetThermalWarningLevel(&getlevel);
if ( (kIOReturnSuccess == ret)
&& (kIOPMThermalWarningLevelNormal != getlevel))
{
thermalWarningLevel = true;
} else {
thermalWarningLevel = false;
}
coresConstrained = false;
forcedIdle = false;
plimitBelowThreshold = false;
if (!newCPU) {
ret = IOPMCopyCPUPowerStatus(&ourAllocatedCPU);
if (kIOReturnSuccess == ret) {
newCPU = ourAllocatedCPU;
} else {
goto exit;
}
}
if (!newCPU)
goto exit;
plimitNum = CFDictionaryGetValue(newCPU, CFSTR(kIOPMCPUPowerLimitProcessorSpeedKey));
if (plimitNum) {
CFNumberGetValue(plimitNum, kCFNumberIntType, &plimit);
}
cpuCountNum = CFDictionaryGetValue(newCPU, CFSTR(kIOPMCPUPowerLimitProcessorCountKey));
if (cpuCountNum) {
CFNumberGetValue(cpuCountNum, kCFNumberIntType, &cpuCount);
}
runnableTimeNum = CFDictionaryGetValue(newCPU, CFSTR(kIOPMCPUPowerLimitSchedulerTimeKey));
if (runnableTimeNum) {
CFNumberGetValue(runnableTimeNum, kCFNumberIntType, &runnableTime);
}
if (50 >= plimit) {
plimitBelowThreshold = true;
}
if (maxCPUCount > cpuCount) {
coresConstrained = true;
}
if (100 != runnableTime) {
forcedIdle = true;
}
shareTheSystemLoad(kYesNotify);
exit:
if (ourAllocatedCPU)
CFRelease(ourAllocatedCPU);
return;
}
#if !TARGET_OS_EMBEDDED
__private_extern__ void SystemLoadUserStateHasChanged(void)
{
CFStringRef loggedInUserName;
loggedInUser = false;
loggedInUserName = SCDynamicStoreCopyConsoleUser(_getSharedPMDynamicStore(),
NULL, NULL); if (loggedInUserName) {
loggedInUser = true;
CFRelease(loggedInUserName);
}
shareTheSystemLoad(kYesNotify);
}
#endif