diff mbox

[API-NEXT,PATCHv12,11/13] linux-generic: schedule: implement odp_schedule_release_ordered()

Message ID 1439126035-13656-12-git-send-email-bill.fischofer@linaro.org
State New
Headers show

Commit Message

Bill Fischofer Aug. 9, 2015, 1:13 p.m. UTC
Permit events to be removed from an ordered flow.

Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>
---
 platform/linux-generic/odp_queue.c | 72 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)
diff mbox

Patch

diff --git a/platform/linux-generic/odp_queue.c b/platform/linux-generic/odp_queue.c
index 4d3c548..75cc95b 100644
--- a/platform/linux-generic/odp_queue.c
+++ b/platform/linux-generic/odp_queue.c
@@ -908,3 +908,75 @@  void odp_queue_param_init(odp_queue_param_t *params)
 {
 	memset(params, 0, sizeof(odp_queue_param_t));
 }
+
+/* These routines exists here rather than in odp_schedule
+ * because they operate on queue interenal structures
+ */
+int odp_schedule_release_ordered(odp_event_t ev)
+{
+	odp_buffer_t placeholder_buf;
+	odp_buffer_hdr_t *placeholder_buf_hdr, *reorder_buf, *reorder_prev;
+	odp_buffer_hdr_t *buf_hdr =
+		odp_buf_to_hdr(odp_buffer_from_event(ev));
+	queue_entry_t *origin_qe = buf_hdr->origin_qe;
+
+	/* Can't release if we didn't originate from an ordered queue */
+	if (!origin_qe)
+		return -1;
+
+	/* Buffer is no longer associated with an ordered queue */
+	buf_hdr->origin_qe = NULL;
+
+	/* Sustaining buffers can be released without further action */
+	if (buf_hdr->flags.sustain)
+		return 0;
+
+	/* Must lock the origin queue to process the release */
+	LOCK(&origin_qe->s.lock);
+
+	/* If we are the first or second element in the current order,
+	 * we can release immediately since there can be no confusion about
+	 * intermediate elements
+	 */
+	if (buf_hdr->order <= origin_qe->s.order_out + 1) {
+		order_release(origin_qe, 1);
+
+		/* check if this release allows us to unblock waiters */
+		reorder_buf = origin_qe->s.reorder_head;
+		if (reorder_buf &&
+		    reorder_buf->order <= origin_qe->s.order_out)
+			origin_qe->s.reorder_head = reorder_buf->next;
+		else
+			reorder_buf = NULL;
+		UNLOCK(&origin_qe->s.lock);
+		if (reorder_buf)
+			odp_queue_enq(reorder_buf->target_qe->s.handle,
+				      (odp_event_t)reorder_buf->handle.handle);
+		return 0;
+	}
+
+	/* If we are beyond the second element in the expected order, we need
+	 * a placeholder to represent our "place in line". Just use an element
+	 * from the same pool the buffer being released is from.
+	 */
+	placeholder_buf = odp_buffer_alloc(buf_hdr->pool_hdl);
+
+	/* Can't release if no placeholder is available */
+	if (odp_unlikely(placeholder_buf == ODP_BUFFER_INVALID)) {
+		UNLOCK(&origin_qe->s.lock);
+		buf_hdr->origin_qe = origin_qe;
+		return -1;
+	}
+
+	placeholder_buf_hdr = odp_buf_to_hdr(placeholder_buf);
+
+	/* Copy info to placeholder and add it to the reorder queue */
+	placeholder_buf_hdr->origin_qe     = origin_qe;
+	placeholder_buf_hdr->order         = buf_hdr->order;
+	placeholder_buf_hdr->flags.sustain = 0;
+
+	reorder_enq(NULL, origin_qe, placeholder_buf_hdr);
+
+	UNLOCK(&origin_qe->s.lock);
+	return 0;
+}