+ wq_element = (wait_queue_element_t)
+ queue_next((queue_t) wq_element);
+ }
+ wait_queue_unlock(wq);
+ splx(s);
+ return KERN_NOT_IN_SET;
+}
+
+
+/*
+ * Routine: wait_queue_unlinkall_nofree
+ * Purpose:
+ * Remove the linkage between a wait queue and all its
+ * sets. The caller is responsible for freeing
+ * the wait queue link structures.
+ */
+
+kern_return_t
+wait_queue_unlinkall_nofree(
+ wait_queue_t wq)
+{
+ wait_queue_element_t wq_element;
+ wait_queue_element_t wq_next_element;
+ wait_queue_set_t wq_set;
+ wait_queue_link_t wql;
+ queue_head_t links_queue_head;
+ queue_t links = &links_queue_head;
+ queue_t q;
+ spl_t s;
+
+ if (!wait_queue_is_queue(wq)) {
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ queue_init(links);
+
+ s = splsched();
+ wait_queue_lock(wq);
+
+ q = &wq->wq_queue;
+
+ wq_element = (wait_queue_element_t) queue_first(q);
+ while (!queue_end(q, (queue_entry_t)wq_element)) {
+ WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element);
+ wq_next_element = (wait_queue_element_t)
+ queue_next((queue_t) wq_element);
+
+ if (wq_element->wqe_type == WAIT_QUEUE_LINK) {
+ wql = (wait_queue_link_t)wq_element;
+ wq_set = wql->wql_setqueue;
+ wqs_lock(wq_set);
+ wait_queue_unlink_locked(wq, wq_set, wql);
+ wqs_unlock(wq_set);
+ }
+ wq_element = wq_next_element;
+ }
+ wait_queue_unlock(wq);
+ splx(s);
+ return(KERN_SUCCESS);
+}
+
+
+/*
+ * Routine: wait_queue_unlink_all
+ * Purpose:
+ * Remove the linkage between a wait queue and all its sets.
+ * All the linkage structures are freed.
+ * Conditions:
+ * Nothing of interest locked.
+ */
+
+kern_return_t
+wait_queue_unlink_all(
+ wait_queue_t wq)
+{
+ wait_queue_element_t wq_element;
+ wait_queue_element_t wq_next_element;
+ wait_queue_set_t wq_set;
+ wait_queue_link_t wql;
+ queue_head_t links_queue_head;
+ queue_t links = &links_queue_head;
+ queue_t q;
+ spl_t s;
+
+ if (!wait_queue_is_queue(wq)) {
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ queue_init(links);
+
+ s = splsched();
+ wait_queue_lock(wq);
+
+ q = &wq->wq_queue;
+
+ wq_element = (wait_queue_element_t) queue_first(q);
+ while (!queue_end(q, (queue_entry_t)wq_element)) {
+ WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element);
+ wq_next_element = (wait_queue_element_t)
+ queue_next((queue_t) wq_element);
+
+ if (wq_element->wqe_type == WAIT_QUEUE_LINK) {
+ wql = (wait_queue_link_t)wq_element;
+ wq_set = wql->wql_setqueue;
+ wqs_lock(wq_set);
+ wait_queue_unlink_locked(wq, wq_set, wql);
+ wqs_unlock(wq_set);
+ enqueue(links, &wql->wql_links);
+ }
+ wq_element = wq_next_element;
+ }
+ wait_queue_unlock(wq);
+ splx(s);
+
+ while(!queue_empty(links)) {
+ wql = (wait_queue_link_t) dequeue(links);
+ kfree(wql, sizeof(struct _wait_queue_link));
+ }
+
+ 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;
+ 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);
+}
+
+/* legacy interface naming */
+kern_return_t
+wait_subqueue_unlink_all(
+ wait_queue_set_t wq_set)
+{
+ return wait_queue_set_unlink_all_nofree(wq_set);
+}
+
+
+/*
+ * 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;
+ 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);