]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/sync_sema.c
xnu-2422.100.13.tar.gz
[apple/xnu.git] / osfmk / kern / sync_sema.c
index a072684adde6b4ec4986de0ba5a6854a8ca6c5f4..812aa800a1ba8aae5450a1af488a6ad7f27a3c3b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -58,6 +58,8 @@
 #include <kern/zalloc.h>
 #include <kern/mach_param.h>
 
+#include <libkern/OSAtomic.h>
+
 static unsigned int semaphore_event;
 #define SEMAPHORE_EVENT CAST_EVENT64_T(&semaphore_event)
 
@@ -179,7 +181,12 @@ semaphore_create(
        }
 
        s->count = value;
-       s->ref_count = (task == kernel_task) ? 1 : 2;
+
+       /*
+        * One reference for caller, one for port, and one for owner
+        * task (if not the kernel itself).
+        */
+       s->ref_count = (task == kernel_task) ? 2 : 3;
 
        /*
         *  Create and initialize the semaphore port
@@ -241,7 +248,7 @@ semaphore_destroy(
                task_unlock(task);
                return KERN_INVALID_ARGUMENT;
        }
-       remqueue(&task->semaphore_list, (queue_entry_t) semaphore);
+       remqueue((queue_entry_t) semaphore);
        semaphore->owner = TASK_NULL;
        task->semaphores_owned--;
        task_unlock(task);
@@ -630,7 +637,9 @@ semaphore_wait_internal(
                (void)wait_queue_assert_wait64_locked(
                                        &wait_semaphore->wait_queue,
                                        SEMAPHORE_EVENT,
-                                       THREAD_ABORTSAFE, deadline,
+                                       THREAD_ABORTSAFE,
+                                       TIMEOUT_URGENCY_USER_NORMAL,
+                                       deadline, 0,
                                        self);
                thread_unlock(self);
        }
@@ -1060,9 +1069,21 @@ semaphore_dereference(
        if (semaphore != NULL) {
                ref_count = hw_atomic_sub(&semaphore->ref_count, 1);
 
+               if (ref_count == 1) {
+                       ipc_port_t port = semaphore->port;
+
+                       if (IP_VALID(port) && 
+                           OSCompareAndSwapPtr(port, IP_NULL, &semaphore->port)) {
+                               /*
+                                * We get to disassociate the port from the sema and
+                                * drop the port's reference on the sema.
+                                */
+                               ipc_port_dealloc_kernel(port);
+                               ref_count = hw_atomic_sub(&semaphore->ref_count, 1);
+                       }
+               }
                if (ref_count == 0) {
                        assert(wait_queue_empty(&semaphore->wait_queue));
-                       ipc_port_dealloc_kernel(semaphore->port);
                        zfree(semaphore_zone, semaphore);
                }
        }