@@ -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;
+}
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(+)