IOPSNotificationCreateRunLoopSource query

Hello,


I have the below program in Objective-C++ for IOPSNotificationCreateRunLoopSource.

But, I am not able to receive power source change events without the infinite do { } while(!done) loop in startThread() function.

Please suggest a way to get rind of the infinite loop to receive power source change events.


#import "PowerSourceInfoWorker.h"
@implementation PowerSourceInfoWorker

-(void) dealloc {
[self stopThread];
[super dealloc];
}


-(void) startThread {
BOOL done = NO;
do {
runLoopSource = (CFRunLoopSourceRef)IOPSNotificationCreateRunLoopSource(powerSourceChange, self);
if(runLoopSource) {
NSLog(@"Waiting for power source change........ ");
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
}
int result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, YES);
done = (result == kCFRunLoopRunStopped) || (result == kCFRunLoopRunFinished);
} while (!done);
}

-(void) stopThread {
if(runLoopSource) {
CFRunLoopSourceInvalidate(runLoopSource);
CFRelease(runLoopSource);
}
}

void powerSourceChange(void* context) {
NSLog(@"Power Source has changed");
}

int main(int argc, const char * argv[]) {
NSLog(@"Power Source Change detection");

PowerSourceInfoWorker *psiWorker = [[PowerSourceInfoWorker alloc]init];

NSLog(@"before startThread");
[psiWorker startThread];
}
@end

Replies

I’m not entirely sure why your code doesn’t work but pasted in below you’ll find some code that does. When I run it on my machine (10.15.4) I see the following:

2020-05-20 09:45:26…[68499:3100242] will start
2020-05-20 09:45:26…[68499:3100242] did start
2020-05-20 09:45:26…[68499:3100242] will wait for 10.0
2020-05-20 09:45:33…[68499:3100242] did receive power callback
2020-05-20 09:45:33…[68499:3100242] will wait for 3.8
2020-05-20 09:45:36…[68499:3100242] did receive power callback
2020-05-20 09:45:36…[68499:3100242] will wait for 0.8
2020-05-20 09:45:36…[68499:3100242] will stop
2020-05-20 09:45:36…[68499:3100242] did stop

I’m on a laptop, and I triggered the power callbacks by plugging and unplugging the power supply.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
@import Foundation;
@import IOKit.ps;

@interface Main: NSObject

@end

@interface Main ()

@property (nonatomic, strong, readwrite, nullable) CFRunLoopSourceRef source __attribute__ (( NSObject ));

@end

@implementation Main

- (void)start {
    NSLog(@"will start");
    assert(self.source == nil);
    CFRunLoopSourceRef source = IOPSNotificationCreateRunLoopSource(
        myPowerSourceCallbackType,
        (__bridge void *) self
    );
    self.source = source;
    CFRelease(source);
    CFRunLoopRef current = CFRunLoopGetCurrent();
    CFRunLoopAddSource(current, self.source, kCFRunLoopDefaultMode);
    NSLog(@"did start");
}

- (void)didReceivePowerCallback {
    NSLog(@"did receive power callback");
}

static void myPowerSourceCallbackType(void * context) {
    Main * obj = (__bridge Main *) context;
    [obj didReceivePowerCallback];
}

- (void)stop {
    NSLog(@"will stop");
    if (self.source == nil) {
        NSLog(@"ignoring redundant stop");
        return;
    }
    CFRunLoopSourceInvalidate(self.source);
    self.source = nil;
    NSLog(@"did stop");
}

- (void)runUntil:(NSDate *)deadline {
    do {
        NSTimeInterval delay = [deadline timeIntervalSinceNow];
        if (delay <= 0.0) {
            break;
        }
        NSLog(@"will wait for %.1f", delay);
        CFRunLoopRunInMode(kCFRunLoopDefaultMode, delay, true);
    } while (YES);
}

@end

int main(int argc, char **argv) {
    #pragma unused(argc)
    #pragma unused(argv)
    Main * main = [[Main alloc] init];
    [main start];
    [main runUntil:[NSDate dateWithTimeIntervalSinceNow:10.0]];
    [main stop];
    return EXIT_SUCCESS;
}