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