diff mbox

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

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

Commit Message

Bill Fischofer Aug. 9, 2015, 1:55 a.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 | 85 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)
diff mbox

Patch

diff --git a/platform/linux-generic/odp_queue.c b/platform/linux-generic/odp_queue.c
index 4d3c548..669b630 100644
--- a/platform/linux-generic/odp_queue.c
+++ b/platform/linux-generic/odp_queue.c
@@ -908,3 +908,88 @@  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;
+
+	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) {
+		buf_hdr->origin_qe = NULL;
+		if (!buf_hdr->flags.sustain)
+			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 (placeholder_buf == ODP_BUFFER_INVALID) {
+		UNLOCK(&origin_qe->s.lock);
+		return -1;
+	}
+
+	placeholder_buf_hdr = odp_buf_to_hdr(placeholder_buf);
+	reorder_buf = origin_qe->s.reorder_head;
+
+	if (!reorder_buf) {
+		placeholder_buf_hdr->next = NULL;
+		origin_qe->s.reorder_head = placeholder_buf_hdr;
+		origin_qe->s.reorder_tail = placeholder_buf_hdr;
+	} else {
+		reorder_prev = NULL;
+
+		while (buf_hdr->order > reorder_buf->order) {
+			reorder_prev = reorder_buf;
+			reorder_buf  = reorder_buf->next;
+			if (!reorder_buf)
+				break;
+		}
+
+		placeholder_buf_hdr->next = reorder_buf;
+		if (reorder_prev)
+			reorder_prev->next = placeholder_buf_hdr;
+		else
+			origin_qe->s.reorder_head = placeholder_buf_hdr;
+
+		if (!reorder_buf)
+			origin_qe->s.reorder_tail = placeholder_buf_hdr;
+	}
+
+	placeholder_buf_hdr->target_qe = NULL;
+
+	UNLOCK(&origin_qe->s.lock);
+	return 0;
+}