From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 0D9B541C3C; Wed, 8 Feb 2023 09:31:26 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id DF53A42D16; Wed, 8 Feb 2023 09:31:01 +0100 (CET) Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by mails.dpdk.org (Postfix) with ESMTP id 009E7410EE for ; Wed, 8 Feb 2023 09:30:55 +0100 (CET) Received: from dggpeml500024.china.huawei.com (unknown [172.30.72.56]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4PBY7X24fczJsGX; Wed, 8 Feb 2023 16:29:12 +0800 (CST) Received: from localhost.localdomain (10.50.163.32) by dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.34; Wed, 8 Feb 2023 16:30:53 +0800 From: Chengwen Feng To: , , , , , CC: , Subject: [PATCH v13 3/6] memarea: support alloc and free API Date: Wed, 8 Feb 2023 08:24:49 +0000 Message-ID: <20230208082452.43883-4-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230208082452.43883-1-fengchengwen@huawei.com> References: <20220721044648.6817-1-fengchengwen@huawei.com> <20230208082452.43883-1-fengchengwen@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit X-Originating-IP: [10.50.163.32] X-ClientProxiedBy: dggems701-chm.china.huawei.com (10.3.19.178) To dggpeml500024.china.huawei.com (7.185.36.10) X-CFilter-Loop: Reflected X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org This patch supports rte_memarea_alloc() and rte_memarea_free() API. Signed-off-by: Chengwen Feng Reviewed-by: Dongdong Liu Acked-by: Morten Brørup --- doc/guides/prog_guide/memarea_lib.rst | 6 + lib/memarea/rte_memarea.c | 180 ++++++++++++++++++++++++++ lib/memarea/rte_memarea.h | 42 ++++++ lib/memarea/version.map | 2 + 4 files changed, 230 insertions(+) diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst index 3630328642..55ca4b1166 100644 --- a/doc/guides/prog_guide/memarea_lib.rst +++ b/doc/guides/prog_guide/memarea_lib.rst @@ -31,6 +31,12 @@ returns the pointer to the created memarea or ``NULL`` if the creation failed. The ``rte_memarea_destroy()`` function is used to destroy a memarea. +The ``rte_memarea_alloc()`` function is used to alloc one memory object from +the memarea. + +The ``rte_memarea_free()`` function is used to free one memory object which +allocated by ``rte_memarea_alloc()``. + Debug Mode ---------- diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c index 523f34eb41..158e24b7f3 100644 --- a/lib/memarea/rte_memarea.c +++ b/lib/memarea/rte_memarea.c @@ -2,8 +2,10 @@ * Copyright(c) 2023 HiSilicon Limited */ +#include #include #include +#include #include #include @@ -88,6 +90,8 @@ memarea_alloc_area(const struct rte_memarea_param *init) init->numa_socket); else if (init->source == RTE_MEMAREA_SOURCE_LIBC) ptr = memarea_alloc_from_libc(init->total_sz); + else if (init->source == RTE_MEMAREA_SOURCE_MEMAREA) + ptr = rte_memarea_alloc(init->src_ma, init->total_sz); return ptr; } @@ -99,6 +103,8 @@ memarea_free_area(const struct rte_memarea_param *init, void *ptr) rte_free(ptr); else if (init->source == RTE_MEMAREA_SOURCE_LIBC) free(ptr); + else if (init->source == RTE_MEMAREA_SOURCE_MEMAREA) + rte_memarea_free(init->src_ma, ptr); } struct rte_memarea * @@ -169,3 +175,177 @@ rte_memarea_destroy(struct rte_memarea *ma) rte_free(ma); } +static inline void +memarea_lock(struct rte_memarea *ma) +{ + if (ma->init.mt_safe) + rte_spinlock_lock(&ma->lock); +} + +static inline void +memarea_unlock(struct rte_memarea *ma) +{ + if (ma->init.mt_safe) + rte_spinlock_unlock(&ma->lock); +} + +/** + * Check cookie or panic. + * + * @param status + * - 0: object is supposed to be available + * - 1: object is supposed to be allocated + * - 2: just check that cookie is valid (available or allocated) + */ +static inline void +memarea_check_cookie(const struct rte_memarea *ma, const struct memarea_objhdr *hdr, int status) +{ +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + static const char *const str[] = { " PASS", " FAILED" }; + struct memarea_objtlr *tlr; + bool hdr_fail, tlr_fail; + + if (unlikely(hdr == ma->guard_hdr)) + return; + + tlr = RTE_PTR_SUB(TAILQ_NEXT(hdr, obj_next), sizeof(struct memarea_objtlr)); + hdr_fail = (status == 0 && hdr->cookie != MEMAREA_OBJECT_HEADER_AVAILABLE_COOKIE) || + (status == 1 && hdr->cookie != MEMAREA_OBJECT_HEADER_ALLOCATED_COOKIE) || + (status == 2 && (hdr->cookie != MEMAREA_OBJECT_HEADER_AVAILABLE_COOKIE && + hdr->cookie != MEMAREA_OBJECT_HEADER_ALLOCATED_COOKIE)); + tlr_fail = (tlr->cookie != MEMAREA_OBJECT_TRAILER_COOKIE); + if (!hdr_fail && !tlr_fail) + return; + + rte_panic("MEMAREA: %s check cookies failed! addr-%p header-cookie<0x%" PRIx64 "%s> trailer-cookie<0x%" PRIx64 "%s>\n", + ma->init.name, RTE_PTR_ADD(hdr, sizeof(struct memarea_objhdr)), + hdr->cookie, str[hdr_fail], tlr->cookie, str[tlr_fail]); +#else + RTE_SET_USED(ma); + RTE_SET_USED(hdr); + RTE_SET_USED(status); +#endif +} + +static inline bool +memarea_whether_add_node(size_t avail_sz, size_t alloc_sz) +{ + return (avail_sz - alloc_sz) > (sizeof(struct memarea_objhdr) + + MEMAREA_OBJECT_SIZE_ALIGN +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + + sizeof(struct memarea_objtlr) + +#endif + ); +} + +static inline void +memarea_add_node(struct rte_memarea *ma, struct memarea_objhdr *hdr, size_t alloc_sz) +{ +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + struct memarea_objtlr *cur_tlr; +#endif + struct memarea_objhdr *new_hdr; + +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + cur_tlr = RTE_PTR_ADD(hdr, sizeof(struct memarea_objhdr) + alloc_sz); + cur_tlr->cookie = MEMAREA_OBJECT_TRAILER_COOKIE; + new_hdr = RTE_PTR_ADD(cur_tlr, sizeof(struct memarea_objtlr)); + new_hdr->cookie = MEMAREA_OBJECT_HEADER_AVAILABLE_COOKIE; +#else + new_hdr = RTE_PTR_ADD(hdr, sizeof(struct memarea_objhdr) + alloc_sz); +#endif + TAILQ_INSERT_AFTER(&ma->obj_list, hdr, new_hdr, obj_next); + TAILQ_INSERT_AFTER(&ma->avail_list, hdr, new_hdr, avail_next); +} + +void * +rte_memarea_alloc(struct rte_memarea *ma, size_t size) +{ + size_t align_sz = RTE_ALIGN(size, MEMAREA_OBJECT_SIZE_ALIGN); + struct memarea_objhdr *hdr; + size_t avail_sz; + void *ptr = NULL; + + if (unlikely(ma == NULL || size == 0 || align_sz < size)) + return ptr; + + memarea_lock(ma); + TAILQ_FOREACH(hdr, &ma->avail_list, avail_next) { + memarea_check_cookie(ma, hdr, 0); + avail_sz = MEMAREA_OBJECT_GET_SIZE(hdr); + if (avail_sz < align_sz) + continue; + if (memarea_whether_add_node(avail_sz, align_sz)) + memarea_add_node(ma, hdr, align_sz); + TAILQ_REMOVE(&ma->avail_list, hdr, avail_next); + MEMAREA_OBJECT_MARK_ALLOCATED(hdr); +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + hdr->cookie = MEMAREA_OBJECT_HEADER_ALLOCATED_COOKIE; +#endif + ptr = RTE_PTR_ADD(hdr, sizeof(struct memarea_objhdr)); + break; + } + memarea_unlock(ma); + + return ptr; +} + +static inline void +memarea_merge_node(struct rte_memarea *ma, struct memarea_objhdr *curr, + struct memarea_objhdr *next) +{ +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + struct memarea_objtlr *tlr; +#endif + RTE_SET_USED(curr); + TAILQ_REMOVE(&ma->obj_list, next, obj_next); + TAILQ_REMOVE(&ma->avail_list, next, avail_next); +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + next->cookie = 0; + tlr = RTE_PTR_SUB(next, sizeof(struct memarea_objtlr)); + tlr->cookie = 0; +#endif +} + +void +rte_memarea_free(struct rte_memarea *ma, void *ptr) +{ + struct memarea_objhdr *hdr, *prev, *next; + + if (unlikely(ma == NULL || ptr == NULL)) + return; + + hdr = RTE_PTR_SUB(ptr, sizeof(struct memarea_objhdr)); + if (unlikely(!MEMAREA_OBJECT_IS_ALLOCATED(hdr))) { + RTE_MEMAREA_LOG(ERR, "detect invalid object when free!"); + return; + } + memarea_check_cookie(ma, hdr, 1); + + memarea_lock(ma); + + /** 1st: add to avail list. */ +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + hdr->cookie = MEMAREA_OBJECT_HEADER_AVAILABLE_COOKIE; +#endif + TAILQ_INSERT_HEAD(&ma->avail_list, hdr, avail_next); + + /** 2nd: merge if previous object is avail. */ + prev = TAILQ_PREV(hdr, memarea_objhdr_list, obj_next); + if (prev != NULL && !MEMAREA_OBJECT_IS_ALLOCATED(prev)) { + memarea_check_cookie(ma, prev, 0); + memarea_merge_node(ma, prev, hdr); + hdr = prev; + } + + /** 3rd: merge if next object is avail. */ + next = TAILQ_NEXT(hdr, obj_next); + if (next != NULL && !MEMAREA_OBJECT_IS_ALLOCATED(next)) { + memarea_check_cookie(ma, next, 0); + memarea_merge_node(ma, hdr, next); + } + + memarea_unlock(ma); +} + diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h index 435dca293f..02b4825461 100644 --- a/lib/memarea/rte_memarea.h +++ b/lib/memarea/rte_memarea.h @@ -115,6 +115,48 @@ struct rte_memarea *rte_memarea_create(const struct rte_memarea_param *init); __rte_experimental void rte_memarea_destroy(struct rte_memarea *ma); +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Allocate memory from memarea. + * + * Allocate one memory object from the memarea. + * + * @param ma + * The pointer of memarea. + * @param size + * The memory size to be allocated. + * + * @return + * - NULL on error. Not enough memory, or invalid arguments (ma is NULL, + * size is 0). + * - Otherwise, the pointer to the allocated object. + */ +__rte_experimental +void *rte_memarea_alloc(struct rte_memarea *ma, size_t size); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Free memory to memarea. + * + * Free one memory object to the memarea. + * @note The memory object must have been returned by a previous call to + * rte_memarea_alloc(), it must be freed to the same memarea which previous + * allocated from. The behaviour of rte_memarea_free() is undefined if the + * memarea or pointer does not match these requirements. + * + * @param ma + * The pointer of memarea. If the ma is NULL, the function does nothing. + * @param ptr + * The pointer of memory object which need be freed. If the pointer is NULL, + * the function does nothing. + */ +__rte_experimental +void rte_memarea_free(struct rte_memarea *ma, void *ptr); + #ifdef __cplusplus } #endif diff --git a/lib/memarea/version.map b/lib/memarea/version.map index f36a04d7cf..effbd0b488 100644 --- a/lib/memarea/version.map +++ b/lib/memarea/version.map @@ -1,8 +1,10 @@ EXPERIMENTAL { global: + rte_memarea_alloc; rte_memarea_create; rte_memarea_destroy; + rte_memarea_free; local: *; }; -- 2.17.1