#include "powermanagementServer.h" // mig generated
#include <asl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <mach/mach.h>
#include <mach/message.h>
#include <notify.h>
#include "PrivateLib.h"
#include "PMConnection.h"
#include "AutoWakeScheduler.h"
#include "RepeatingAutoWake.h"
enum {
kSleepWakeInterestBit = 1,
kMaintenanceInterestBit = 2
};
enum {
_kSleepStateBits = 0x0000,
_kOnStateBits = 0xFFFF
};
static int const kMaxConnectionIDCount = 1000*1000*1000;
static int const kConnectionOffset = 1000;
static double const kPMConnectionNotifyTimeoutDefault = 25.0;
extern CFMachPortRef pmServerMachPort;
typedef struct {
CFMutableArrayRef awaitingResponses;
CFRunLoopTimerRef awaitingResponsesTimeout;
CFAbsoluteTime allRepliedTime;
long kernelAcknowledgementID;
int notificationType;
int awaitingResponsesCount;
int awaitResponsesTimeoutSeconds;
int completedStatus; bool needsMaintenanceWake;
bool completed;
bool nextIsValid;
long nextKernelAcknowledgementID;
int nextInterestBits;
} PMResponseWrangler;
typedef struct {
mach_port_t notifyPort;
PMResponseWrangler *responseHandler;
CFStringRef callerName;
uint32_t uniqueID;
int callerPID;
IOPMSystemPowerStateCapabilities interestsBits;
} PMConnection;
typedef struct {
PMConnection *connection;
PMResponseWrangler *myResponseWrangler;
IOPMConnectionMessageToken token;
CFAbsoluteTime repliedWhen;
CFAbsoluteTime notifiedWhen;
CFAbsoluteTime maintenanceRequested;
int notificationType;
bool replied;
bool timedout;
} PMResponse;
#define kIOPMPrivilegedPowerInterest "IOPMPrivilegedPowerInterest"
#define kIOPMRootDomainRunStateKey "Run State"
static IOReturn createConnectionWithID(
PMConnection **);
static PMConnection *connectionForID(
uint32_t findMe);
static CFArrayRef createArrayOfConnectionsWithInterest(
int interestBitsNotify);
static PMResponseWrangler *connectionFireNotification(
int notificationType,
long kernelAcknowledgementID);
static void _sendMachMessage(
mach_port_t port,
mach_msg_id_t msg_id,
uint32_t payload_bits,
uint32_t payload_messagetoken);
static void checkResponses(PMResponseWrangler *wrangler);
static void responsesTimedOut(CFRunLoopTimerRef timer, void * info);
static void cleanupConnection(PMConnection *reap);
static void cleanupResponseWrangler(PMResponseWrangler *reap);
static void setSystemSleepStateTracking(IOPMSystemPowerStateCapabilities);
static void PMConnectionPowerCallBack(
void *port,
io_service_t rootdomainservice,
natural_t messageType,
void *acknowledgementToken);
__private_extern__ void
ClockSleepWakeNotification(
natural_t messageType);
static Boolean _CFArrayConnectionEquality(const void *value1, const void *value2)
{
const PMConnection *v1 = (const PMConnection *)value1;
const PMConnection *v2 = (const PMConnection *)value2;
return (v1->uniqueID == v2->uniqueID);
}
static CFArrayCallBacks _CFArrayConnectionCallBacks =
{ 0, NULL, NULL, NULL, _CFArrayConnectionEquality };
static CFArrayCallBacks _CFArrayVanillaCallBacks =
{ 0, NULL, NULL, NULL, NULL };
static CFMutableArrayRef gConnections = NULL;
static uint32_t globalConnectionIDTally = 0;
static io_connect_t gRootDomainConnect = IO_OBJECT_NULL;
static PMResponseWrangler * gLastResponseWrangler = NULL;
__private_extern__
void PMConnection_prime()
{
io_service_t rootDomainService = IO_OBJECT_NULL;
io_object_t sleepWakeCallbackHandle = IO_OBJECT_NULL;
IONotificationPortRef notify = NULL;
kern_return_t kr = 0;
char *errorString = NULL;
gConnections = CFArrayCreateMutable(kCFAllocatorDefault, 100,
&_CFArrayConnectionCallBacks);
rootDomainService = getRootDomain();
if (IO_OBJECT_NULL == rootDomainService) {
errorString = "Could not find IOPMrootDomain";
goto error;
}
kr = IOServiceOpen(rootDomainService, mach_task_self(), 0, &gRootDomainConnect);
if (KERN_SUCCESS != kr) {
errorString = "Could not open IOPMrootDomain";
goto error;
}
notify = IONotificationPortCreate(MACH_PORT_NULL);
if (!notify) {
errorString = "Could not create IONotificationPort";
goto error;
}
kr = IOServiceAddInterestNotification(
notify,
rootDomainService,
kIOPMPrivilegedPowerInterest,
(IOServiceInterestCallback) PMConnectionPowerCallBack,
NULL,
&sleepWakeCallbackHandle);
if (KERN_SUCCESS != kr) {
errorString = "Could not add interest notification kIOPMPrivilegedPowerInterest";
goto error;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(notify),
kCFRunLoopDefaultMode);
return;
error:
asl_log(NULL, NULL, ASL_LEVEL_ERR,
"PowerManagement: unable to register with kernel power management. %s %s",
errorString ? "Reason = : ":"", errorString ? errorString:"");
return;
}
kern_return_t _io_pm_connection_create
(
mach_port_t server,
mach_port_t task_in,
string_t name,
int interests,
uint32_t *connection_id,
int *return_code
)
{
PMConnection *newConnection = NULL;
int task_pid;
createConnectionWithID(&newConnection);
if (!newConnection) {
*return_code = kIOReturnError;
goto exit;
}
if (KERN_SUCCESS == pid_for_task(task_in, &task_pid)) {
newConnection->callerPID = task_pid;
}
if (name && strlen(name)) {
newConnection->callerName = CFStringCreateWithCString(0, name,
kCFStringEncodingUTF8);
}
newConnection->interestsBits = 0xFF;
*connection_id = newConnection->uniqueID;
*return_code = kIOReturnSuccess;
exit:
if (MACH_PORT_NULL != task_in)
{
__MACH_PORT_DEBUG(true, "_io_pm_connection_create dropping send right", task_in);
mach_port_deallocate(mach_task_self(), task_in);
}
return KERN_SUCCESS;
}
kern_return_t _io_pm_connection_schedule_notification(
mach_port_t server,
uint32_t connection_id,
mach_port_t notify_port_in,
int disable,
int *return_code)
{
PMConnection *connection = NULL;
mach_port_t oldNotify;
if (MACH_PORT_NULL == notify_port_in || NULL == return_code) {
if (return_code) *return_code = kIOReturnBadArgument;
goto exit;
}
__MACH_PORT_DEBUG(true, "_io_pm_connection_schedule_notification notify_port", notify_port_in);
*return_code = kIOReturnError;
connection = connectionForID(connection_id);
if (!connection) {
return kIOReturnNotFound;
}
connection->notifyPort = notify_port_in;
mach_port_request_notification(
mach_task_self(), notify_port_in, MACH_NOTIFY_DEAD_NAME, 1, CFMachPortGetPort(pmServerMachPort), MACH_MSG_TYPE_MAKE_SEND_ONCE, &oldNotify);
__MACH_PORT_DEBUG(true, "Registered dead name notification on notifyPort", notify_port_in);
*return_code = kIOReturnSuccess;
exit:
return KERN_SUCCESS;
}
kern_return_t _io_pm_connection_release
(
mach_port_t server,
uint32_t connection_id,
int *return_code
)
{
PMConnection *cleanMeUp = NULL;
cleanMeUp = connectionForID(connection_id);
if (cleanMeUp) {
cleanupConnection(cleanMeUp);
if (return_code)
*return_code = kIOReturnSuccess;
} else {
if (return_code)
*return_code = kIOReturnNotFound;
}
return KERN_SUCCESS;
}
kern_return_t _io_pm_connection_acknowledge_event
(
mach_port_t server,
uint32_t connection_id,
int messageToken,
vm_offset_t options_ptr,
mach_msg_type_number_t options_len,
int *return_code
)
{
#if TARGET_OS_EMBEDDED
return KERN_FAILURE;
#else
PMConnection *connection = connectionForID(connection_id);
PMResponse *checkResponse = NULL;
PMResponse *foundResponse = NULL;
CFMutableArrayRef responsesTrackingList = NULL;
int responsesCount = 0;
int i;
int timeIntervalMS;
CFDictionaryRef ackOptionsDict = NULL;
CFDateRef maintenanceDate = NULL;
CFNumberRef maintenanceRequirementBits = NULL;
int maintRequireBitfield = 0;
CFDataRef optionsAsData = NULL;
CFPropertyListRef optionsUnzipped = NULL;
if (!connection) {
*return_code = kIOReturnNotFound;
goto exit;
}
if (!connection->responseHandler) {
*return_code = kIOReturnNotFound;
goto exit;
}
responsesTrackingList = connection->responseHandler->awaitingResponses;
if (!responsesTrackingList) {
*return_code = kIOReturnNotFound;
goto exit;
}
responsesCount = CFArrayGetCount(responsesTrackingList);
for (i=0; i<responsesCount; i++)
{
checkResponse = (PMResponse *)CFArrayGetValueAtIndex(responsesTrackingList, i);
if (checkResponse && (messageToken == checkResponse->token)) {
foundResponse = checkResponse;
break;
}
}
if (!foundResponse) {
*return_code = kIOReturnNotFound;
goto exit;
}
foundResponse->repliedWhen = CFAbsoluteTimeGetCurrent();
foundResponse->replied = true;
timeIntervalMS = (int)((foundResponse->repliedWhen - foundResponse->notifiedWhen) * 1000);
if (timeIntervalMS > kAppResponseLogThresholdMS) {
CFNumberRef timeIntervalNumber = CFNumberCreate(NULL, kCFNumberIntType, &timeIntervalMS);
logASLMessageApplicationResponse(
kAppResponseLogSourcePMConnection,
connection->callerName,
CFSTR(kIOPMStatsResponseSlow),
timeIntervalNumber);
if (timeIntervalNumber)
CFRelease(timeIntervalNumber);
}
if ( options_ptr != 0 && options_len != 0)
{
optionsAsData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
(const uint8_t *)options_ptr,
options_len,
kCFAllocatorNull);
if (optionsAsData)
{
optionsUnzipped = CFPropertyListCreateWithData(0, optionsAsData, kCFPropertyListImmutable, NULL, NULL);
ackOptionsDict = (CFDictionaryRef) isA_CFDictionary(optionsUnzipped);
}
if (ackOptionsDict)
{
maintenanceDate = isA_CFDate(
CFDictionaryGetValue(ackOptionsDict,
kIOPMAcknowledgmentOptionWakeDate));
maintenanceRequirementBits = isA_CFNumber(
CFDictionaryGetValue(ackOptionsDict,
kIOPMAcknowledgmentOptionSystemCapabilityRequirements));
if (maintenanceDate && maintenanceRequirementBits)
{
connection->responseHandler->needsMaintenanceWake = true;
foundResponse->maintenanceRequested = CFDateGetAbsoluteTime(maintenanceDate);
CFNumberGetValue(maintenanceRequirementBits, kCFNumberSInt32Type,
&maintRequireBitfield);
}
}
}
checkResponses(connection->responseHandler);
*return_code = kIOReturnSuccess;
exit:
if (optionsAsData) CFRelease(optionsAsData);
if (optionsUnzipped) CFRelease(optionsUnzipped);
vm_deallocate(mach_task_self(), options_ptr, options_len);
return KERN_SUCCESS;
#endif
}
kern_return_t _io_pm_connection_copy_status
(
mach_port_t server,
int status_index,
vm_offset_t *status_data,
mach_msg_type_number_t *status_dataCnt,
int *return_val
)
{
return KERN_SUCCESS;
}
static void cleanupConnection(PMConnection *reap)
{
PMResponseWrangler *responseWrangler = NULL;
PMResponse *openResponse = NULL;
int allResponsesCount = 0;
int i;
int index;
CFRange connectionsRange =
CFRangeMake(0, CFArrayGetCount(gConnections));
if (MACH_PORT_NULL != reap->notifyPort) {
__MACH_PORT_DEBUG(true, "IOPMConnection cleanupConnection drop notifyPort", reap->notifyPort);
mach_port_deallocate(mach_task_self(), reap->notifyPort);
reap->notifyPort = MACH_PORT_NULL;
}
if (reap->callerName) {
CFRelease(reap->callerName);
reap->callerName = NULL;
}
responseWrangler = reap->responseHandler;
if (responseWrangler && responseWrangler->awaitingResponses)
{
allResponsesCount = CFArrayGetCount(responseWrangler->awaitingResponses);
for (i=0; i<allResponsesCount; i++)
{
openResponse = (PMResponse *)CFArrayGetValueAtIndex(
responseWrangler->awaitingResponses, i);
if (openResponse) {
openResponse->connection = NULL;
openResponse->replied = true;
openResponse->timedout = true;
}
}
checkResponses(responseWrangler);
}
index = CFArrayGetFirstIndexOfValue(gConnections, connectionsRange, (void *)reap);
if (kCFNotFound != index)
{
CFArrayRemoveValueAtIndex(gConnections, index);
}
free(reap);
return;
}
static void cleanupResponseWrangler(PMResponseWrangler *reap)
{
PMConnection *one_connection;
long nextAcknowledgementID;
int responseCount;
int connectionsCount;
int i;
int nextInterestBits;
bool nextIsValid;
if (!reap)
return;
if (!gConnections)
return;
nextInterestBits = reap->nextInterestBits;
nextAcknowledgementID = reap->nextKernelAcknowledgementID;
nextIsValid = reap->nextIsValid;
connectionsCount = CFArrayGetCount(gConnections);
for (i=0; i<connectionsCount; i++)
{
one_connection = (PMConnection *)CFArrayGetValueAtIndex(gConnections, i);
if (reap == one_connection->responseHandler)
{
one_connection->responseHandler = NULL;
}
}
if (reap->awaitingResponses)
{
responseCount = CFArrayGetCount(reap->awaitingResponses);
if (responseCount > 0)
{
for (i=0; i<responseCount; i++)
{
free((PMResponse *)CFArrayGetValueAtIndex(reap->awaitingResponses, i));
}
}
CFRelease(reap->awaitingResponses);
reap->awaitingResponses = NULL;
}
if (gLastResponseWrangler == reap) {
gLastResponseWrangler = NULL;
}
free(reap);
if (nextIsValid)
{
PMResponseWrangler * resp;
resp = connectionFireNotification(nextInterestBits, nextAcknowledgementID);
if (!resp && (nextInterestBits == _kSleepStateBits))
{
_pm_scheduledevent_choose_best_wake_event(
kChooseMaintenance, 0);
IOAllowPowerChange(gRootDomainConnect, nextAcknowledgementID);
}
}
}
__private_extern__ bool PMConnectionHandleDeadName(mach_port_t deadPort)
{
PMConnection *one_connection = NULL;;
PMConnection *the_connection = NULL;
int connectionsCount = 0;
int i;
if (!gConnections)
return false;
connectionsCount = CFArrayGetCount(gConnections);
for (i=0; i<connectionsCount; i++)
{
one_connection = (PMConnection *)CFArrayGetValueAtIndex(gConnections, i);
if (one_connection && (deadPort == one_connection->notifyPort))
{
the_connection = one_connection;
break;
}
}
if (the_connection) {
cleanupConnection(the_connection);
return true;
} else {
return false;
}
}
static int getRunState(void)
{
io_registry_entry_t rootdomainservice = IO_OBJECT_NULL;
CFNumberRef runState = NULL;
CFTypeRef runState0 = NULL;
int rstate = 0;
rootdomainservice = getRootDomain();
runState0 = IORegistryEntryCreateCFProperty(
rootdomainservice,
CFSTR(kIOPMRootDomainRunStateKey),
kCFAllocatorDefault,
kNilOptions);
runState = (CFNumberRef)isA_CFNumber(runState0);
if (runState)
{
CFNumberGetValue(runState, kCFNumberSInt32Type, &rstate);
CFRelease(runState);
} else if (runState0) {
CFRelease(runState0);
}
return rstate;
}
static void setSystemSleepStateTracking(IOPMSystemPowerStateCapabilities capables)
{
SCDynamicStoreRef store = _getSharedPMDynamicStore();
CFStringRef key = NULL;
CFNumberRef capablesNum = NULL;
if (!store)
return;
key = SCDynamicStoreKeyCreate(0, CFSTR("%@%@"),
kSCDynamicStoreDomainState,
CFSTR(kIOPMSystemPowerCapabilitiesKeySuffix));
if (!key)
return;
capablesNum = CFNumberCreate(0, kCFNumberIntType, &capables);
if (capablesNum) {
SCDynamicStoreSetValue(store, key, capablesNum);
CFRelease(capablesNum);
}
CFRelease(key);
}
__private_extern__ void PMConnectionPowerCallBack(
void *port,
io_service_t rootdomainservice,
natural_t messageType,
void *acknowledgementToken)
{
PMResponseWrangler *responseController = NULL;
IOPMSystemPowerStateCapabilities deliverCapabilityBits = 0;
int rstate = getRunState();
if (kIOMessageSystemWillSleep == messageType
|| kIOMessageSystemHasPoweredOn == messageType)
{
_pm_scheduledevent_choose_best_wake_event(kChooseReset, 0);
}
AutoWakeSleepWakeNotification(messageType, rstate);
RepeatingAutoWakeSleepWakeNotification(messageType, rstate);
ClockSleepWakeNotification(messageType);
switch (messageType)
{
case kIOMessageSystemWillSleep:
setSystemSleepStateTracking(0);
notify_post(kIOPMSystemPowerStateNotify);
responseController = connectionFireNotification(_kSleepStateBits,
(long)acknowledgementToken);
if (!responseController) {
_pm_scheduledevent_choose_best_wake_event(
kChooseMaintenance, 0);
IOAllowPowerChange(gRootDomainConnect, (long)acknowledgementToken);
}
break;
case kIOMessageCanSystemSleep:
IOAllowPowerChange(gRootDomainConnect, (long)acknowledgementToken);
break;
case kIOMessageSystemWillPowerOn:
switch (rstate)
{
case kRStateNormal:
deliverCapabilityBits =
kIOPMSystemPowerStateCapabilityCPU
| kIOPMSystemPowerStateCapabilityDisk
| kIOPMSystemPowerStateCapabilityNetwork
| kIOPMSystemPowerStateCapabilityAudio
| kIOPMSystemPowerStateCapabilityVideo;
break;
case kRStateDark:
case kRStateMaintenance:
deliverCapabilityBits =
kIOPMSystemPowerStateCapabilityCPU
| kIOPMSystemPowerStateCapabilityDisk
| kIOPMSystemPowerStateCapabilityNetwork;
break;
default:
deliverCapabilityBits = 0;
break;
}
setSystemSleepStateTracking(deliverCapabilityBits);
notify_post(kIOPMSystemPowerStateNotify);
responseController = connectionFireNotification(deliverCapabilityBits, 0);
break;
case kIOMessageSystemHasPoweredOn:
switch (rstate)
{
case kRStateNormal:
logASLMessageSleep(kMsgTracerSigSuccess, NULL, CFAbsoluteTimeGetCurrent(), NULL);
logASLMessageWake(kMsgTracerSigSuccess, NULL, CFAbsoluteTimeGetCurrent(), NULL);
logASLMessageHibernateStatistics();
logASLMessageKernelApplicationResponses();
break;
case kRStateDark:
case kRStateMaintenance:
logASLMessageMaintenanceWake();
break;
}
break;
}
}
static PMResponseWrangler *connectionFireNotification(
int interestBitsNotify,
long kernelAcknowledgementID)
{
static int lastInterestBits = 0xFFFFFFFF;
int affectedBits = 0;
CFArrayRef interested = NULL;
PMConnection *connection = NULL;
int interestedCount = 0;
uint32_t messageToken = 0;
uint16_t calloutCount = 0;
PMResponseWrangler *responseWrangler = NULL;
PMResponse *awaitThis = NULL;
if (gLastResponseWrangler && !gLastResponseWrangler->nextIsValid)
{
gLastResponseWrangler->nextIsValid = true;
gLastResponseWrangler->nextInterestBits = interestBitsNotify;
gLastResponseWrangler->nextKernelAcknowledgementID = kernelAcknowledgementID;
return gLastResponseWrangler;
}
affectedBits = interestBitsNotify ^ lastInterestBits;
lastInterestBits = interestBitsNotify;
interested = createArrayOfConnectionsWithInterest(affectedBits);
if (!interested) {
goto exit;
}
interestedCount = CFArrayGetCount(interested);
if (0 == interestedCount) {
goto exit;
}
responseWrangler = calloc(1, sizeof(PMResponseWrangler));
if (!responseWrangler) {
goto exit;
}
responseWrangler->notificationType = interestBitsNotify;
responseWrangler->awaitResponsesTimeoutSeconds =
(int)kPMConnectionNotifyTimeoutDefault;
responseWrangler->kernelAcknowledgementID = kernelAcknowledgementID;
responseWrangler->awaitingResponses =
CFArrayCreateMutable(kCFAllocatorDefault, interestedCount, &_CFArrayVanillaCallBacks);
responseWrangler->awaitingResponsesCount = interestedCount;
for (calloutCount=0; calloutCount<interestedCount; calloutCount++)
{
connection = (PMConnection *)CFArrayGetValueAtIndex(interested, calloutCount);
if (MACH_PORT_NULL == connection->notifyPort) {
continue;
}
messageToken = (interestBitsNotify << 16)
| calloutCount;
connection->responseHandler = responseWrangler;
_sendMachMessage(connection->notifyPort,
0,
interestBitsNotify,
messageToken);
awaitThis = calloc(1, sizeof(PMResponse));
if (!awaitThis) {
goto exit;
}
awaitThis->token = messageToken;
awaitThis->connection = connection;
awaitThis->notificationType = interestBitsNotify;
awaitThis->myResponseWrangler = responseWrangler;
awaitThis->notifiedWhen = CFAbsoluteTimeGetCurrent();
CFArrayAppendValue(responseWrangler->awaitingResponses, awaitThis);
}
CFRunLoopTimerContext responseTimerContext =
{ 0, (void *)responseWrangler, NULL, NULL, NULL };
responseWrangler->awaitingResponsesTimeout =
CFRunLoopTimerCreate(0,
CFAbsoluteTimeGetCurrent() + responseWrangler->awaitResponsesTimeoutSeconds,
0.0, 0, 0, responsesTimedOut, &responseTimerContext);
if (responseWrangler->awaitingResponsesTimeout)
{
CFRunLoopAddTimer(CFRunLoopGetCurrent(),
responseWrangler->awaitingResponsesTimeout,
kCFRunLoopDefaultMode);
CFRelease(responseWrangler->awaitingResponsesTimeout);
}
exit:
if (interested)
CFRelease(interested);
if (responseWrangler)
gLastResponseWrangler = responseWrangler;
return responseWrangler;
}
static void responsesTimedOut(CFRunLoopTimerRef timer, void * info)
{
PMResponseWrangler *responseWrangler = (PMResponseWrangler *)info;
PMResponse *one_response = NULL;
int responsesCount = 0;
int i;
int tardyCount = 0;
if (!responseWrangler)
return;
responseWrangler->awaitingResponsesTimeout = NULL;
responsesCount = CFArrayGetCount(responseWrangler->awaitingResponses);
for (i=0; i<responsesCount; i++)
{
one_response = (PMResponse *)CFArrayGetValueAtIndex(
responseWrangler->awaitingResponses, i);
if (!one_response)
continue;
if (one_response->replied)
continue;
tardyCount++;
one_response->replied = true;
one_response->timedout = true;
one_response->repliedWhen = CFAbsoluteTimeGetCurrent();
int timeIntervalMS = (int)((one_response->repliedWhen - one_response->notifiedWhen) * 1000);
CFNumberRef timeIntervalNumber = CFNumberCreate(NULL, kCFNumberIntType, &timeIntervalMS);
logASLMessageApplicationResponse(
kAppResponseLogSourcePMConnection,
one_response->connection->callerName,
CFSTR(kIOPMStatsResponseTimedOut),
timeIntervalNumber);
if (timeIntervalNumber)
CFRelease(timeIntervalNumber);
}
checkResponses(responseWrangler);
}
#define kMsgPayloadCount 2
typedef struct {
mach_msg_header_t header;
mach_msg_body_t body;
uint32_t payload[kMsgPayloadCount];
} IOPMMessageStructure;
static void _sendMachMessage(
mach_port_t port,
mach_msg_id_t msg_id,
uint32_t payload_bits,
uint32_t payload_messagetoken)
{
kern_return_t status;
IOPMMessageStructure msg;
bzero(&msg, sizeof(msg));
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
msg.header.msgh_size = sizeof(msg);
msg.header.msgh_remote_port = port;
msg.header.msgh_local_port = MACH_PORT_NULL;
msg.header.msgh_id = msg_id;
msg.body.msgh_descriptor_count = 0;
msg.payload[0] = payload_bits;
msg.payload[1] = payload_messagetoken;
status = mach_msg(&msg.header,
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
msg.header.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
if (status == MACH_SEND_TIMED_OUT) {
mach_msg_destroy(&msg.header);
}
if (status != MACH_MSG_SUCCESS)
{
}
return;
}
static void checkResponses(PMResponseWrangler *wrangler)
{
int i = 0;
int responsesCount = 0;
int notRepliedCount = 0;
bool complete = true;
PMResponse *oneResponse = NULL;
PMResponse *maintrequester = NULL;
CFAbsoluteTime earliestRequest = 0.0;
responsesCount = CFArrayGetCount(wrangler->awaitingResponses);
for (i=0; i<responsesCount; i++)
{
oneResponse = (PMResponse *)CFArrayGetValueAtIndex(
wrangler->awaitingResponses, i);
if (!oneResponse->replied) {
complete = false;
notRepliedCount++;
}
if ( ((oneResponse->maintenanceRequested < earliestRequest)
|| (0.0 == earliestRequest))
&& oneResponse->maintenanceRequested != 0.0)
{
earliestRequest = oneResponse->maintenanceRequested;
maintrequester = oneResponse;
}
}
if (!complete) {
return;
}
if (wrangler->awaitingResponsesTimeout) {
CFRunLoopTimerInvalidate(wrangler->awaitingResponsesTimeout);
wrangler->awaitingResponsesTimeout = NULL;
}
if (wrangler->needsMaintenanceWake) {
_pm_scheduledevent_choose_best_wake_event(kChooseMaintenance, earliestRequest);
} else {
_pm_scheduledevent_choose_best_wake_event(kChooseMaintenance, 0);
}
if (_kSleepStateBits == wrangler->notificationType)
{
IOAllowPowerChange(gRootDomainConnect, wrangler->kernelAcknowledgementID);
}
cleanupResponseWrangler(wrangler);
return;
}
static CFArrayRef createArrayOfConnectionsWithInterest(
int interestBits)
{
CFMutableArrayRef arrayFoundInterests = NULL;
PMConnection *lookee;
int gConnectionsCount;
int i;
if (0 == interestBits)
return NULL;
arrayFoundInterests = CFArrayCreateMutable(kCFAllocatorDefault, 0, &_CFArrayConnectionCallBacks);
gConnectionsCount = CFArrayGetCount(gConnections);
for (i=0; i<gConnectionsCount; i++)
{
lookee = (PMConnection *)CFArrayGetValueAtIndex(gConnections, i);
if (interestBits & lookee->interestsBits) {
CFArrayAppendValue(arrayFoundInterests, lookee);
}
}
return arrayFoundInterests;
}
static IOReturn createConnectionWithID(PMConnection **out)
{
static bool hasLoggedTooManyConnections = false;
if ((globalConnectionIDTally > kMaxConnectionIDCount)
&& !hasLoggedTooManyConnections)
{
return kIOReturnNoSpace;
}
*out = (PMConnection *)calloc(1, sizeof(PMConnection));
if (!*out)
return kIOReturnNoMemory;
((PMConnection *)*out)->uniqueID = kConnectionOffset + globalConnectionIDTally++;
CFArrayAppendValue(gConnections, *out);
return kIOReturnSuccess;
}
static PMConnection *connectionForID(uint32_t findMe)
{
CFIndex where = 0;
CFRange theRange = CFRangeMake(0, CFArrayGetCount(gConnections));
PMConnection dummy;
dummy.uniqueID = findMe;
where = CFArrayGetFirstIndexOfValue(gConnections, theRange, &dummy);
if (kCFNotFound == where) {
return NULL;
} else {
return (PMConnection *)CFArrayGetValueAtIndex(gConnections, where);
}
}