5#ifndef _RTE_RCU_QSBR_H_
6#define _RTE_RCU_QSBR_H_
36#include <rte_compat.h>
42extern int rte_rcu_log_type;
44#if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
45#define __RTE_RCU_DP_LOG(level, fmt, args...) \
46 rte_log(RTE_LOG_ ## level, rte_rcu_log_type, \
47 "%s(): " fmt "\n", __func__, ## args)
49#define __RTE_RCU_DP_LOG(level, fmt, args...)
52#if defined(RTE_LIBRTE_RCU_DEBUG)
53#define __RTE_RCU_IS_LOCK_CNT_ZERO(v, thread_id, level, fmt, args...) do {\
54 if (v->qsbr_cnt[thread_id].lock_cnt) \
55 rte_log(RTE_LOG_ ## level, rte_rcu_log_type, \
56 "%s(): " fmt "\n", __func__, ## args); \
59#define __RTE_RCU_IS_LOCK_CNT_ZERO(v, thread_id, level, fmt, args...)
66#define __RTE_QSBR_THRID_ARRAY_ELM_SIZE (sizeof(uint64_t) * 8)
67#define __RTE_QSBR_THRID_ARRAY_SIZE(max_threads) \
68 RTE_ALIGN(RTE_ALIGN_MUL_CEIL(max_threads, \
69 __RTE_QSBR_THRID_ARRAY_ELM_SIZE) >> 3, RTE_CACHE_LINE_SIZE)
70#define __RTE_QSBR_THRID_ARRAY_ELM(v, i) ((uint64_t *) \
71 ((struct rte_rcu_qsbr_cnt *)(v + 1) + v->max_threads) + i)
72#define __RTE_QSBR_THRID_INDEX_SHIFT 6
73#define __RTE_QSBR_THRID_MASK 0x3f
74#define RTE_QSBR_THRID_INVALID 0xffffffff
77struct rte_rcu_qsbr_cnt {
88#define __RTE_QSBR_CNT_THR_OFFLINE 0
89#define __RTE_QSBR_CNT_INIT 1
90#define __RTE_QSBR_CNT_MAX ((uint64_t)~0)
91#define __RTE_QSBR_TOKEN_SIZE sizeof(uint64_t)
102 uint64_t acked_token;
109 uint32_t num_threads;
111 uint32_t max_threads;
137#define RTE_RCU_QSBR_DQ_NAMESIZE RTE_RING_NAMESIZE
147#define RTE_RCU_QSBR_DQ_MT_UNSAFE 1
191 struct rte_rcu_qsbr *
v;
200struct rte_rcu_qsbr_dq;
305 RTE_ASSERT(v != NULL && thread_id < v->max_threads);
307 __RTE_RCU_IS_LOCK_CNT_ZERO(v, thread_id, ERR,
"Lock counter %u",
308 v->qsbr_cnt[thread_id].lock_cnt);
315 t = __atomic_load_n(&v->token, __ATOMIC_RELAXED);
320 __atomic_store_n(&v->qsbr_cnt[thread_id].cnt,
321 t, __ATOMIC_RELAXED);
356 RTE_ASSERT(v != NULL && thread_id < v->max_threads);
358 __RTE_RCU_IS_LOCK_CNT_ZERO(v, thread_id, ERR,
"Lock counter %u",
359 v->qsbr_cnt[thread_id].lock_cnt);
366 __atomic_store_n(&v->qsbr_cnt[thread_id].cnt,
367 __RTE_QSBR_CNT_THR_OFFLINE, __ATOMIC_RELEASE);
394 RTE_ASSERT(v != NULL && thread_id < v->max_threads);
396#if defined(RTE_LIBRTE_RCU_DEBUG)
398 __atomic_fetch_add(&v->qsbr_cnt[thread_id].lock_cnt,
399 1, __ATOMIC_ACQUIRE);
427 RTE_ASSERT(v != NULL && thread_id < v->max_threads);
429#if defined(RTE_LIBRTE_RCU_DEBUG)
431 __atomic_fetch_sub(&v->qsbr_cnt[thread_id].lock_cnt,
432 1, __ATOMIC_RELEASE);
434 __RTE_RCU_IS_LOCK_CNT_ZERO(v, thread_id, WARNING,
435 "Lock counter %u. Nested locks?",
436 v->qsbr_cnt[thread_id].lock_cnt);
458 RTE_ASSERT(v != NULL);
465 t = __atomic_add_fetch(&v->token, 1, __ATOMIC_RELEASE);
487 RTE_ASSERT(v != NULL && thread_id < v->max_threads);
489 __RTE_RCU_IS_LOCK_CNT_ZERO(v, thread_id, ERR,
"Lock counter %u",
490 v->qsbr_cnt[thread_id].lock_cnt);
497 t = __atomic_load_n(&v->token, __ATOMIC_ACQUIRE);
504 if (t != __atomic_load_n(&v->qsbr_cnt[thread_id].cnt, __ATOMIC_RELAXED))
505 __atomic_store_n(&v->qsbr_cnt[thread_id].cnt,
506 t, __ATOMIC_RELEASE);
508 __RTE_RCU_DP_LOG(DEBUG,
"%s: update: token = %" PRIu64
", Thread ID = %d",
509 __func__, t, thread_id);
516__rte_rcu_qsbr_check_selective(
struct rte_rcu_qsbr *v, uint64_t t,
bool wait)
521 uint64_t *reg_thread_id;
522 uint64_t acked_token = __RTE_QSBR_CNT_MAX;
524 for (i = 0, reg_thread_id = __RTE_QSBR_THRID_ARRAY_ELM(v, 0);
526 i++, reg_thread_id++) {
530 bmap = __atomic_load_n(reg_thread_id, __ATOMIC_ACQUIRE);
531 id = i << __RTE_QSBR_THRID_INDEX_SHIFT;
534 j = __builtin_ctzl(bmap);
535 __RTE_RCU_DP_LOG(DEBUG,
536 "%s: check: token = %" PRIu64
", wait = %d, Bit Map = 0x%" PRIx64
", Thread ID = %d",
537 __func__, t, wait, bmap,
id + j);
539 &v->qsbr_cnt[
id + j].cnt,
541 __RTE_RCU_DP_LOG(DEBUG,
542 "%s: status: token = %" PRIu64
", wait = %d, Thread QS cnt = %" PRIu64
", Thread ID = %d",
543 __func__, t, wait, c,
id+j);
549 __RTE_QSBR_CNT_THR_OFFLINE && c < t)) {
558 bmap = __atomic_load_n(reg_thread_id,
568 if (c != __RTE_QSBR_CNT_THR_OFFLINE && acked_token > c)
579 if (acked_token != __RTE_QSBR_CNT_MAX)
580 __atomic_store_n(&v->acked_token, acked_token,
590__rte_rcu_qsbr_check_all(
struct rte_rcu_qsbr *v, uint64_t t,
bool wait)
593 struct rte_rcu_qsbr_cnt *cnt;
595 uint64_t acked_token = __RTE_QSBR_CNT_MAX;
597 for (i = 0, cnt = v->qsbr_cnt; i < v->max_threads; i++, cnt++) {
598 __RTE_RCU_DP_LOG(DEBUG,
599 "%s: check: token = %" PRIu64
", wait = %d, Thread ID = %d",
600 __func__, t, wait, i);
602 c = __atomic_load_n(&cnt->cnt, __ATOMIC_ACQUIRE);
603 __RTE_RCU_DP_LOG(DEBUG,
604 "%s: status: token = %" PRIu64
", wait = %d, Thread QS cnt = %" PRIu64
", Thread ID = %d",
605 __func__, t, wait, c, i);
610 if (
likely(c == __RTE_QSBR_CNT_THR_OFFLINE || c >= t))
623 if (
likely(c != __RTE_QSBR_CNT_THR_OFFLINE && acked_token > c))
631 if (acked_token != __RTE_QSBR_CNT_MAX)
632 __atomic_store_n(&v->acked_token, acked_token,
672 RTE_ASSERT(v != NULL);
675 if (
likely(t <= v->acked_token)) {
676 __RTE_RCU_DP_LOG(DEBUG,
677 "%s: check: token = %" PRIu64
", wait = %d",
679 __RTE_RCU_DP_LOG(DEBUG,
680 "%s: status: least acked token = %" PRIu64,
681 __func__, v->acked_token);
685 if (
likely(v->num_threads == v->max_threads))
686 return __rte_rcu_qsbr_check_all(v, t, wait);
688 return __rte_rcu_qsbr_check_selective(v, t, wait);
747struct rte_rcu_qsbr_dq *
813 unsigned int *freed,
unsigned int *pending,
unsigned int *available);
static void rte_atomic_thread_fence(int memorder)
#define __rte_cache_aligned
#define __rte_always_inline
static void rte_pause(void)
static __rte_always_inline uint64_t rte_rcu_qsbr_start(struct rte_rcu_qsbr *v)
__rte_experimental struct rte_rcu_qsbr_dq * rte_rcu_qsbr_dq_create(const struct rte_rcu_qsbr_dq_parameters *params)
static __rte_always_inline void rte_rcu_qsbr_unlock(__rte_unused struct rte_rcu_qsbr *v, __rte_unused unsigned int thread_id)
int rte_rcu_qsbr_thread_register(struct rte_rcu_qsbr *v, unsigned int thread_id)
static __rte_always_inline void rte_rcu_qsbr_thread_online(struct rte_rcu_qsbr *v, unsigned int thread_id)
int rte_rcu_qsbr_thread_unregister(struct rte_rcu_qsbr *v, unsigned int thread_id)
static __rte_always_inline void rte_rcu_qsbr_lock(__rte_unused struct rte_rcu_qsbr *v, __rte_unused unsigned int thread_id)
__rte_experimental int rte_rcu_qsbr_dq_enqueue(struct rte_rcu_qsbr_dq *dq, void *e)
int rte_rcu_qsbr_init(struct rte_rcu_qsbr *v, uint32_t max_threads)
static __rte_always_inline void rte_rcu_qsbr_thread_offline(struct rte_rcu_qsbr *v, unsigned int thread_id)
__rte_experimental int rte_rcu_qsbr_dq_delete(struct rte_rcu_qsbr_dq *dq)
__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)
void(* rte_rcu_qsbr_free_resource_t)(void *p, void *e, unsigned int n)
void rte_rcu_qsbr_synchronize(struct rte_rcu_qsbr *v, unsigned int thread_id)
int rte_rcu_qsbr_dump(FILE *f, struct rte_rcu_qsbr *v)
static __rte_always_inline int rte_rcu_qsbr_check(struct rte_rcu_qsbr *v, uint64_t t, bool wait)
size_t rte_rcu_qsbr_get_memsize(uint32_t max_threads)
static __rte_always_inline void rte_rcu_qsbr_quiescent(struct rte_rcu_qsbr *v, unsigned int thread_id)
rte_rcu_qsbr_free_resource_t free_fn
uint32_t trigger_reclaim_limit
uint32_t max_reclaim_size