+/*
+ * Routine: ipc_mqueue_peek
+ * Purpose:
+ * Peek at a (non-set) message queue to see if it has a message
+ * matching the sequence number provided (if zero, then the
+ * first message in the queue) and return vital info about the
+ * message.
+ *
+ * Conditions:
+ * Locks may be held by callers, so this routine cannot block.
+ * Caller holds reference on the message queue.
+ */
+unsigned
+ipc_mqueue_peek(ipc_mqueue_t mq,
+ mach_port_seqno_t *seqnop,
+ mach_msg_size_t *msg_sizep,
+ mach_msg_id_t *msg_idp,
+ mach_msg_max_trailer_t *msg_trailerp)
+{
+ ipc_kmsg_queue_t kmsgq;
+ ipc_kmsg_t kmsg;
+ mach_port_seqno_t seqno, msgoff;
+ int res = 0;
+ spl_t s;
+
+ assert(!imq_is_set(mq));
+
+ s = splsched();
+ imq_lock(mq);
+
+ seqno = (seqnop != NULL) ? seqno = *seqnop : 0;
+
+ if (seqno == 0) {
+ seqno = mq->imq_seqno;
+ msgoff = 0;
+ } else if (seqno >= mq->imq_seqno &&
+ seqno < mq->imq_seqno + mq->imq_msgcount) {
+ msgoff = seqno - mq->imq_seqno;
+ } else
+ goto out;
+
+ /* look for the message that would match that seqno */
+ kmsgq = &mq->imq_messages;
+ kmsg = ipc_kmsg_queue_first(kmsgq);
+ while (msgoff-- && kmsg != IKM_NULL) {
+ kmsg = ipc_kmsg_queue_next(kmsgq, kmsg);
+ }
+ if (kmsg == IKM_NULL)
+ goto out;
+
+ /* found one - return the requested info */
+ if (seqnop != NULL)
+ *seqnop = seqno;
+ if (msg_sizep != NULL)
+ *msg_sizep = kmsg->ikm_header->msgh_size;
+ if (msg_idp != NULL)
+ *msg_idp = kmsg->ikm_header->msgh_id;
+ if (msg_trailerp != NULL)
+ memcpy(msg_trailerp,
+ (mach_msg_max_trailer_t *)((vm_offset_t)kmsg->ikm_header +
+ round_msg(kmsg->ikm_header->msgh_size)),
+ sizeof(mach_msg_max_trailer_t));
+ res = 1;
+
+ out:
+ imq_unlock(mq);
+ splx(s);
+ return res;
+}
+
+/*
+ * Routine: ipc_mqueue_set_peek
+ * Purpose:
+ * Peek at a message queue set to see if it has any ports
+ * with messages.
+ *
+ * Conditions:
+ * Locks may be held by callers, so this routine cannot block.
+ * Caller holds reference on the message queue.
+ */
+unsigned
+ipc_mqueue_set_peek(ipc_mqueue_t mq)
+{
+ wait_queue_link_t wql;
+ queue_t q;
+ spl_t s;
+ int res;
+
+ assert(imq_is_set(mq));
+
+ s = splsched();
+ imq_lock(mq);
+
+ /*
+ * peek at the contained port message queues, return as soon as
+ * we spot a message on one of the message queues linked on the
+ * prepost list. No need to lock each message queue, as only the
+ * head of each queue is checked. If a message wasn't there before
+ * we entered here, no need to find it (if we do, great).
+ */
+ res = 0;
+ q = &mq->imq_preposts;
+ queue_iterate(q, wql, wait_queue_link_t, wql_preposts) {
+ ipc_mqueue_t port_mq = (ipc_mqueue_t)wql->wql_queue;
+ ipc_kmsg_queue_t kmsgs = &port_mq->imq_messages;
+
+ if (ipc_kmsg_queue_first(kmsgs) != IKM_NULL) {
+ res = 1;
+ break;
+ }
+ }
+ imq_unlock(mq);
+ splx(s);
+ return res;
+}
+
+/*
+ * Routine: ipc_mqueue_set_gather_member_names
+ * Purpose:
+ * Iterate a message queue set to identify the member port
+ * names. Actual returned names is limited to maxnames entries,
+ * but we keep counting the actual number of members to let
+ * the caller decide to retry if necessary.
+ *
+ * Conditions:
+ * Locks may be held by callers, so this routine cannot block.
+ * Caller holds reference on the message queue.
+ */
+void
+ipc_mqueue_set_gather_member_names(
+ ipc_mqueue_t mq,
+ ipc_entry_num_t maxnames,
+ mach_port_name_t *names,
+ ipc_entry_num_t *actualp)
+{
+ wait_queue_link_t wql;
+ queue_t q;
+ spl_t s;
+ ipc_entry_num_t actual = 0;
+
+ assert(imq_is_set(mq));
+
+ s = splsched();
+ imq_lock(mq);
+
+ /*
+ * Iterate over the member ports through the mqueue set links
+ * capturing as many names as we can.
+ */
+ q = &mq->imq_setlinks;
+ queue_iterate(q, wql, wait_queue_link_t, wql_setlinks) {
+ ipc_mqueue_t port_mq = (ipc_mqueue_t)wql->wql_queue;
+
+ if (actual < maxnames)
+ names[actual] = port_mq->imq_receiver_name;
+ actual++;
+ }
+ imq_unlock(mq);
+ splx(s);
+
+ *actualp = actual;
+}
+
+