void host_notify_port_destroy( ipc_port_t port) { host_notify_t entry; mutex_lock(&host_notify_lock); ip_lock(port); if (ip_kotype(port) == IKOT_HOST_NOTIFY) { entry = (host_notify_t)port->ip_kobject; assert(entry != NULL); ipc_kobject_set_atomically(port, IKO_NULL, IKOT_NONE); ip_unlock(port); assert(entry->port == port); remqueue(NULL, (queue_entry_t)entry); mutex_unlock(&host_notify_lock); zfree(host_notify_zone, (vm_offset_t)entry); ipc_port_release_sonce(port); return; } ip_unlock(port); mutex_unlock(&host_notify_lock); }
void mk_timer_port_destroy( ipc_port_t port) { mk_timer_t timer = NULL; ip_lock(port); if (ip_kotype(port) == IKOT_TIMER) { timer = (mk_timer_t)port->ip_kobject; assert(timer != NULL); ipc_kobject_set_atomically(port, IKO_NULL, IKOT_NONE); simple_lock(&timer->lock); assert(timer->port == port); } ip_unlock(port); if (timer != NULL) { if (thread_call_cancel(&timer->call_entry)) timer->active--; timer->is_armed = FALSE; timer->is_dead = TRUE; if (timer->active == 0) { simple_unlock(&timer->lock); zfree(mk_timer_zone, timer); ipc_port_release_send(port); return; } simple_unlock(&timer->lock); } }
/* * Routine: ipc_kobject_set * Purpose: * Make a port represent a kernel object of the given type. * The caller is responsible for handling refs for the * kernel object, if necessary. * Conditions: * Nothing locked. The port must be active if setting * a kobject linkage. Clearing a linkage is OK on an * inactive port. */ void ipc_kobject_set( ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t type) { ip_lock(port); ipc_kobject_set_atomically(port, kobject, type); ip_unlock(port); }
/* * Routine: convert_mig_object_to_port [interface] * Purpose: * Base implementation of MIG outtrans routine to convert from * a mig object reference to a new send right on the object's * port. The object reference is consumed. * Returns: * IP_NULL - Null MIG object supplied * Otherwise, a newly made send right for the port * Conditions: * Nothing locked. */ ipc_port_t convert_mig_object_to_port( mig_object_t mig_object) { ipc_port_t port; boolean_t deallocate = TRUE; if (mig_object == MIG_OBJECT_NULL) return IP_NULL; port = mig_object->port; while ((port == IP_NULL) || ((port = ipc_port_make_send(port)) == IP_NULL)) { ipc_port_t previous; /* * Either the port was never set up, or it was just * deallocated out from under us by the no-senders * processing. In either case, we must: * Attempt to make one * Arrange for no senders * Try to atomically register it with the object * Destroy it if we are raced. */ port = ipc_port_alloc_kernel(); ip_lock(port); ipc_kobject_set_atomically(port, (ipc_kobject_t) mig_object, IKOT_MIG); /* make a sonce right for the notification */ port->ip_sorights++; ip_reference(port); ipc_port_nsrequest(port, 1, port, &previous); /* port unlocked */ assert(previous == IP_NULL); if (OSCompareAndSwapPtr((void *)IP_NULL, (void *)port, (void * volatile *)&mig_object->port)) { deallocate = FALSE; } else { ipc_port_dealloc_kernel(port); port = mig_object->port; } } if (deallocate) mig_object->pVtbl->Release((IMIGObject *)mig_object); return (port); }
static void host_notify_all( host_flavor_t notify_type, mach_msg_header_t *msg, mach_msg_size_t msg_size) { queue_t notify_queue = &host_notify_queue[notify_type]; mutex_lock(&host_notify_lock); if (!queue_empty(notify_queue)) { queue_head_t send_queue; host_notify_t entry; send_queue = *notify_queue; queue_init(notify_queue); send_queue.next->prev = &send_queue; send_queue.prev->next = &send_queue; msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0); msg->msgh_local_port = MACH_PORT_NULL; msg->msgh_id = host_notify_replyid[notify_type]; msg->msgh_reserved = 0; while ((entry = (host_notify_t)dequeue(&send_queue)) != NULL) { ipc_port_t port; port = entry->port; assert(port != IP_NULL); ip_lock(port); assert(ip_kotype(port) == IKOT_HOST_NOTIFY); assert(port->ip_kobject == (ipc_kobject_t)entry); ipc_kobject_set_atomically(port, IKO_NULL, IKOT_NONE); ip_unlock(port); mutex_unlock(&host_notify_lock); zfree(host_notify_zone, (vm_offset_t)entry); msg->msgh_remote_port = port; (void) mach_msg_send_from_kernel(msg, msg_size); mutex_lock(&host_notify_lock); } } mutex_unlock(&host_notify_lock); }
/* * Routine: ipc_kobject_set * Purpose: * Make a port represent a kernel object of the given type. * The caller is responsible for handling refs for the * kernel object, if necessary. * Conditions: * Nothing locked. The port must be active if setting * a kobject linkage. Clearing a linkage is OK on an * inactive port. */ void ipc_kobject_set( ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t type) { ip_lock(port); ipc_kobject_set_atomically(port, kobject, type); #if CONFIG_MACF_MACH mac_port_label_update_kobject (&port->ip_label, type); #endif ip_unlock(port); }
/* * 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); }
kern_return_t host_request_notification( host_t host, host_flavor_t notify_type, ipc_port_t port) { host_notify_t entry; if (host == HOST_NULL) return (KERN_INVALID_ARGUMENT); if (!IP_VALID(port)) return (KERN_INVALID_CAPABILITY); if (notify_type > HOST_NOTIFY_TYPE_MAX || notify_type < 0) return (KERN_INVALID_ARGUMENT); entry = (host_notify_t)zalloc(host_notify_zone); if (entry == NULL) return (KERN_RESOURCE_SHORTAGE); mutex_lock(&host_notify_lock); ip_lock(port); if (!ip_active(port) || ip_kotype(port) != IKOT_NONE) { ip_unlock(port); mutex_unlock(&host_notify_lock); zfree(host_notify_zone, (vm_offset_t)entry); return (KERN_FAILURE); } entry->port = port; ipc_kobject_set_atomically(port, (ipc_kobject_t)entry, IKOT_HOST_NOTIFY); ip_unlock(port); enqueue_tail(&host_notify_queue[notify_type], (queue_entry_t)entry); mutex_unlock(&host_notify_lock); return (KERN_SUCCESS); }
mach_port_name_t mk_timer_create_trap( __unused struct mk_timer_create_trap_args *args) { mk_timer_t timer; ipc_space_t myspace = current_space(); mach_port_name_t name = MACH_PORT_NULL; ipc_port_t port; kern_return_t result; timer = (mk_timer_t)zalloc(mk_timer_zone); if (timer == NULL) return (MACH_PORT_NULL); result = mach_port_allocate_qos(myspace, MACH_PORT_RIGHT_RECEIVE, &mk_timer_qos, &name); if (result == KERN_SUCCESS) result = ipc_port_translate_receive(myspace, name, &port); if (result != KERN_SUCCESS) { zfree(mk_timer_zone, timer); return (MACH_PORT_NULL); } simple_lock_init(&timer->lock, 0); call_entry_setup(&timer->call_entry, mk_timer_expire, timer); timer->is_armed = timer->is_dead = FALSE; timer->active = 0; timer->port = port; ipc_kobject_set_atomically(port, (ipc_kobject_t)timer, IKOT_TIMER); port->ip_srights++; ip_reference(port); ip_unlock(port); return (name); }