- lock_set_t lock_set = LOCK_SET_NULL;
- ulock_t ulock;
- vm_size_t size;
- int x;
-
- *new_lock_set = LOCK_SET_NULL;
-
- if (task == TASK_NULL || n_ulocks <= 0 || policy > SYNC_POLICY_MAX)
- return KERN_INVALID_ARGUMENT;
-
- if ((VM_MAX_ADDRESS - sizeof(struct lock_set))/sizeof(struct ulock) < (unsigned)n_ulocks)
- return KERN_RESOURCE_SHORTAGE;
-
- size = sizeof(struct lock_set) + (sizeof(struct ulock) * (n_ulocks-1));
- lock_set = (lock_set_t) kalloc (size);
-
- if (lock_set == LOCK_SET_NULL)
- return KERN_RESOURCE_SHORTAGE;
-
-
- lock_set_lock_init(lock_set);
- lock_set->n_ulocks = n_ulocks;
- lock_set->ref_count = 1;
-
- /*
- * Create and initialize the lock set port
- */
- lock_set->port = ipc_port_alloc_kernel();
- if (lock_set->port == IP_NULL) {
- /* This will deallocate the lock set */
- lock_set_dereference(lock_set);
- return KERN_RESOURCE_SHORTAGE;
- }
-
- ipc_kobject_set (lock_set->port,
- (ipc_kobject_t) lock_set,
- IKOT_LOCK_SET);
-
- /*
- * Initialize each ulock in the lock set
- */
-
- for (x=0; x < n_ulocks; x++) {
- ulock = (ulock_t) &lock_set->ulock_list[x];
- ulock_lock_init(ulock);
- ulock->lock_set = lock_set;
- ulock->holder = THREAD_NULL;
- ulock->blocked = FALSE;
- ulock->unstable = FALSE;
- ulock->ho_wait = FALSE;
- wait_queue_init(&ulock->wait_queue, policy);
- }
-
- lock_set_ownership_set(lock_set, task);
-
- lock_set->active = TRUE;
- *new_lock_set = lock_set;
-
- return KERN_SUCCESS;
-}
-
-/*
- * ROUTINE: lock_set_destroy [exported]
- *
- * Destroys a lock set. This call will only succeed if the
- * specified task is the SAME task name specified at the lock set's
- * creation.
- *
- * NOTES:
- * - All threads currently blocked on the lock set's ulocks are awoken.
- * - These threads will return with the KERN_LOCK_SET_DESTROYED error.
- */
-kern_return_t
-lock_set_destroy (task_t task, lock_set_t lock_set)
-{
- ulock_t ulock;
- int i;
-
- if (task == TASK_NULL || lock_set == LOCK_SET_NULL)
- return KERN_INVALID_ARGUMENT;
-
- if (lock_set->owner != task)
- return KERN_INVALID_RIGHT;
-
- lock_set_lock(lock_set);
- if (!lock_set->active) {
- lock_set_unlock(lock_set);
- return KERN_LOCK_SET_DESTROYED;
- }
-
- /*
- * Deactivate lock set
- */
- lock_set->active = FALSE;
-
- /*
- * If a ulock is currently held in the target lock set:
- *
- * 1) Wakeup all threads blocked on the ulock (if any). Threads
- * may be blocked waiting normally, or waiting for a handoff.
- * Blocked threads will return with KERN_LOCK_SET_DESTROYED.
- *
- * 2) ulock ownership is cleared.
- * The thread currently holding the ulock is revoked of its
- * ownership.
- */
- for (i = 0; i < lock_set->n_ulocks; i++) {
- ulock = &lock_set->ulock_list[i];
-
- ulock_lock(ulock);
-
- if (ulock->accept_wait) {
- ulock->accept_wait = FALSE;
- wait_queue_wakeup64_one(&ulock->wait_queue,
- LOCK_SET_HANDOFF,
- THREAD_RESTART);
- }
-
- if (ulock->holder) {
- if (ulock->blocked) {
- ulock->blocked = FALSE;
- wait_queue_wakeup64_all(&ulock->wait_queue,
- LOCK_SET_EVENT,
- THREAD_RESTART);
- }
- if (ulock->ho_wait) {
- ulock->ho_wait = FALSE;
- wait_queue_wakeup64_one(&ulock->wait_queue,
- LOCK_SET_HANDOFF,
- THREAD_RESTART);
- }
- ulock_ownership_clear(ulock);
- }
-
- ulock_unlock(ulock);
- }
-
- lock_set_unlock(lock_set);
- lock_set_ownership_clear(lock_set, task);
-
- /*
- * Deallocate
- *
- * Drop the lock set reference, which inturn destroys the
- * lock set structure if the reference count goes to zero.
- */
-
- ipc_port_dealloc_kernel(lock_set->port);
- lock_set_dereference(lock_set);
-
- return KERN_SUCCESS;
-}
-
-kern_return_t
-lock_acquire (lock_set_t lock_set, int lock_id)
-{
- ulock_t ulock;
-
- if (lock_set == LOCK_SET_NULL)
- return KERN_INVALID_ARGUMENT;
-
- if (lock_id < 0 || lock_id >= lock_set->n_ulocks)
- return KERN_INVALID_ARGUMENT;
-
- retry:
- lock_set_lock(lock_set);
- if (!lock_set->active) {
- lock_set_unlock(lock_set);
- return KERN_LOCK_SET_DESTROYED;
- }
-
- ulock = (ulock_t) &lock_set->ulock_list[lock_id];
- ulock_lock(ulock);
- lock_set_unlock(lock_set);
-
- /*
- * Block the current thread if the lock is already held.
- */
-
- if (ulock->holder != THREAD_NULL) {
- int wait_result;
-
- if (ulock->holder == current_thread()) {
- ulock_unlock(ulock);
- return KERN_LOCK_OWNED_SELF;
- }
-
- ulock->blocked = TRUE;
- wait_result = wait_queue_assert_wait64(&ulock->wait_queue,
- LOCK_SET_EVENT,
- THREAD_ABORTSAFE, 0);
- ulock_unlock(ulock);
-
- /*
- * Block - Wait for lock to become available.
- */
- if (wait_result == THREAD_WAITING)
- wait_result = thread_block(THREAD_CONTINUE_NULL);
-
- /*
- * Check the result status:
- *
- * Check to see why thread was woken up. In all cases, we
- * already have been removed from the queue.
- */
- switch (wait_result) {
- case THREAD_AWAKENED:
- /* lock transitioned from old locker to us */
- /* he already made us owner */
- return (ulock->unstable) ? KERN_LOCK_UNSTABLE :
- KERN_SUCCESS;
-
- case THREAD_INTERRUPTED:
- return KERN_ABORTED;
-
- case THREAD_RESTART:
- goto retry; /* probably a dead lock_set */
-
- default:
- panic("lock_acquire\n");
- }
- }
-
- /*
- * Assign lock ownership
- */
- ulock_ownership_set(ulock, current_thread());
- ulock_unlock(ulock);
-
- return (ulock->unstable) ? KERN_LOCK_UNSTABLE : KERN_SUCCESS;