/* * 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; }
/* * Routine: semaphore_dereference * * Release a reference on a semaphore. If this is the last reference, * the semaphore data structure is deallocated. */ void semaphore_dereference( semaphore_t semaphore) { uint32_t collisions; spl_t spl_level; if (semaphore == NULL) return; if (hw_atomic_sub(&semaphore->ref_count, 1) != 0) return; /* * Last ref, clean up the port [if any] * associated with the semaphore, destroy * it (if still active) and then free * the semaphore. */ ipc_port_t port = semaphore->port; if (IP_VALID(port)) { assert(!port->ip_srights); ipc_port_dealloc_kernel(port); } /* * Lock the semaphore to lock in the owner task reference. * Then continue to try to lock the task (inverse order). */ spl_level = splsched(); semaphore_lock(semaphore); for (collisions = 0; semaphore->active; collisions++) { task_t task = semaphore->owner; assert(task != TASK_NULL); if (task_lock_try(task)) { semaphore_destroy_internal(task, semaphore); /* semaphore unlocked */ splx(spl_level); task_unlock(task); goto out; } /* failed to get out-of-order locks */ semaphore_unlock(semaphore); splx(spl_level); mutex_pause(collisions); spl_level = splsched(); semaphore_lock(semaphore); } semaphore_unlock(semaphore); splx(spl_level); out: zfree(semaphore_zone, semaphore); }