/*
- * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#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)
}
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
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);
(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);
}
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);
}
}