void mach_port_gst_helper( ipc_pset_t pset, ipc_port_t port, ipc_entry_num_t maxnames, mach_port_name_t *names, ipc_entry_num_t *actualp) { ipc_pset_t ip_pset; mach_port_name_t name; assert(port != IP_NULL); ip_lock(port); assert(ip_active(port)); name = port->ip_receiver_name; assert(name != MACH_PORT_NULL); ip_unlock(port); if (ipc_pset_member(pset, port)) { ipc_entry_num_t actual = *actualp; if (actual < maxnames) names[actual] = name; *actualp = actual+1; } }
void ipc_port_clear_receiver( ipc_port_t port, queue_t links) { spl_t s; assert(ip_active(port)); /* * pull ourselves from any sets. */ if (port->ip_pset_count != 0) { ipc_pset_remove_from_all(port, links); assert(port->ip_pset_count == 0); } /* * Send anyone waiting on the port's queue directly away. * Also clear the mscount and seqno. */ s = splsched(); imq_lock(&port->ip_messages); ipc_mqueue_changed(&port->ip_messages); ipc_port_set_mscount(port, 0); port->ip_messages.imq_seqno = 0; port->ip_context = port->ip_guarded = port->ip_strict_guard = 0; imq_unlock(&port->ip_messages); splx(s); }
void ipc_pset_add( ipc_pset_t pset, ipc_port_t port) { assert(ips_active(pset)); assert(ip_active(port)); assert(port->ip_pset == IPS_NULL); port->ip_pset = pset; port->ip_cur_target = &pset->ips_target; ips_reference(pset); imq_lock(&port->ip_messages); imq_lock(&pset->ips_messages); /* move messages from port's queue to the port set's queue */ ipc_mqueue_move(&pset->ips_messages, &port->ip_messages, port); imq_unlock(&pset->ips_messages); assert(ipc_kmsg_queue_empty(&port->ip_messages.imq_messages)); /* wake up threads waiting to receive from the port */ ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_CHANGED); assert(ipc_thread_queue_empty(&port->ip_messages.imq_threads)); imq_unlock(&port->ip_messages); }
void ipc_port_nsrequest( ipc_port_t port, mach_port_mscount_t sync, ipc_port_t notify, ipc_port_t *previousp) { ipc_port_t previous; mach_port_mscount_t mscount; assert(ip_active(port)); previous = port->ip_nsrequest; mscount = port->ip_mscount; if ((port->ip_srights == 0) && (sync <= mscount) && (notify != IP_NULL)) { port->ip_nsrequest = IP_NULL; ip_unlock(port); ipc_notify_no_senders(notify, mscount); } else { port->ip_nsrequest = notify; ip_unlock(port); } *previousp = previous; }
void ipc_port_release_send( ipc_port_t port) { ipc_port_t nsrequest = IP_NULL; mach_port_mscount_t mscount; if (!IP_VALID(port)) return; ip_lock(port); if (!ip_active(port)) { ip_unlock(port); ip_release(port); return; } assert(port->ip_srights > 0); if (--port->ip_srights == 0 && port->ip_nsrequest != IP_NULL) { nsrequest = port->ip_nsrequest; port->ip_nsrequest = IP_NULL; mscount = port->ip_mscount; ip_unlock(port); ip_release(port); ipc_notify_no_senders(nsrequest, mscount); } else { ip_unlock(port); ip_release(port); } }
EXTERN io_object_t iokit_lookup_connect_ref(io_object_t connectRef, ipc_space_t space) { io_object_t obj = NULL; if (connectRef && MACH_PORT_VALID(CAST_MACH_PORT_TO_NAME(connectRef))) { ipc_port_t port; kern_return_t kr; kr = ipc_object_translate(space, CAST_MACH_PORT_TO_NAME(connectRef), MACH_PORT_RIGHT_SEND, (ipc_object_t *)&port); if (kr == KERN_SUCCESS) { assert(IP_VALID(port)); ip_reference(port); ip_unlock(port); iokit_lock_port(port); if (ip_active(port) && (ip_kotype(port) == IKOT_IOKIT_CONNECT)) { obj = (io_object_t) port->ip_kobject; iokit_add_connect_reference(obj); } iokit_unlock_port(port); ip_release(port); } } return obj; }
/* * Routine: convert_port_to_locked_task * Purpose: * Internal helper routine to convert from a port to a locked * task. Used by several routines that try to convert from a * task port to a reference on some task related object. * Conditions: * Nothing locked, blocking OK. */ task_t convert_port_to_locked_task(ipc_port_t port) { int try_failed_count = 0; while (IP_VALID(port)) { task_t task; ip_lock(port); if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) { ip_unlock(port); return TASK_NULL; } task = (task_t) port->ip_kobject; assert(task != TASK_NULL); /* * Normal lock ordering puts task_lock() before ip_lock(). * Attempt out-of-order locking here. */ if (task_lock_try(task)) { ip_unlock(port); return(task); } try_failed_count++; ip_unlock(port); mutex_pause(try_failed_count); } return TASK_NULL; }
ipc_port_t retrieve_task_self_fast( register task_t task) { register ipc_port_t port; assert(task == current_task()); itk_lock(task); assert(task->itk_self != IP_NULL); if ((port = task->itk_sself) == task->itk_self) { /* no interposing */ ip_lock(port); assert(ip_active(port)); ip_reference(port); port->ip_srights++; ip_unlock(port); } else port = ipc_port_copy_send(port); itk_unlock(task); return port; }
ipc_port_t retrieve_thread_self_fast( thread_t thread) { register ipc_port_t port; assert(thread == current_thread()); thread_mtx_lock(thread); assert(thread->ith_self != IP_NULL); if ((port = thread->ith_sself) == thread->ith_self) { /* no interposing */ ip_lock(port); assert(ip_active(port)); ip_reference(port); port->ip_srights++; ip_unlock(port); } else port = ipc_port_copy_send(port); thread_mtx_unlock(thread); return port; }
/* * fileport_notify * * Description: Handle a no-senders notification for a fileport. Unless * the message is spoofed, destroys the port and releases * its reference on the fileglob. * * Parameters: msg A Mach no-senders notification message. */ void fileport_notify(mach_msg_header_t *msg) { mach_no_senders_notification_t *notification = (void *)msg; ipc_port_t port = notification->not_header.msgh_remote_port; struct fileglob *fg = NULL; if (!IP_VALID(port)) panic("Invalid port passed to fileport_notify()\n"); ip_lock(port); fg = (struct fileglob *)port->ip_kobject; if (!ip_active(port)) panic("Inactive port passed to fileport_notify()\n"); if (ip_kotype(port) != IKOT_FILEPORT) panic("Port of type other than IKOT_FILEPORT passed to fileport_notify()\n"); if (fg == NULL) panic("fileport without an assocated fileglob\n"); if (port->ip_srights == 0) { ip_unlock(port); fileport_releasefg(fg); ipc_port_dealloc_kernel(port); } else { ip_unlock(port); } return; }
kern_return_t ipc_port_dnrequest( ipc_port_t port, mach_port_name_t name, ipc_port_t soright, ipc_port_request_index_t *indexp) { ipc_port_request_t ipr, table; ipc_port_request_index_t index; assert(ip_active(port)); assert(name != MACH_PORT_NULL); assert(soright != IP_NULL); table = port->ip_dnrequests; if (table == IPR_NULL) return KERN_NO_SPACE; index = table->ipr_next; if (index == 0) return KERN_NO_SPACE; ipr = &table[index]; assert(ipr->ipr_name == MACH_PORT_NULL); table->ipr_next = ipr->ipr_next; ipr->ipr_name = name; ipr->ipr_soright = soright; *indexp = index; return KERN_SUCCESS; }
/* * Routine: convert_port_to_mig_object [interface] * Purpose: * Base implementation of MIG intrans routine to convert from * an incoming port reference to a new reference on the * underlying object. A new reference must be created, because * the port's reference could go away asynchronously. * Returns: * NULL - Not an active MIG object port or iid not supported * Otherwise, a reference to the underlying MIG interface * Conditions: * Nothing locked. */ mig_object_t convert_port_to_mig_object( ipc_port_t port, const MIGIID *iid) { mig_object_t mig_object; void *ppv; if (!IP_VALID(port)) return NULL; ip_lock(port); if (!ip_active(port) || (ip_kotype(port) != IKOT_MIG)) { ip_unlock(port); return NULL; } /* * Our port points to some MIG object interface. Now * query it to get a reference to the desired interface. */ ppv = NULL; mig_object = (mig_object_t)port->ip_kobject; mig_object->pVtbl->QueryInterface((IMIGObject *)mig_object, iid, &ppv); ip_unlock(port); return (mig_object_t)ppv; }
kern_return_t ipc_port_request_alloc( ipc_port_t port, mach_port_name_t name, ipc_port_t soright, boolean_t send_possible, boolean_t immediate, ipc_port_request_index_t *indexp) #endif /* IMPORTANCE_INHERITANCE */ { ipc_port_request_t ipr, table; ipc_port_request_index_t index; uintptr_t mask = 0; #if IMPORTANCE_INHERITANCE *importantp = FALSE; #endif /* IMPORTANCE_INHERITANCE */ assert(ip_active(port)); assert(name != MACH_PORT_NULL); assert(soright != IP_NULL); table = port->ip_requests; if (table == IPR_NULL) return KERN_NO_SPACE; index = table->ipr_next; if (index == 0) return KERN_NO_SPACE; ipr = &table[index]; assert(ipr->ipr_name == MACH_PORT_NULL); table->ipr_next = ipr->ipr_next; ipr->ipr_name = name; if (send_possible) { mask |= IPR_SOR_SPREQ_MASK; if (immediate) { mask |= IPR_SOR_SPARM_MASK; if (port->ip_sprequests == 0) { port->ip_sprequests = 1; #if IMPORTANCE_INHERITANCE if (port->ip_impdonation != 0 && port->ip_spimportant == 0 && (task_is_importance_donor(current_task()))) { port->ip_spimportant = 1; *importantp = TRUE; } #endif /* IMPORTANCE_INHERTANCE */ } } } ipr->ipr_soright = IPR_SOR_MAKE(soright, mask); *indexp = index; return KERN_SUCCESS; }
ipc_port_t ipc_port_lookup_notify( ipc_space_t space, mach_port_name_t name) { ipc_port_t port; ipc_entry_t entry; assert(is_active(space)); entry = ipc_entry_lookup(space, name); if (entry == IE_NULL) return IP_NULL; if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) return IP_NULL; port = (ipc_port_t) entry->ie_object; assert(port != IP_NULL); ip_lock(port); assert(ip_active(port)); assert(port->ip_receiver_name == name); assert(port->ip_receiver == space); ip_reference(port); port->ip_sorights++; ip_unlock(port); return port; }
ipc_port_t ipc_port_request_cancel( ipc_port_t port, __assert_only mach_port_name_t name, ipc_port_request_index_t index) { ipc_port_request_t ipr, table; ipc_port_t request = IP_NULL; assert(ip_active(port)); table = port->ip_requests; assert(table != IPR_NULL); assert (index != IE_REQ_NONE); ipr = &table[index]; assert(ipr->ipr_name == name); request = IPR_SOR_PORT(ipr->ipr_soright); /* return ipr to the free list inside the table */ ipr->ipr_name = MACH_PORT_NULL; ipr->ipr_next = table->ipr_next; table->ipr_next = index; return request; }
void ipc_port_set_qlimit( ipc_port_t port, mach_port_msgcount_t qlimit) { assert(ip_active(port)); /* wake up senders allowed by the new qlimit */ if (qlimit > port->ip_qlimit) { mach_port_msgcount_t i, wakeup; /* caution: wakeup, qlimit are unsigned */ wakeup = qlimit - port->ip_qlimit; for (i = 0; i < wakeup; i++) { ipc_thread_t th; th = ipc_thread_dequeue(&port->ip_blocked); if (th == ITH_NULL) break; th->ith_state = MACH_MSG_SUCCESS; thread_go(th); } } port->ip_qlimit = qlimit; }
ipc_port_t ipc_port_dncancel( ipc_port_t port, mach_port_name_t name, ipc_port_request_index_t index) { ipc_port_request_t ipr, table; ipc_port_t dnrequest; assert(ip_active(port)); assert(name != MACH_PORT_NAME_NULL); assert(index != 0); table = port->ip_dnrequests; assert(table != IPR_NULL); ipr = &table[index]; dnrequest = ipr->ipr_soright; assert(ipr->ipr_name == name); /* return ipr to the free list inside the table */ ipr->ipr_name = MACH_PORT_NAME_NULL; ipr->ipr_next = table->ipr_next; table->ipr_next = index; return dnrequest; }
boolean_t ipc_right_check( ipc_space_t space, ipc_port_t port, mach_port_t name, ipc_entry_t entry) { ipc_entry_bits_t bits; assert(space->is_active); assert(port == (ipc_port_t) entry->ie_object); ip_lock(port); if (ip_active(port)) return FALSE; ip_unlock(port); /* this was either a pure send right or a send-once right */ bits = entry->ie_bits; assert((bits & MACH_PORT_TYPE_RECEIVE) == 0); assert(IE_BITS_UREFS(bits) > 0); if (bits & MACH_PORT_TYPE_SEND) { assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND); /* clean up msg-accepted request */ if (bits & IE_BITS_MAREQUEST) { bits &= ~IE_BITS_MAREQUEST; ipc_marequest_cancel(space, name); } ipc_reverse_remove(space, (ipc_object_t) port); } else { assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); assert(IE_BITS_UREFS(bits) == 1); assert((bits & IE_BITS_MAREQUEST) == 0); } ipc_port_release(port); /* convert entry to dead name */ bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME; if (entry->ie_request != 0) { assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX); entry->ie_request = 0; bits++; /* increment urefs */ } entry->ie_bits = bits; entry->ie_object = IO_NULL; return TRUE; }
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 ); } } }
void exception( integer_t _exception, integer_t code, integer_t subcode) { ipc_thread_t self = current_thread(); ipc_port_t exc_port; if (_exception == KERN_SUCCESS) panic("exception"); /* * Optimized version of retrieve_thread_exception. */ ith_lock(self); assert(self->ith_self != IP_NULL); exc_port = self->ith_exception; if (!IP_VALID(exc_port)) { ith_unlock(self); exception_try_task(_exception, code, subcode); /*NOTREACHED*/ } ip_lock(exc_port); ith_unlock(self); if (!ip_active(exc_port)) { ip_unlock(exc_port); exception_try_task(_exception, code, subcode); /*NOTREACHED*/ } /* * Make a naked send right for the exception port. */ ip_reference(exc_port); exc_port->ip_srights++; ip_unlock(exc_port); /* * If this exception port doesn't work, * we will want to try the task's exception port. * Indicate this by saving the exception state. */ self->ith_exc = _exception; self->ith_exc_code = code; self->ith_exc_subcode = subcode; exception_raise(exc_port, retrieve_thread_self_fast(self), retrieve_task_self_fast(self->task), _exception, code, subcode); /*NOTREACHED*/ }
/* * Routine: ipc_pset_member * Purpose: * Checks to see if a port is a member of a pset * Conditions: * Both port and port set are locked. * The port must be active. */ boolean_t ipc_pset_member( ipc_pset_t pset, ipc_port_t port) { assert(ip_active(port)); return (ipc_mqueue_member(&port->ip_messages, &pset->ips_messages)); }
ipc_port_t ipc_port_make_sonce_locked( ipc_port_t port) { assert(ip_active(port)); port->ip_sorights++; ip_reference(port); return port; }
void mach_port_names_helper( ipc_port_timestamp_t timestamp, ipc_entry_t entry, mach_port_name_t name, mach_port_name_t *names, mach_port_type_t *types, ipc_entry_num_t *actualp, ipc_space_t space) { ipc_entry_bits_t bits; ipc_port_request_index_t request; mach_port_type_t type; ipc_entry_num_t actual; bits = entry->ie_bits; request = entry->ie_request; if (bits & MACH_PORT_TYPE_SEND_RIGHTS) { ipc_port_t port; boolean_t died; port = (ipc_port_t) entry->ie_object; assert(port != IP_NULL); /* * The timestamp serializes mach_port_names * with ipc_port_destroy. If the port died, * but after mach_port_names started, pretend * that it isn't dead. */ ip_lock(port); died = (!ip_active(port) && IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp)); ip_unlock(port); if (died) { /* pretend this is a dead-name entry */ bits &= ~(IE_BITS_TYPE_MASK); bits |= MACH_PORT_TYPE_DEAD_NAME; if (request != 0) bits++; request = 0; } } type = IE_BITS_TYPE(bits); if (request != 0) type |= MACH_PORT_TYPE_DNREQUEST; actual = *actualp; names[actual] = name; types[actual] = type; *actualp = actual+1; }
/* * Routine: ipc_port_make_send_locked * Purpose: * Make a naked send right from a receive right. * * Conditions: * port locked and active. */ ipc_port_t ipc_port_make_send_locked( ipc_port_t port) { assert(ip_active(port)); port->ip_mscount++; port->ip_srights++; ip_reference(port); return port; }
void exception_try_task( integer_t _exception, integer_t code, integer_t subcode) { ipc_thread_t self = current_thread(); task_t task = self->task; ipc_port_t exc_port; /* * Optimized version of retrieve_task_exception. */ itk_lock(task); assert(task->itk_self != IP_NULL); exc_port = task->itk_exception; if (!IP_VALID(exc_port)) { itk_unlock(task); exception_no_server(); /*NOTREACHED*/ } ip_lock(exc_port); itk_unlock(task); if (!ip_active(exc_port)) { ip_unlock(exc_port); exception_no_server(); /*NOTREACHED*/ } /* * Make a naked send right for the exception port. */ ip_reference(exc_port); exc_port->ip_srights++; ip_unlock(exc_port); /* * This is the thread's last chance. * Clear the saved exception state. */ self->ith_exc = KERN_SUCCESS; exception_raise(exc_port, retrieve_thread_self_fast(self), retrieve_task_self_fast(task), _exception, code, subcode); /*NOTREACHED*/ }
boolean_t ipc_right_reverse( ipc_space_t space, ipc_object_t object, mach_port_t *namep, ipc_entry_t *entryp) { ipc_port_t port; mach_port_t name; ipc_entry_t entry; /* would switch on io_otype to handle multiple types of object */ assert(space->is_active); assert(io_otype(object) == IOT_PORT); port = (ipc_port_t) object; ip_lock(port); if (!ip_active(port)) { ip_unlock(port); return FALSE; } if (port->ip_receiver == space) { name = port->ip_receiver_name; assert(name != MACH_PORT_NULL); entry = ipc_entry_lookup(space, name); assert(entry != IE_NULL); assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE); assert(port == (ipc_port_t) entry->ie_object); *namep = name; *entryp = entry; return TRUE; } if ((*entryp = ipc_reverse_lookup(space, (ipc_object_t) port))) { *namep = (*entryp)->ie_name; assert((entry = *entryp) != IE_NULL); assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND); assert(port == (ipc_port_t) entry->ie_object); return TRUE; } ip_unlock(port); return FALSE; }
void ipc_kobject_set_atomically( ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t type) { assert(type == IKOT_NONE || ip_active(port)); #if MACH_ASSERT port->ip_spares[2] = (port->ip_bits & IO_BITS_KOTYPE); #endif /* MACH_ASSERT */ port->ip_bits = (port->ip_bits &~ IO_BITS_KOTYPE) | type; port->ip_kobject = kobject; }
/* * Routine: semaphore_notify * Purpose: * Called whenever the Mach port system detects no-senders * on the semaphore port. * * When a send-right is first created, a no-senders * notification is armed (and a semaphore reference is donated). * * A no-senders notification will be posted when no one else holds a * send-right (reference) to the semaphore's port. This notification function * will consume the semaphore reference donated to the extant collection of * send-rights. */ void semaphore_notify(mach_msg_header_t *msg) { mach_no_senders_notification_t *notification = (void *)msg; ipc_port_t port = notification->not_header.msgh_remote_port; semaphore_t semaphore; assert(ip_active(port)); assert(IKOT_SEMAPHORE == ip_kotype(port)); semaphore = (semaphore_t)port->ip_kobject; semaphore_dereference(semaphore); }
ipc_port_t ipc_port_make_sonce( ipc_port_t port) { assert(IP_VALID(port)); ip_lock(port); assert(ip_active(port)); port->ip_sorights++; ip_reference(port); ip_unlock(port); return port; }
kern_return_t mach_port_kobject( ipc_space_t space, mach_port_name_t name, natural_t *typep, mach_vm_address_t *addrp) { ipc_entry_t entry; ipc_port_t port; kern_return_t kr; mach_vm_address_t kaddr; if (space == IS_NULL) return KERN_INVALID_TASK; kr = ipc_right_lookup_read(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is read-locked and active */ if ((entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0) { is_read_unlock(space); return KERN_INVALID_RIGHT; } __IGNORE_WCASTALIGN(port = (ipc_port_t) entry->ie_object); assert(port != IP_NULL); ip_lock(port); is_read_unlock(space); if (!ip_active(port)) { ip_unlock(port); return KERN_INVALID_RIGHT; } *typep = (unsigned int) ip_kotype(port); kaddr = (mach_vm_address_t)port->ip_kobject; ip_unlock(port); #if (DEVELOPMENT || DEBUG) if (0 != kaddr && is_ipc_kobject(*typep)) *addrp = VM_KERNEL_UNSLIDE_OR_PERM(kaddr); else #endif *addrp = 0; return KERN_SUCCESS; }