/* * Routine: wait_queue_set_unlink_all * Purpose: * Remove the linkage between a set wait queue and all its * member wait queues. The link structures are freed for those * links which were dynamically allocated. * Conditions: * The wait queue must be a set */ kern_return_t wait_queue_set_unlink_all( wait_queue_set_t wq_set) { wait_queue_link_t wql; wait_queue_t wq; queue_t q; queue_head_t links_queue_head; queue_t links = &links_queue_head; spl_t s; if (!wait_queue_is_set(wq_set)) { return KERN_INVALID_ARGUMENT; } queue_init(links); retry: s = splsched(); wqs_lock(wq_set); q = &wq_set->wqs_setlinks; wql = (wait_queue_link_t)queue_first(q); while (!queue_end(q, (queue_entry_t)wql)) { WAIT_QUEUE_SET_LINK_CHECK(wq_set, wql); wq = wql->wql_queue; if (wait_queue_lock_try(wq)) { boolean_t alloced; alloced = (wql->wql_type == WAIT_QUEUE_LINK); wait_queue_unlink_locked(wq, wq_set, wql); wait_queue_unlock(wq); if (alloced) enqueue(links, &wql->wql_links); wql = (wait_queue_link_t)queue_first(q); } else { wqs_unlock(wq_set); splx(s); delay(1); goto retry; } } wqs_unlock(wq_set); splx(s); while (!queue_empty (links)) { wql = (wait_queue_link_t) dequeue(links); zfree(_wait_queue_link_zone, wql); } return(KERN_SUCCESS); }
/* * Routine: wait_queue_set_unlink_all * Purpose: * Remove the linkage between a set wait queue and all its * member wait queues. The link structures are freed. * Conditions: * The wait queue must be a set */ kern_return_t wait_queue_set_unlink_all( wait_queue_set_t wq_set) { wait_queue_link_t wql; wait_queue_t wq; queue_t q; queue_head_t links_queue_head; queue_t links = &links_queue_head; kern_return_t kret; spl_t s; if (!wait_queue_is_set(wq_set)) { return KERN_INVALID_ARGUMENT; } queue_init(links); retry: s = splsched(); wqs_lock(wq_set); q = &wq_set->wqs_setlinks; wql = (wait_queue_link_t)queue_first(q); while (!queue_end(q, (queue_entry_t)wql)) { WAIT_QUEUE_SET_LINK_CHECK(wq_set, wql); wq = wql->wql_queue; if (wait_queue_lock_try(wq)) { wait_queue_unlink_locked(wq, wq_set, wql); wait_queue_unlock(wq); enqueue(links, &wql->wql_links); wql = (wait_queue_link_t)queue_first(q); } else { wqs_unlock(wq_set); splx(s); delay(1); goto retry; } } wqs_unlock(wq_set); splx(s); while (!queue_empty (links)) { wql = (wait_queue_link_t) dequeue(links); kfree((vm_offset_t)wql, sizeof(struct wait_queue_link)); } return(KERN_SUCCESS); }
kern_return_t wait_queue_set_unlink_one( wait_queue_set_t wq_set, wait_queue_link_t wql) { wait_queue_t wq; spl_t s; assert(wait_queue_is_set(wq_set)); retry: s = splsched(); wqs_lock(wq_set); WAIT_QUEUE_SET_CHECK(wq_set); /* Already unlinked, e.g. by selclearthread() */ if (wql->wql_type == WAIT_QUEUE_UNLINKED) { goto out; } WAIT_QUEUE_SET_LINK_CHECK(wq_set, wql); /* On a wait queue, and we hold set queue lock ... */ wq = wql->wql_queue; if (wait_queue_lock_try(wq)) { wait_queue_unlink_locked(wq, wq_set, wql); wait_queue_unlock(wq); } else { wqs_unlock(wq_set); splx(s); delay(1); goto retry; } out: wqs_unlock(wq_set); splx(s); return KERN_SUCCESS; }
/* * Routine: wait_queue_set_unlink_all_nofree * Purpose: * Remove the linkage between a set wait queue and all its * member wait queues. The link structures are not freed, nor * returned. It is the caller's responsibility to track and free * them. * Conditions: * The wait queue being must be a member set queue */ kern_return_t wait_queue_set_unlink_all_nofree( wait_queue_set_t wq_set) { wait_queue_link_t wql; wait_queue_t wq; queue_t q; kern_return_t kret; spl_t s; if (!wait_queue_is_set(wq_set)) { return KERN_INVALID_ARGUMENT; } retry: s = splsched(); wqs_lock(wq_set); q = &wq_set->wqs_setlinks; wql = (wait_queue_link_t)queue_first(q); while (!queue_end(q, (queue_entry_t)wql)) { WAIT_QUEUE_SET_LINK_CHECK(wq_set, wql); wq = wql->wql_queue; if (wait_queue_lock_try(wq)) { wait_queue_unlink_locked(wq, wq_set, wql); wait_queue_unlock(wq); wql = (wait_queue_link_t)queue_first(q); } else { wqs_unlock(wq_set); splx(s); delay(1); goto retry; } } wqs_unlock(wq_set); splx(s); return(KERN_SUCCESS); }