- if (semaphore->active) {
- assert(semaphore->owner != TASK_NULL);
- semaphore_destroy_internal(semaphore->owner, semaphore);
+
+ /*
+ * 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);