void CFMessagePortInvalidate(CFMessagePortRef ms) { __CFGenericValidateType(ms, __kCFMessagePortTypeID); if (!__CFMessagePortIsDeallocing(ms)) { CFRetain(ms); } __CFMessagePortLock(ms); if (__CFMessagePortIsValid(ms)) { CFMessagePortInvalidationCallBack callout = ms->_icallout; CFRunLoopSourceRef source = ms->_source; CFMachPortRef replyPort = ms->_replyPort; CFMachPortRef port = ms->_port; CFStringRef name = ms->_name; void *info = NULL; __CFMessagePortUnsetValid(ms); if (!__CFMessagePortIsRemote(ms)) { info = ms->_context.info; ms->_context.info = NULL; } ms->_source = NULL; ms->_replyPort = NULL; __CFMessagePortUnlock(ms); __CFSpinLock(&__CFAllMessagePortsLock); if (NULL != (__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts)) { CFDictionaryRemoveValue(__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts, name); } __CFSpinUnlock(&__CFAllMessagePortsLock); if (NULL != callout) { callout(ms, info); } // We already know we're going invalid, don't need this callback // anymore; plus, this solves a reentrancy deadlock; also, this // must be done before the deallocate of the Mach port, to // avoid a race between the notification message which could be // handled in another thread, and this NULL'ing out. CFMachPortSetInvalidationCallBack(port, NULL); // For hashing and equality purposes, cannot get rid of _port here if (!__CFMessagePortIsRemote(ms) && NULL != ms->_context.release) { ms->_context.release(info); } if (NULL != source) { CFRunLoopSourceInvalidate(source); CFRelease(source); } if (NULL != replyPort) { CFMachPortInvalidate(replyPort); CFRelease(replyPort); } if (__CFMessagePortIsRemote(ms)) { // Get rid of our extra ref on the Mach port gotten from bs server mach_port_deallocate(mach_task_self(), CFMachPortGetPort(port)); } } else { __CFMessagePortUnlock(ms); } if (!__CFMessagePortIsDeallocing(ms)) { CFRelease(ms); } }
void MonitorStartupItem (StartupContext aStartupContext, CFMutableDictionaryRef anItem) { pid_t aPID = StartupItemGetPID(anItem); if (anItem && aPID > 0) { mach_port_t aPort; kern_return_t aResult; CFMachPortContext aContext; CFMachPortRef aMachPort; CFRunLoopSourceRef aSource; TerminationContext aTerminationContext = (TerminationContext) malloc(sizeof(struct TerminationContextStorage)); aTerminationContext->aStartupContext = aStartupContext; aTerminationContext->anItem = anItem; aContext.version = 0; aContext.info = aTerminationContext; aContext.retain = 0; aContext.release = 0; if ((aResult = task_for_pid(mach_task_self(), aPID, &aPort)) != KERN_SUCCESS) goto out_bad; if (!(aMachPort = CFMachPortCreateWithPort(NULL, aPort, NULL, &aContext, NULL))) goto out_bad; if (!(aSource = CFMachPortCreateRunLoopSource(NULL, aMachPort, 0))) { CFRelease(aMachPort); goto out_bad; } CFMachPortSetInvalidationCallBack(aMachPort, startupItemTerminated); CFRunLoopAddSource(CFRunLoopGetCurrent(), aSource, kCFRunLoopCommonModes); CFRelease(aSource); CFRelease(aMachPort); return; out_bad: /* The assumption is something failed, the task already terminated. */ startupItemTerminated(NULL, aTerminationContext); } }
// This constructor is the general form: // - If inMachPort is MACH_PORT_NULL, the CFMachPort will allocate the port and own the send and // receive rights. Otherwise, the caller owns the rights and is resposible for cleaning them // up. // - If inCallBack is NULL, then received messages will just get swallowed by the CFMachPort. // This is useful if you are only using the CFMachPort to track port death (aka invalidation). // - If inInvalidationCallBack is non-NULL, then it will be installed as the invalidation // callback on the CFMachPort. CACFMachPort::CACFMachPort(mach_port_t inMachPort, CFMachPortCallBack inCallBack, CFMachPortInvalidationCallBack inInvalidationCallBack, void* inUserData) : mMachPort(NULL), mRunLoopSource(NULL), mOwnsPort(false) { CFMachPortContext theContext = { 1, inUserData, NULL, NULL, NULL }; if(inMachPort == MACH_PORT_NULL) { mMachPort = CFMachPortCreate(NULL, inCallBack, &theContext, NULL); ThrowIfNULL(mMachPort, CAException('what'), "CACFMachPort::CACFMachPort: couldn't create the CFMachPort"); mOwnsPort = true; } else { mMachPort = CFMachPortCreateWithPort(NULL, inMachPort, inCallBack, &theContext, NULL); ThrowIfNULL(mMachPort, CAException('what'), "CACFMachPort::CACFMachPort: couldn't create the CFMachPort with a port"); mOwnsPort = false; } mRunLoopSource = CFMachPortCreateRunLoopSource(NULL, mMachPort, 0); if(mRunLoopSource == NULL) { if(mOwnsPort) { CFMachPortInvalidate(mMachPort); } CFRelease(mMachPort); mMachPort = NULL; DebugMessage("CACFMachPort::CACFMachPort: couldn't create the CFRunLoopSource"); throw CAException('what'); } if(inInvalidationCallBack != NULL) { CFMachPortSetInvalidationCallBack(mMachPort, inInvalidationCallBack); } }
CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) { CFMessagePortRef memory; CFMachPortRef native; CFMachPortContext ctx; uint8_t *utfname = NULL; CFIndex size; mach_port_t bp, port; kern_return_t ret; name = __CFMessagePortSanitizeStringName(allocator, name, &utfname, NULL); if (NULL == name) { return NULL; } __CFSpinLock(&__CFAllMessagePortsLock); if (NULL != name) { CFMessagePortRef existing; if (NULL != __CFAllRemoteMessagePorts && CFDictionaryGetValueIfPresent(__CFAllRemoteMessagePorts, name, (const void **)&existing)) { __CFSpinUnlock(&__CFAllMessagePortsLock); CFRelease(name); CFAllocatorDeallocate(allocator, utfname); return (CFMessagePortRef)CFRetain(existing); } } size = sizeof(struct __CFMessagePort) - sizeof(CFMessagePortContext) - sizeof(CFRuntimeBase); memory = (CFMessagePortRef)_CFRuntimeCreateInstance(allocator, __kCFMessagePortTypeID, size, NULL); if (NULL == memory) { __CFSpinUnlock(&__CFAllMessagePortsLock); if (NULL != name) { CFRelease(name); } CFAllocatorDeallocate(allocator, utfname); return NULL; } __CFMessagePortUnsetValid(memory); __CFMessagePortSetRemote(memory); memory->_lock = 0; memory->_name = name; memory->_port = NULL; memory->_replies = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); memory->_convCounter = 0; memory->_replyPort = NULL; memory->_source = NULL; memory->_icallout = NULL; memory->_callout = NULL; ctx.version = 0; ctx.info = memory; ctx.retain = NULL; ctx.release = NULL; ctx.copyDescription = NULL; task_get_bootstrap_port(mach_task_self(), &bp); ret = bootstrap_look_up(bp, utfname, &port); native = (KERN_SUCCESS == ret) ? CFMachPortCreateWithPort(allocator, port, __CFMessagePortDummyCallback, &ctx, NULL) : NULL; CFAllocatorDeallocate(allocator, utfname); if (NULL == native) { __CFSpinUnlock(&__CFAllMessagePortsLock); // name is released by deallocation CFRelease(memory); return NULL; } memory->_port = native; CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); __CFMessagePortSetValid(memory); if (NULL != name) { if (NULL == __CFAllRemoteMessagePorts) { __CFAllRemoteMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); } CFDictionaryAddValue(__CFAllRemoteMessagePorts, name, memory); } __CFSpinUnlock(&__CFAllMessagePortsLock); return (CFMessagePortRef)memory; }
CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) { CFMessagePortRef memory; CFMachPortRef native; CFMachPortContext ctx; uint8_t *utfname = NULL; CFIndex size; if (shouldFreeInfo) *shouldFreeInfo = true; if (NULL != name) { name = __CFMessagePortSanitizeStringName(allocator, name, &utfname, NULL); } __CFSpinLock(&__CFAllMessagePortsLock); if (NULL != name) { CFMessagePortRef existing; if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) { __CFSpinUnlock(&__CFAllMessagePortsLock); CFRelease(name); CFAllocatorDeallocate(allocator, utfname); return (CFMessagePortRef)CFRetain(existing); } } size = sizeof(struct __CFMessagePort) - sizeof(CFRuntimeBase); memory = (CFMessagePortRef)_CFRuntimeCreateInstance(allocator, __kCFMessagePortTypeID, size, NULL); if (NULL == memory) { __CFSpinUnlock(&__CFAllMessagePortsLock); if (NULL != name) { CFRelease(name); } CFAllocatorDeallocate(allocator, utfname); return NULL; } __CFMessagePortUnsetValid(memory); __CFMessagePortUnsetRemote(memory); memory->_lock = 0; memory->_name = name; memory->_port = NULL; memory->_replies = NULL; memory->_convCounter = 0; memory->_replyPort = NULL; memory->_source = NULL; memory->_icallout = NULL; memory->_callout = callout; memory->_context.info = NULL; memory->_context.retain = NULL; memory->_context.release = NULL; memory->_context.copyDescription = NULL; ctx.version = 0; ctx.info = memory; ctx.retain = NULL; ctx.release = NULL; ctx.copyDescription = NULL; native = CFMachPortCreate(allocator, __CFMessagePortDummyCallback, &ctx, NULL); if (NULL != native && NULL != name && !__CFMessagePortNativeSetNameLocal(native, utfname)) { CFMachPortInvalidate(native); CFRelease(native); native = NULL; } CFAllocatorDeallocate(allocator, utfname); if (NULL == native) { __CFSpinUnlock(&__CFAllMessagePortsLock); // name is released by deallocation CFRelease(memory); return NULL; } memory->_port = native; CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); __CFMessagePortSetValid(memory); if (NULL != context) { memmove(&memory->_context, context, sizeof(CFMessagePortContext)); memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info; } if (NULL != name) { if (NULL == __CFAllLocalMessagePorts) { __CFAllLocalMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); } CFDictionaryAddValue(__CFAllLocalMessagePorts, name, memory); } __CFSpinUnlock(&__CFAllMessagePortsLock); if (shouldFreeInfo) *shouldFreeInfo = false; return memory; }
int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid) { if(pid < 1) return -1; kern_return_t kernResult; mach_port_t taskOfOurProcess; mach_port_t machPortForProcess; taskOfOurProcess = mach_task_self(); if(taskOfOurProcess == MACH_PORT_NULL) { wxLogDebug(wxT("No mach_task_self()")); return -1; } wxLogDebug(wxT("pid=%d"),pid); kernResult = task_for_pid(taskOfOurProcess,pid, &machPortForProcess); if(kernResult != KERN_SUCCESS) { wxLogDebug(wxT("no task_for_pid()")); // try seeing if it is already dead or something // FIXME: a better method would be to call the callback function // from idle time until the process terminates. Of course, how // likely is it that it will take more than 0.1 seconds for the // mach terminate event to make its way to the BSD subsystem? usleep(100); // sleep for 0.1 seconds wxMAC_MachPortEndProcessDetect(NULL, (void*)proc_data); return -1; } CFMachPortContext termcb_contextinfo; termcb_contextinfo.version = 0; termcb_contextinfo.info = (void*)proc_data; termcb_contextinfo.retain = NULL; termcb_contextinfo.release = NULL; termcb_contextinfo.copyDescription = NULL; CFMachPortRef CFMachPortForProcess; Boolean ShouldFreePort; CFMachPortForProcess = CFMachPortCreateWithPort(NULL, machPortForProcess, NULL, &termcb_contextinfo, &ShouldFreePort); if(!CFMachPortForProcess) { wxLogDebug(wxT("No CFMachPortForProcess")); mach_port_deallocate(taskOfOurProcess, machPortForProcess); return -1; } if(ShouldFreePort) { kernResult = mach_port_deallocate(taskOfOurProcess, machPortForProcess); if(kernResult!=KERN_SUCCESS) { wxLogDebug(wxT("Couldn't deallocate mach port")); return -1; } } CFMachPortSetInvalidationCallBack(CFMachPortForProcess, &wxMAC_MachPortEndProcessDetect); CFRunLoopSourceRef runloopsource; runloopsource = CFMachPortCreateRunLoopSource(NULL,CFMachPortForProcess, (CFIndex)0); if(!runloopsource) { wxLogDebug(wxT("Couldn't create runloopsource")); return -1; } CFRelease(CFMachPortForProcess); CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource,kCFRunLoopDefaultMode); CFRelease(runloopsource); wxLogDebug(wxT("Successfully added notification to the runloop")); return 0; }
// // Handle dead-port notifications. // Since we don't actually run our own runloop here, we can't well use standard // notifications to our own server port. So we use a CFMachPort facility instead. // void MachRunLoopServer::notifyIfDead(Port port, bool doNotify) const { if (CFMachPortRef cfPort = CFMachPortCreateWithPort(NULL, port, NULL, NULL, NULL)) CFMachPortSetInvalidationCallBack(cfPort, cfInvalidate); }