EXTERN ipc_port_t iokit_alloc_object_port( io_object_t obj, ipc_kobject_type_t type ) { ipc_port_t notify; ipc_port_t port; do { /* Allocate port, keeping a reference for it. */ port = ipc_port_alloc_kernel(); if( port == IP_NULL) continue; /* set kobject & type */ // iokit_add_reference( obj ); ipc_kobject_set( port, (ipc_kobject_t) obj, type); /* Request no-senders notifications on the port. */ ip_lock( port); notify = ipc_port_make_sonce_locked( port); ipc_port_nsrequest( port, 1, notify, ¬ify); /* port unlocked */ assert( notify == IP_NULL); gIOKitPortCount++; } while( FALSE); return( port ); }
/* * fileport_alloc * * Description: Obtain a send right for the given fileglob, which must be * referenced. * * Parameters: fg A fileglob. * * Returns: Port of type IKOT_FILEPORT with fileglob set as its kobject. * Port is returned with a send right. */ ipc_port_t fileport_alloc(struct fileglob *fg) { ipc_port_t fileport; ipc_port_t sendport; ipc_port_t notifyport; fileport = ipc_port_alloc_kernel(); if (fileport == IP_NULL) { goto out; } ipc_kobject_set(fileport, (ipc_kobject_t)fg, IKOT_FILEPORT); ip_lock(fileport); /* unlocked by ipc_port_nsrequest */ notifyport = ipc_port_make_sonce_locked(fileport); ipc_port_nsrequest(fileport, 1, notifyport, ¬ifyport); sendport = ipc_port_make_send(fileport); if (!IP_VALID(sendport)) { panic("Couldn't allocate send right for fileport!\n"); } out: return fileport; }
static void iokit_no_senders( mach_no_senders_notification_t * notification ) { ipc_port_t port; io_object_t obj = NULL; ipc_kobject_type_t type = IKOT_NONE; ipc_port_t notify; port = (ipc_port_t) notification->not_header.msgh_remote_port; // convert a port to io_object_t. if( IP_VALID(port)) { iokit_lock_port(port); if( ip_active(port)) { obj = (io_object_t) port->ip_kobject; type = ip_kotype( port ); if( (IKOT_IOKIT_OBJECT == type) || (IKOT_IOKIT_CONNECT == type)) iokit_add_reference( obj ); else obj = NULL; } iokit_unlock_port(port); if( obj ) { mach_port_mscount_t mscount = notification->not_count; if( KERN_SUCCESS != iokit_client_died( obj, port, type, &mscount )) { /* Re-request no-senders notifications on the port (if still active) */ ip_lock(port); if (ip_active(port)) { notify = ipc_port_make_sonce_locked(port); ipc_port_nsrequest( port, mscount + 1, notify, ¬ify); /* port unlocked */ if ( notify != IP_NULL) ipc_port_release_sonce(notify); } else { ip_unlock(port); } } iokit_remove_reference( obj ); } } }
/* * Routine: convert_semaphore_to_port * Purpose: * Convert a semaphore reference to a send right to a * semaphore port. * * Consumes the semaphore reference. If the semaphore * port currently has no send rights (or doesn't exist * yet), the reference is donated to the port to represent * all extant send rights collectively. */ ipc_port_t convert_semaphore_to_port (semaphore_t semaphore) { ipc_port_t port, send; if (semaphore == SEMAPHORE_NULL) return (IP_NULL); /* caller is donating a reference */ port = semaphore->port; if (!IP_VALID(port)) { port = ipc_port_alloc_kernel(); assert(IP_VALID(port)); ipc_kobject_set_atomically(port, (ipc_kobject_t) semaphore, IKOT_SEMAPHORE); /* If we lose the race, deallocate and pick up the other guy's port */ if (!OSCompareAndSwapPtr(IP_NULL, port, &semaphore->port)) { ipc_port_dealloc_kernel(port); port = semaphore->port; assert(ip_kotype(port) == IKOT_SEMAPHORE); assert(port->ip_kobject == (ipc_kobject_t)semaphore); } } ip_lock(port); assert(ip_active(port)); send = ipc_port_make_send_locked(port); if (1 == port->ip_srights) { ipc_port_t old_notify; /* transfer our ref to the port, and arm the no-senders notification */ assert(IP_NULL == port->ip_nsrequest); ipc_port_nsrequest(port, port->ip_mscount, ipc_port_make_sonce_locked(port), &old_notify); /* port unlocked */ assert(IP_NULL == old_notify); } else { /* piggyback on the existing port reference, so consume ours */ ip_unlock(port); semaphore_dereference(semaphore); } return (send); }