I have the following code where I attempt to create a message port for communication between two run loops. 1 run loop is executing instead of a pthread and the other is the main run loop. This function appears to function normally under a number of different conditions, however, none of them are the desired condition.
For example, passing NULL instead of kCFRunLoopDefaultMode works, but does not block.
Passing kCFRunLoopDefaultMode and NULL data for BOTH the sndData and return value from the MessagePortProc callback (retrun NULL) also work as expected with the only problem being that I need to send and return data from the MessagePortProc callback, hence the use of the Message Port.
If kCFRunLoopDefaultMode is used AND either the MessagePortProc return value OR the sndData parameter are NOT NULL CFMessagePortSendRequest blocks and never returns. MessagePortProc is called just fine, it just never returns control to where it was called. No error message is printed, no crash occurs, it just simply sits there.
I am using the simple CFDataRef created from the small byte array outlined below for both the send and received data as a test case. Either one will cause the behavior outlined.
UInt8 bytes[] = { 0, 1 };
CFDataRef sndData = CFDataCreate(kCFAllocatorDefault, bytes, 2);
SInt32 response = CFMessagePortSendRequest(remoteMsgPort, 0, sndData, 1, 1, kCFRunLoopDefaultMode, &rtnData);
CFDataRef MessagePortProc(CFMessagePortRef msgport, SInt32 msgid, CFDataRef data, void *info) {
CFDataRef retData = NULL;
... Processing Done Here ...
return retData;
}
void StartMessagePortRunLoop() {
CFMessagePortContext context = {
.version = 0,
.info = NULL,
.retain = NULL,
.release = NULL,
.copyDescription = NULL
};
localMsgPort = CFMessagePortCreateLocal(kCFAllocatorDefault, CFSTR("TextServiceMessagePort"), MessagePortProc, &context, NULL);
if (localMsgPort != NULL) {
sourceMsgPort = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, localMsgPort, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), sourceMsgPort, kCFRunLoopDefaultMode);
}
}
void StopMessagePortRunLoop() {
if (CFRunLoopContainsSource(CFRunLoopGetMain(), sourceMsgPort, kCFRunLoopDefaultMode)) {
CFRunLoopRemoveSource(CFRunLoopGetMain(), sourceMsgPort, kCFRunLoopDefaultMode);
CFRelease(sourceMsgPort);
}
CFMessagePortInvalidate(localMsgPort);
CFRelease(localMsgPort);
}