X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/43866e378188c25dd1e2208016ab3cbeb086ae6c..d26ffc64f583ab2d29df48f13518685602bc8832:/osfmk/kern/ipc_sync.c diff --git a/osfmk/kern/ipc_sync.c b/osfmk/kern/ipc_sync.c index 37ced9071..941bd1839 100644 --- a/osfmk/kern/ipc_sync.c +++ b/osfmk/kern/ipc_sync.c @@ -1,16 +1,19 @@ /* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER @@ -20,7 +23,7 @@ * Please see the License for the specific language governing rights and * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ @@ -34,18 +37,26 @@ #include #include #include +#include #include #include #include #include +/* + * Routine: port_name_to_semaphore + * Purpose: + * Convert from a port name in the current space to a semaphore. + * Produces a semaphore ref, which may be null. + * Conditions: + * Nothing locked. + */ kern_return_t port_name_to_semaphore( mach_port_name_t name, semaphore_t *semaphorep) { - semaphore_t semaphore; ipc_port_t kern_port; kern_return_t kr; @@ -53,7 +64,7 @@ port_name_to_semaphore( *semaphorep = SEMAPHORE_NULL; return KERN_INVALID_NAME; } - + kr = ipc_object_translate(current_space(), name, MACH_PORT_RIGHT_SEND, (ipc_object_t *) &kern_port); if (kr != KERN_SUCCESS) { @@ -63,79 +74,144 @@ port_name_to_semaphore( /* have the port locked */ assert(IP_VALID(kern_port)); - if (!ip_active(kern_port) || (ip_kotype(kern_port) != IKOT_SEMAPHORE)) { - ip_unlock(kern_port); - *semaphorep = SEMAPHORE_NULL; - return KERN_INVALID_ARGUMENT; + *semaphorep = convert_port_to_semaphore(kern_port); + if (*semaphorep == SEMAPHORE_NULL) { + /* the port is valid, but doesn't denote a semaphore */ + kr = KERN_INVALID_CAPABILITY; + } else { + kr = KERN_SUCCESS; } - - semaphore = (semaphore_t) kern_port->ip_kobject; - assert(semaphore != SEMAPHORE_NULL); - semaphore_reference(semaphore); ip_unlock(kern_port); - *semaphorep = semaphore; - return KERN_SUCCESS; + return kr; } - + +/* + * Routine: convert_port_to_semaphore + * Purpose: + * Convert from a port to a semaphore. + * Doesn't consume the port [send-right] ref; + * produces a semaphore ref, which may be null. + * Conditions: + * Caller has a send-right reference to port. + * Port may or may not be locked. + */ semaphore_t convert_port_to_semaphore (ipc_port_t port) { - semaphore_t semaphore = SEMAPHORE_NULL; - if (IP_VALID (port)) { - ip_lock(port); - if (ip_active(port) && (ip_kotype(port) == IKOT_SEMAPHORE)) { + if (IP_VALID(port)) { + semaphore_t semaphore; + + /* + * No need to lock because we have a reference on the + * port, and if it is a true semaphore port, that reference + * keeps the semaphore bound to the port (and active). + */ + if (ip_kotype(port) == IKOT_SEMAPHORE) { + assert(ip_active(port)); semaphore = (semaphore_t) port->ip_kobject; semaphore_reference(semaphore); + return (semaphore); } - ip_unlock(port); } - - return (semaphore); + return SEMAPHORE_NULL; } +/* + * 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; + ipc_port_t port, send; - if (semaphore != SEMAPHORE_NULL) - port = ipc_port_make_send(semaphore->port); - else - port = IP_NULL; + if (semaphore == SEMAPHORE_NULL) + return (IP_NULL); - return (port); -} + /* caller is donating a reference */ + port = semaphore->port; -lock_set_t -convert_port_to_lock_set (ipc_port_t port) -{ - lock_set_t lock_set = LOCK_SET_NULL; + 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 (IP_VALID (port)) { - ip_lock(port); - if (ip_active(port) && (ip_kotype(port) == IKOT_LOCK_SET)) { - lock_set = (lock_set_t) port->ip_kobject; - lock_set_reference(lock_set); + /* 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_unlock(port); } - return (lock_set); + 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); } -ipc_port_t -convert_lock_set_to_port (lock_set_t lock_set) +/* + * 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) { - ipc_port_t port; + 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; - if (lock_set != LOCK_SET_NULL) - port = ipc_port_make_send(lock_set->port); - else - port = IP_NULL; + semaphore_dereference(semaphore); +} - return (port); +lock_set_t +convert_port_to_lock_set (__unused ipc_port_t port) +{ + return (LOCK_SET_NULL); +} + +ipc_port_t +convert_lock_set_to_port (__unused lock_set_t lock_set) +{ + return (IP_NULL); }