/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright (c) 2018 Arm Limited
+ * Copyright (c) 2018-2020 Arm Limited
*/
#ifndef _RTE_RCU_QSBR_H_
/**
* @file
- * RTE Quiescent State Based Reclamation (QSBR)
+ *
+ * RTE Quiescent State Based Reclamation (QSBR).
+ *
+ * @warning
+ * @b EXPERIMENTAL:
+ * All functions in this file may be changed or removed without prior notice.
*
* Quiescent State (QS) is any point in the thread execution
* where the thread does not hold a reference to a data structure
#include <rte_lcore.h>
#include <rte_debug.h>
#include <rte_atomic.h>
+#include <rte_ring.h>
extern int rte_rcu_log_type;
#define __RTE_QSBR_CNT_THR_OFFLINE 0
#define __RTE_QSBR_CNT_INIT 1
#define __RTE_QSBR_CNT_MAX ((uint64_t)~0)
+#define __RTE_QSBR_TOKEN_SIZE sizeof(uint64_t)
/* RTE Quiescent State variable structure.
* This structure has two elements that vary in size based on the
*/
} __rte_cache_aligned;
+/**
+ * Call back function called to free the resources.
+ *
+ * @param p
+ * Pointer provided while creating the defer queue
+ * @param e
+ * Pointer to the resource data stored on the defer queue
+ * @param n
+ * Number of resources to free. Currently, this is set to 1.
+ *
+ * @return
+ * None
+ */
+typedef void (*rte_rcu_qsbr_free_resource_t)(void *p, void *e, unsigned int n);
+
+#define RTE_RCU_QSBR_DQ_NAMESIZE RTE_RING_NAMESIZE
+
+/**
+ * Various flags supported.
+ */
+/**< Enqueue and reclaim operations are multi-thread safe by default.
+ * The call back functions registered to free the resources are
+ * assumed to be multi-thread safe.
+ * Set this flag if multi-thread safety is not required.
+ */
+#define RTE_RCU_QSBR_DQ_MT_UNSAFE 1
+
+/**
+ * Parameters used when creating the defer queue.
+ */
+struct rte_rcu_qsbr_dq_parameters {
+ const char *name;
+ /**< Name of the queue. */
+ uint32_t flags;
+ /**< Flags to control API behaviors */
+ uint32_t size;
+ /**< Number of entries in queue. Typically, this will be
+ * the same as the maximum number of entries supported in the
+ * lock free data structure.
+ * Data structures with unbounded number of entries is not
+ * supported currently.
+ */
+ uint32_t esize;
+ /**< Size (in bytes) of each element in the defer queue.
+ * This has to be multiple of 4B.
+ */
+ uint32_t trigger_reclaim_limit;
+ /**< Trigger automatic reclamation after the defer queue
+ * has at least these many resources waiting. This auto
+ * reclamation is triggered in rte_rcu_qsbr_dq_enqueue API
+ * call.
+ * If this is greater than 'size', auto reclamation is
+ * not triggered.
+ * If this is set to 0, auto reclamation is triggered
+ * in every call to rte_rcu_qsbr_dq_enqueue API.
+ */
+ uint32_t max_reclaim_size;
+ /**< When automatic reclamation is enabled, reclaim at the max
+ * these many resources. This should contain a valid value, if
+ * auto reclamation is on. Setting this to 'size' or greater will
+ * reclaim all possible resources currently on the defer queue.
+ */
+ rte_rcu_qsbr_free_resource_t free_fn;
+ /**< Function to call to free the resource. */
+ void *p;
+ /**< Pointer passed to the free function. Typically, this is the
+ * pointer to the data structure to which the resource to free
+ * belongs. This can be NULL.
+ */
+ struct rte_rcu_qsbr *v;
+ /**< RCU QSBR variable to use for this defer queue */
+};
+
+/* RTE defer queue structure.
+ * This structure holds the defer queue. The defer queue is used to
+ * hold the deleted entries from the data structure that are not
+ * yet freed.
+ */
+struct rte_rcu_qsbr_dq;
+
/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice
RTE_ASSERT(v != NULL);
/* Check if all the readers have already acknowledged this token */
- if (likely(t <= v->acked_token))
+ if (likely(t <= v->acked_token)) {
+ __RTE_RCU_DP_LOG(DEBUG,
+ "%s: check: token = %"PRIu64", wait = %d",
+ __func__, t, wait);
+ __RTE_RCU_DP_LOG(DEBUG,
+ "%s: status: least acked token = %"PRIu64"",
+ __func__, v->acked_token);
return 1;
+ }
if (likely(v->num_threads == v->max_threads))
return __rte_rcu_qsbr_check_all(v, t, wait);
int
rte_rcu_qsbr_dump(FILE *f, struct rte_rcu_qsbr *v);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create a queue used to store the data structure elements that can
+ * be freed later. This queue is referred to as 'defer queue'.
+ *
+ * @param params
+ * Parameters to create a defer queue.
+ * @return
+ * On success - Valid pointer to defer queue
+ * On error - NULL
+ * Possible rte_errno codes are:
+ * - EINVAL - NULL parameters are passed
+ * - ENOMEM - Not enough memory
+ */
+__rte_experimental
+struct rte_rcu_qsbr_dq *
+rte_rcu_qsbr_dq_create(const struct rte_rcu_qsbr_dq_parameters *params);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Enqueue one resource to the defer queue and start the grace period.
+ * The resource will be freed later after at least one grace period
+ * is over.
+ *
+ * If the defer queue is full, it will attempt to reclaim resources.
+ * It will also reclaim resources at regular intervals to avoid
+ * the defer queue from growing too big.
+ *
+ * Multi-thread safety is provided as the defer queue configuration.
+ * When multi-thread safety is requested, it is possible that the
+ * resources are not stored in their order of deletion. This results
+ * in resources being held in the defer queue longer than they should.
+ *
+ * @param dq
+ * Defer queue to allocate an entry from.
+ * @param e
+ * Pointer to resource data to copy to the defer queue. The size of
+ * the data to copy is equal to the element size provided when the
+ * defer queue was created.
+ * @return
+ * On success - 0
+ * On error - 1 with rte_errno set to
+ * - EINVAL - NULL parameters are passed
+ * - ENOSPC - Defer queue is full. This condition can not happen
+ * if the defer queue size is equal (or larger) than the
+ * number of elements in the data structure.
+ */
+__rte_experimental
+int
+rte_rcu_qsbr_dq_enqueue(struct rte_rcu_qsbr_dq *dq, void *e);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Free resources from the defer queue.
+ *
+ * This API is multi-thread safe.
+ *
+ * @param dq
+ * Defer queue to free an entry from.
+ * @param n
+ * Maximum number of resources to free.
+ * @param freed
+ * Number of resources that were freed.
+ * @param pending
+ * Number of resources pending on the defer queue. This number might not
+ * be accurate if multi-thread safety is configured.
+ * @param available
+ * Number of resources that can be added to the defer queue.
+ * This number might not be accurate if multi-thread safety is configured.
+ * @return
+ * On successful reclamation of at least 1 resource - 0
+ * On error - 1 with rte_errno set to
+ * - EINVAL - NULL parameters are passed
+ */
+__rte_experimental
+int
+rte_rcu_qsbr_dq_reclaim(struct rte_rcu_qsbr_dq *dq, unsigned int n,
+ unsigned int *freed, unsigned int *pending, unsigned int *available);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Delete a defer queue.
+ *
+ * It tries to reclaim all the resources on the defer queue.
+ * If any of the resources have not completed the grace period
+ * the reclamation stops and returns immediately. The rest of
+ * the resources are not reclaimed and the defer queue is not
+ * freed.
+ *
+ * @param dq
+ * Defer queue to delete.
+ * @return
+ * On success - 0
+ * On error - 1
+ * Possible rte_errno codes are:
+ * - EAGAIN - Some of the resources have not completed at least 1 grace
+ * period, try again.
+ */
+__rte_experimental
+int
+rte_rcu_qsbr_dq_delete(struct rte_rcu_qsbr_dq *dq);
+
#ifdef __cplusplus
}
#endif