1/* 2 * Copyright (c) 2014 3 Apple Computer, Inc. All rights reserved. 4 * 5 * @APPLE_LICENSE_HEADER_START@ 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. Please obtain a copy of the License at 11 * http://www.opensource.apple.com/apsl/ and read it before using this 12 * file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 * Please see the License for the specific language governing rights and 20 * limitations under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25#include <CoreFoundation/CoreFoundation.h> 26#include <IOKit/IOKitLib.h> 27#include <IOKit/pwr_mgt/IOPMLibPrivate.h> 28#include <IOKit/pwr_mgt/IOPMLib.h> 29 30#include <dispatch/dispatch.h> 31#include <stdio.h> 32 33 34/* 35 36cc -o IOPMPerformBlockWithAssertion-15072112 \ 37 IOPMPerformBlockWithAssertion-15072112.c \ 38 -framework IOKit -framework CoreFoundation 39 40Inspired by: 41<rdar://problem/15072112> Sub-TLF: Investigating IOPMAssertion block API 42 43*/ 44 45 46 47enum { 48 kExpectOn, 49 kExpectOff, 50 kExpectNA 51}; 52static CFStringRef kAType = kIOPMAssertNetworkClientActive; 53 54 55static bool globalAssertionLevelFor(CFStringRef type, int expected, const char *print); 56static void asyncPerformBlockWith(CFStringRef type, int assertionTimeoutSec, int blockDurationSec); 57 58static void block10s_execTest(void); 59//static void blockTimeoutExceedsBlockLifespanTest(void); 60 61#define kNoTimeout 0 62 63int main(int argc, char *argv[]) 64{ 65 globalAssertionLevelFor(kAType, kExpectNA, "Baseline"); 66 67 block10s_execTest(); 68 69 return 0; 70} 71 72 73static void block10s_execTest(void) 74{ 75 asyncPerformBlockWith(kAType, kNoTimeout, 10); 76 sleep(1); 77 globalAssertionLevelFor(kAType, kExpectOn, "#1 block is holding assertion"); 78 sleep(3); 79 globalAssertionLevelFor(kAType, kExpectNA, "#1 block should have exited by now"); 80 sleep(10); 81 globalAssertionLevelFor(kAType, kExpectNA, "#1 block should have exited by now EXTRA EXTRA EXIT"); 82} 83 84 85//static void blockTimeoutExceedsBlockLifespanTest(void) 86//{ 87// asyncPerformBlockWith(kAType, 7, 3); 88// sleep(1); 89// globalAssertionLevelFor(kAType, kExpectOn, "#2 block is holding assertion"); 90// sleep(3); 91// globalAssertionLevelFor(kAType, kExpectOff, "#2 block exited; timeout still going"); 92// sleep(5); 93// globalAssertionLevelFor(kAType, kExpectOff, "#2 block exited; timeout exited"); 94//} 95 96static void asyncPerformBlockWith(CFStringRef type, 97 int assertionTimeoutSec, 98 int blockDurationSec) 99{ 100 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 101 ^() { 102 IOReturn ret; 103 CFMutableDictionaryRef properties = NULL; 104 105 properties = CFDictionaryCreateMutable(0, 3, 106 &kCFTypeDictionaryKeyCallBacks, 107 &kCFTypeDictionaryValueCallBacks); 108 109 if (properties) { 110 CFDictionarySetValue(properties, 111 kIOPMAssertionNameKey, 112 CFSTR("IOPMPerformBlockWithAssertion-15072112")); 113 114 CFDictionarySetValue(properties, 115 kIOPMAssertionTypeKey, 116 type); 117 118 if (assertionTimeoutSec) 119 { 120 CFTimeInterval timeint = (CFTimeInterval)assertionTimeoutSec; 121 CFNumberRef timer; 122 timer = CFNumberCreate(0, kCFNumberDoubleType, &timeint); 123 CFDictionarySetValue(properties, 124 kIOPMAssertionTimeoutKey, 125 timer); 126 CFRelease(timer); 127 } 128 129 int levelOn = kIOPMAssertionLevelOn; 130 131 CFNumberRef numOn = CFNumberCreate(0, kCFNumberIntType, &levelOn); 132 133 CFDictionarySetValue(properties, 134 kIOPMAssertionLevelKey, 135 numOn); 136 CFRelease(numOn); 137 } 138 139 IOPMAssertionID aid; 140 IOReturn r2 = IOPMAssertionCreateWithProperties(properties, &aid); 141 printf("r2=0x%08x\n",r2); 142 143 ret = IOPMPerformBlockWithAssertion(properties, 144 ^(){ 145 globalAssertionLevelFor(type, kExpectOn, "Within performed block"); 146 sleep(blockDurationSec); 147 }); 148 149 if (kIOReturnSuccess != ret) { 150 printf ("[FAIL] IOPMPerformBlockWithAssertion returns 0x%08x\n", ret); 151 exit(1); 152 } 153 CFRelease(properties); 154 }); 155} 156 157 158static bool globalAssertionLevelFor(CFStringRef type, int expected, const char *print) 159{ 160 CFDictionaryRef out = NULL; 161 CFNumberRef level = NULL; 162 bool actual = false; 163 int level_int = 0; 164 165 IOPMCopyAssertionsStatus(&out); 166 167 if (!out) { 168 printf("[FAIL] NULL return from IOPMCopyAssertionsStatus"); 169 return false; 170 } 171 172 level = CFDictionaryGetValue(out, type); 173 174 CFNumberGetValue(level, kCFNumberIntType, &level_int); 175 176 actual = (1==level_int); 177 178 if (print) { 179 const char *expectedStr; 180 const char *actualStr; 181 if (kExpectOn == expected) { 182 expectedStr = "On"; 183 } else if (kExpectOff == expected) { 184 expectedStr = "Off"; 185 } else { 186 expectedStr = "N/A"; 187 } 188 actualStr = actual? "On":"Off"; 189 190 if ((kExpectNA == expected) 191 || (actual && (kExpectOn == expected)) 192 || (!actual && (kExpectOff == expected))) 193 { 194 printf("[PASS] \"%s\" level is %s, expected to be %s\n",print, actualStr, expectedStr); 195 } else { 196 printf("[FAIL] \"%s\" level is %s, should be %s\n",print, actualStr, expectedStr); 197 } 198 fflush(stdout); 199 } 200 201 CFRelease(out); 202 203 return (kIOPMAssertionLevelOn > 0); 204} 205 206