* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#define _GNU_SOURCE
#include <sched.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include <semaphore.h>
#include "ascend_hal_define.h"
#include "drv_user_common.h"
#include "drv_buff_common.h"
#include "drv_buff_adp.h"
#include "drv_usr_buff_mempool.h"
#include "drv_buff_common_mempool.h"
#include "drv_buff_memzone.h"
#include "drv_buff_mbuf.h"
#include "bitmap.h"
#include "buff_range.h"
#include "buff_manage_base.h"
#include "buff_recycle_ctx.h"
#include "buff_recycle.h"
#define ATOMIC_SET(x, y) __sync_lock_test_and_set((x), (y))
typedef void (*block_handle)(struct proc_mng_ctx *p_mng, struct block_mem_ctx *block);
typedef void (*block_handle_with_rec_type)(struct block_mem_ctx *block,
enum buff_recycle_type recycle_type);
#ifdef EMU_ST
void buff_restore_proc_para(int pid, int task_id);
#endif
static void block_handle_mov_to_alloc_list(struct proc_mng_ctx *p_mng, struct block_mem_ctx *block)
{
drv_user_list_del(&block->node);
drv_user_list_add_head(&block->node, &p_mng->alloc_list[block->type]);
}
static void block_handle_idle_free(struct proc_mng_ctx *p_mng, struct block_mem_ctx *block)
{
if (block->valid == 0) {
buff_debug("block %p free\n", block->mng);
drv_user_list_del(&block->node);
free(block);
buff_api_atomic_dec(&p_mng->free_num);
}
}
static void mbuf_recycle(struct proc_mng_ctx *p_mng, struct mempool_t *mp,
struct share_mbuf *s_mbuf, struct uni_buff_head_t *head)
{
struct uni_buff_ext_info *ext = (struct uni_buff_ext_info *)((char *)head - sizeof(struct uni_buff_ext_info));
unsigned long long proc_uid;
proc_uid = ext->process_uni_id;
if (p_mng->exit_task_id != proc_uid) {
return;
}
if (ext->use_pid == getpid()) {
return;
}
buff_event("Mbuf recycle. (pid=%d, mbuf=%p, alloc_pid=%d, use_pid=%d, proc_uid=%llu)\n",
buff_get_current_pid(), s_mbuf, ext->alloc_pid, ext->use_pid, proc_uid);
(void)s_mbuf_free((void *)mp, s_mbuf);
}
static void block_handle_mbuf_mp_recycle(struct proc_mng_ctx *p_mng, struct block_mem_ctx *block)
{
struct mempool_t *mp = (struct mempool_t *)block->mng;
struct uni_buff_head_t *head = NULL;
void *buff = NULL;
unsigned long i;
if (block->status == 0) {
return;
}
for (i = 0; i < mp->bit_num; i++) {
i = bitmap_find_next_bit(mp->bitmap, mp->bit_num, i);
if (i >= mp->blk_num) {
break;
}
buff = mp_get_buff_uva_by_index(mp, i);
head = buff_mempool_get_head(buff);
if (head->status == UNI_STATUS_ALLOC) {
if ((head->buff_type == MBUF_BY_POOL) || (head->buff_type == MBUF_NORMAL) ||
(head->buff_type == MBUF_BARE_BUFF) || (head->buff_type == MBUF_BY_BUILD)) {
mbuf_recycle(p_mng, mp, (struct share_mbuf *)buff, head);
}
}
}
}
static void mp_scan_recycle_one_buff(struct proc_mng_ctx * p_mng, void *buff, uint32_t blk_id)
{
struct uni_buff_head_t *head = NULL;
struct uni_buff_trace_t *trace = NULL;
int i;
head = buff_mempool_get_head(buff);
trace = buff_mempool_get_trace(buff);
for (i = 0; i < BUFF_REF_MAX_MBUF_NUM ; i++) {
if (trace->mbuf[i] == NULL) {
continue;
}
if ((uint32)p_mng->exit_task_id != trace->alloc_uid[i]) {
continue;
}
if ((uint32)p_mng->exit_task_id != trace->proc_uid[i]) {
continue;
}
(void)ATOMIC_SET(&(trace->mbuf[i]), NULL);
(void)buff_free(blk_id, buff, head);
}
}
static void mp_scan_recycle_buff(struct proc_mng_ctx *p_mng, struct mempool_t *mp)
{
void *buff = NULL;
unsigned long i;
for (i = 0; i < mp->bit_num; i++) {
i = bitmap_find_next_bit(mp->bitmap, mp->bit_num, i);
if (i >= mp->blk_num) {
break;
}
buff = mp_get_buff_uva_by_index(mp, i);
mp_scan_recycle_one_buff(p_mng, buff, mp->blk_id);
}
}
static void block_handle_mp_recycle(struct proc_mng_ctx *p_mng, struct block_mem_ctx *block)
{
struct mempool_t *mp = (struct mempool_t *)block->mng;
(void)pthread_mutex_lock(&block->mutex);
if (block->status == 1) {
mp_scan_recycle_buff(p_mng, mp);
}
(void)pthread_mutex_unlock(&block->mutex);
}
static void block_handle_mp_scan_free(struct block_mem_ctx *block,
enum buff_recycle_type recycle_type)
{
struct mempool_t *mp = (struct mempool_t *)block->mng;
bool recycle_flag = false;
(void)pthread_mutex_lock(&block->mutex);
if (block->status == 1) {
mp_scan_free_all_buff(mp);
if (block->type == MEMPOOL_MBUF_LIST) {
recycle_flag = true;
}
}
(void)pthread_mutex_unlock(&block->mutex);
if ((recycle_type == ACTIVE_RECYCLE) && (recycle_flag == true)) {
mp_destroy_mbuf_mp(mp);
}
}
static void block_handle_mz_scan_free(struct block_mem_ctx *block,
enum buff_recycle_type recycle_type)
{
struct buff_memzone_list_node *mz_list_node = NULL;
struct memzone_user_mng_t *mz = NULL;
(void)pthread_mutex_lock(&block->mutex);
if (block->status == 1) {
mz = (struct memzone_user_mng_t *)block->mng;
mz_list_node = mz->mz_list_node;
(void)memzone_scan_free(mz);
}
(void)pthread_mutex_unlock(&block->mutex);
if (mz != NULL) {
if (recycle_type == ACTIVE_RECYCLE) {
memzone_scan_free_idle_pool(mz_list_node, mz);
}
}
}
static void block_handle_huge_buf_scan_free(struct block_mem_ctx *block,
enum buff_recycle_type recycle_type)
{
(void)recycle_type;
struct memzone_huge_user_mng_t *huge_mz = (struct memzone_huge_user_mng_t *)block->mng;
struct uni_buff_head_t *head = NULL;
int head_status = UNI_STATUS_IDLE;
(void)pthread_mutex_lock(&block->mutex);
if (block->status == 1) {
head = (struct uni_buff_head_t *)huge_mz->uni_head;
head_status = head->status;
}
(void)pthread_mutex_unlock(&block->mutex);
if (head_status == UNI_STATUS_RELEASE) {
huge_buff_scan_free(huge_mz, head + 1);
}
}
static void block_list_for_each_handle(struct proc_mng_ctx *p_mng, struct list_head *head, block_handle handle)
{
struct block_mem_ctx *block = NULL;
struct list_head *pos = NULL, *n = NULL;
list_for_each_safe(pos, n, head) {
block = list_entry(pos, struct block_mem_ctx, node);
handle(p_mng, block);
}
}
static void block_list_for_each_handle_with_devid(struct list_head *head,
block_handle_with_rec_type handle, uint32 devid, enum buff_recycle_type recycle_type)
{
struct block_mem_ctx *block = NULL;
struct list_head *pos = NULL, *n = NULL;
list_for_each_safe(pos, n, head) {
block = list_entry(pos, struct block_mem_ctx, node);
if ((devid != BUFF_INVALID_DEV) && (devid != block->devid)) {
continue;
}
handle(block, recycle_type);
}
}
static void proc_block_check_free(struct proc_mng_ctx *p_mng)
{
int i;
if (buff_api_atomic_read(&p_mng->free_num) == 0) {
return;
}
for (i = 0; i < MEM_LIST_NUM; i++) {
block_list_for_each_handle(p_mng, &p_mng->alloc_list[i], block_handle_idle_free);
}
}
static void exit_task_recycle(struct proc_mng_ctx *p_mng)
{
do {
int ret = buff_pool_poll_exit_task(p_mng->pool_id, &p_mng->exit_task_id);
if (ret != DRV_ERROR_NONE) {
break;
}
block_list_for_each_handle(p_mng, &p_mng->alloc_list[MEMPOOL_MBUF_LIST], block_handle_mbuf_mp_recycle);
block_list_for_each_handle(p_mng, &p_mng->alloc_list[MEMPOOL_LIST], block_handle_mp_recycle);
} while (true);
}
static void recycle_proc_default_pool_res(struct proc_mng_ctx *p_mng, uint32_t devid, enum buff_recycle_type recycle_type)
{
#ifdef EMU_ST
buff_restore_proc_para(p_mng->pid, p_mng->task_id);
#endif
(void)pthread_mutex_lock(&p_mng->alloc_list_mutex);
(void)pthread_mutex_lock(&p_mng->alloc_tmp_list_mutex);
block_list_for_each_handle(p_mng, &p_mng->alloc_list_tmp, block_handle_mov_to_alloc_list);
(void)pthread_mutex_unlock(&p_mng->alloc_tmp_list_mutex);
proc_block_check_free(p_mng);
exit_task_recycle(p_mng);
block_list_for_each_handle_with_devid(&p_mng->alloc_list[MEMZONE_LIST], block_handle_mz_scan_free,
devid, recycle_type);
block_list_for_each_handle_with_devid(&p_mng->alloc_list[HUGE_BUF_LIST], block_handle_huge_buf_scan_free,
devid, recycle_type);
block_list_for_each_handle_with_devid(&p_mng->alloc_list[MEMPOOL_LIST], block_handle_mp_scan_free,
devid, recycle_type);
block_list_for_each_handle_with_devid(&p_mng->alloc_list[MEMPOOL_MBUF_LIST], block_handle_mp_scan_free,
devid, recycle_type);
(void)pthread_mutex_unlock(&p_mng->alloc_list_mutex);
}
#define USING_BUFF_MAX_SHOW_CNT 10
drvError_t buff_proc_cache_free(uint32_t devid)
{
struct buff_recycle_ctx_mng *ctx_mng = buff_get_recycle_ctx_mng();
struct buff_recycle_ctx *ctx = NULL;
struct list_head *pos = NULL, *n = NULL;
(void)pthread_rwlock_rdlock(&ctx_mng->rwlock);
list_for_each_safe(pos, n, &ctx_mng->head) {
ctx = container_of(pos, struct buff_recycle_ctx, node);
if (ctx->p_mng.pool_id >= 0) {
recycle_proc_default_pool_res(&ctx->p_mng, devid, ACTIVE_RECYCLE);
}
}
(void)pthread_rwlock_unlock(&ctx_mng->rwlock);
return idle_buff_range_free(devid, USING_BUFF_MAX_SHOW_CNT);
}
STATIC void thread_prop_set(void)
{
#ifndef DRV_HOST
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(0, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
buff_warn("sched_setaffinity not success\n");
}
#endif
(void)prctl(PR_SET_NAME, "buff_recycle");
}
#ifdef EMU_ST
static void free_one_buff(struct proc_mng_ctx *p_mng, struct block_mem_ctx *block)
{
if (block->status == 1) {
if (block->type == MEMZONE_LIST) {
memzone_delete(block->mng);
} else if (block->type == HUGE_BUF_LIST) {
struct memzone_huge_user_mng_t *huge_mz = (struct memzone_huge_user_mng_t *)block->mng;
void *buff = (struct uni_buff_head_t *)huge_mz->uni_head + 1;
(void)memzone_free_huge(huge_mz, buff);
} else {
struct buff_req_mp_destroy arg;
arg.mp = block->mng;
(void)buff_usr_mp_delete(&arg);
}
}
}
static void free_all_buff(struct proc_mng_ctx *p_mng)
{
int i;
block_list_for_each_handle(p_mng, &p_mng->alloc_list_tmp, block_handle_mov_to_alloc_list);
for (i = 0; i < MEM_LIST_NUM; i++) {
block_list_for_each_handle(p_mng, &p_mng->alloc_list[i], free_one_buff);
}
proc_block_check_free(p_mng);
}
void list_handle_of_recycle_ctx_destroy(struct list_head *node)
{
struct buff_recycle_ctx *ctx = container_of(node, struct buff_recycle_ctx, node);
buff_info("pid %d recycle thread stop thread status %d\n", buff_get_current_pid(), ctx->status);
if (ctx->p_mng.pool_id >= 0) {
recycle_proc_default_pool_res(&ctx->p_mng, BUFF_INVALID_DEV, PASSIVE_RECYCLE);
free_all_buff(&ctx->p_mng);
}
drv_user_list_del(&ctx->node);
free(ctx);
}
void recycle_thread_stop(void)
{
struct buff_recycle_ctx_mng *ctx_mng = buff_get_recycle_ctx_mng();
if (ctx_mng->ctx_num != 0) {
(void)pthread_rwlock_wrlock(&ctx_mng->rwlock);
drv_user_list_for_each(&ctx_mng->head, list_handle_of_recycle_ctx_destroy);
(void)pthread_rwlock_unlock(&ctx_mng->rwlock);
}
del_others_range();
}
#endif
void wake_up_recyle_thread(int pool_id)
{
struct buff_recycle_ctx *ctx = NULL;
ctx = buff_get_recycle_ctx(pool_id);
if (ctx == NULL) {
return;
}
if ((ctx->wait_flag == 1) && (ctx->wake_up_cnt == 0)) {
ctx->wake_up_cnt++;
}
}
static void *recycle_thread(void *arg)
{
#ifndef EMU_ST
struct buff_recycle_ctx *ctx = (struct buff_recycle_ctx *)arg;
thread_prop_set();
ctx->status = RECYCLE_THREAD_STATUS_RUN;
while (ctx->status == RECYCLE_THREAD_STATUS_RUN) {
if (ctx->p_mng.pool_id >= 0) {
recycle_proc_default_pool_res(&ctx->p_mng, BUFF_INVALID_DEV, PASSIVE_RECYCLE);
}
(void)idle_buff_range_free(BUFF_INVALID_DEV, 0);
(void)usleep(ctx->period);
}
ctx->status = RECYCLE_THREAD_STATUS_STOP;
#endif
return NULL;
}
static void recycle_thread_init(struct buff_recycle_ctx *ctx)
{
pthread_attr_t attr;
pthread_t thread;
int ret;
(void)pthread_attr_init(&attr);
(void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
ret = pthread_create(&thread, &attr, recycle_thread, (void *)ctx);
if (ret != 0) {
buff_err("Buff recycle thread create fail. (ret=%d)\n", ret);
} else {
ctx->thread = thread;
}
(void)pthread_attr_destroy(&attr);
}
static void mem_config_show(unsigned int cfg_id)
{
memZoneCfg *cfg_info = memzone_get_cfg_info_by_id(cfg_id);
buff_show("Mz cfg. (cfg_id=%d; total_size=0x%llx; blk_size=0x%x; max_buf_size=0x%llx; page_type=%d)\n",
cfg_info->cfg_id, cfg_info->total_size, cfg_info->blk_size, cfg_info->max_buf_size, cfg_info->page_type);
}
static void memzone_buff_show(struct memzone_user_mng_t *mz)
{
void *start = NULL, *end = NULL;
struct uni_buff_ext_info *ext_info = NULL;
struct uni_buff_head_t *head = NULL;
unsigned long i, size;
unsigned long j = 0;
(void)pthread_mutex_lock(&mz->mutex);
for (i = 0; i < mz->bitnum;) {
if ((mz->alloc_flag == 1) || (mz->free_flag == 1)) {
break;
}
i = bitmap_find_next_bit(mz->bitmap, mz->bitnum, i);
if (i >= mz->blk_num_total) {
break;
}
head = (struct uni_buff_head_t *)(uintptr_t)*memzone_get_buff_head_by_index(mz, (unsigned int)i);
if (head->status == UNI_STATUS_ALLOC) {
ext_info = buff_get_ext_info(head, mz->area.blk_id);
if (ext_info != NULL) {
j++;
buff_show("Buff. (index=%ld; ext=%p; alloc_pid=%d; use_pid=%d)\n", j, ext_info, ext_info->alloc_pid,
ext_info->use_pid);
buff_put_ext_info(ext_info, mz->area.blk_id);
}
}
start = (void *)((char *)head - (head->resv_head * UNI_RSV_HEAD_LEN));
end = (void *)((char *)head + head->size);
size = (unsigned long)end - (unsigned long)start;
if ((size < mz->blk_size) || (size > mz->area.mz_mem_total_size)) {
break;
}
i += size / mz->blk_size;
}
(void)pthread_mutex_unlock(&mz->mutex);
}
static void memzone_show(void *buff)
{
struct memzone_user_mng_t *mz = (struct memzone_user_mng_t *)buff;
buff_show("memzone %p: blk addr %p pid %d blk(size %d total num %d free %d), mem(total 0x%llx free 0x%llx)\n",
mz, mz->area.mz_mem_uva, mz->pid, mz->blk_size, mz->blk_num_total, mz->blk_num_available,
mz->area.mz_mem_total_size, mz->mz_mem_free_size);
mem_config_show(mz->cfg_id);
memzone_buff_show(mz);
}
static void mem_pool_buff_show(struct mempool_t *mp)
{
struct uni_buff_ext_info *ext_info = NULL;
struct uni_buff_head_t *head = NULL;
void *buff = NULL;
unsigned long i;
unsigned long j = 0;
for (i = 0; i < mp->bit_num; i++) {
i = bitmap_find_next_bit(mp->bitmap, mp->bit_num, i);
if (i >= mp->blk_num) {
break;
}
buff = mp_get_buff_uva_by_index(mp, i);
head = buff_mempool_get_head(buff);
if (head->status == UNI_STATUS_ALLOC) {
ext_info = buff_get_ext_info(head, mp->blk_id);
if (ext_info != NULL) {
j++;
buff_show("Buff. (index=%ld; ext=%p; alloc_pid=%d; use_pid=%d)\n", j, ext_info, ext_info->alloc_pid,
ext_info->use_pid);
buff_put_ext_info(ext_info, mp->blk_id);
}
}
}
}
static void mem_pool_show(void *buff)
{
struct mempool_t *mp = (struct mempool_t *)buff;
buff_show("mempool %p: blk addr %p name(%s) blk(size %d total num %d free %d), bit_num %d\n",
mp, mp->blk_start, mp->pool_name, mp->blk_size, mp->blk_num, mp->blk_available, mp->bit_num);
mem_pool_buff_show(mp);
}
static void large_buf_show(void *buff)
{
struct memzone_huge_user_mng_t *huge_mz = (struct memzone_huge_user_mng_t *)buff;
struct uni_buff_head_t *head = (struct uni_buff_head_t *)huge_mz->uni_head;
buff_show("Large. (buf=%p; size=0x%lx)\n", buff, (unsigned long)head->size);
}
static void (* const mem_show_handler[MEM_LIST_NUM])(void *buff) = {
[MEMZONE_LIST] = memzone_show,
[HUGE_BUF_LIST] = large_buf_show,
[MEMPOOL_LIST] = mem_pool_show,
[MEMPOOL_MBUF_LIST] = mem_pool_show
};
static void block_handle_show(struct proc_mng_ctx *p_mng, struct block_mem_ctx *block)
{
(void)p_mng;
buff_show("block type %d status %d mng %p\n", block->type, block->status, block->mng);
(void)pthread_mutex_lock(&block->mutex);
if (block->status == 1) {
mem_show_handler[block->type](block->mng);
}
(void)pthread_mutex_unlock(&block->mutex);
}
#ifndef EMU_ST
static void _pool_blk_show(struct proc_mng_ctx *p_mng)
{
int i;
buff_show("\n");
buff_show("pid %d, task uid %llu, pool_id %d block_num %u free_num %u. block info:\n",
p_mng->pid, p_mng->task_id, p_mng->pool_id, p_mng->block_num, p_mng->free_num);
buff_show("alloc tmp list:\n");
(void)pthread_mutex_lock(&p_mng->alloc_tmp_list_mutex);
block_list_for_each_handle(p_mng, &p_mng->alloc_list_tmp, block_handle_show);
(void)pthread_mutex_unlock(&p_mng->alloc_tmp_list_mutex);
buff_show("alloc list:\n");
(void)pthread_mutex_lock(&p_mng->alloc_list_mutex);
for (i = 0; i < MEM_LIST_NUM; i++) {
block_list_for_each_handle(p_mng, &p_mng->alloc_list[i], block_handle_show);
}
(void)pthread_mutex_unlock(&p_mng->alloc_list_mutex);
}
static void list_handle_of_pool_blk_show(struct list_head *node)
{
struct buff_recycle_ctx *ctx = container_of(node, struct buff_recycle_ctx, node);
if (ctx->p_mng.pool_id >= 0) {
_pool_blk_show(&ctx->p_mng);
}
}
#endif
static void pool_blk_show(void)
{
struct buff_recycle_ctx_mng *ctx_mng = buff_get_recycle_ctx_mng();
#ifndef EMU_ST
(void)pthread_rwlock_rdlock(&ctx_mng->rwlock);
drv_user_list_for_each(&ctx_mng->head, list_handle_of_pool_blk_show);
(void)pthread_rwlock_unlock(&ctx_mng->rwlock);
#endif
}
STATIC void sigal_proc(signed int signum)
{
#ifndef EMU_ST
buff_show("****************** signum %d proc %d start ***********************\n", signum, buff_get_current_pid());
buff_range_show();
pool_blk_show();
buff_show("****************** signum %d proc %d end ***********************\n", signum, buff_get_current_pid());
#endif
}
static void sigal_init(void)
{
struct sigaction act;
static THREAD bool is_inited = false;
if (is_inited == true) {
return;
}
act.sa_handler = sigal_proc;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaction(SIGUSR1, &act, NULL);
}
drvError_t proc_block_ctx_init(int pool_id, int type, void *mng, struct block_mem_ctx *block)
{
struct common_handle_t *head = (struct common_handle_t *)mng;
struct buff_recycle_ctx *ctx = NULL;
int ret;
ctx = buff_get_recycle_ctx(pool_id);
if (ctx == NULL) {
buff_err("buff_get_recycle_ctx failed\n");
return DRV_ERROR_NO_RESOURCES;
}
block->valid = 1;
block->type = type;
block->status = 1;
block->mng = mng;
block->devid = head->devid;
block->recycle_ctx = ctx;
ret = pthread_mutex_init(&block->mutex, NULL);
if (ret != 0) {
buff_err("pthread_mutex_init failed\n");
return DRV_ERROR_NO_RESOURCES;
}
return DRV_ERROR_NONE;
}
* ensure that the head->parent is assigned before the linked list is added.
* Otherwise, the head->parent may access invalid memory in concurrent scenarios.
*/
void proc_block_add(struct block_mem_ctx *block)
{
struct buff_recycle_ctx *ctx = block->recycle_ctx;
buff_api_atomic_inc(&ctx->p_mng.block_num);
(void)pthread_mutex_lock(&ctx->p_mng.alloc_tmp_list_mutex);
drv_user_list_add_head(&block->node, &ctx->p_mng.alloc_list_tmp);
(void)pthread_mutex_unlock(&ctx->p_mng.alloc_tmp_list_mutex);
}
void proc_block_del(void *blk)
{
struct block_mem_ctx *block = (struct block_mem_ctx *)blk;
struct buff_recycle_ctx *ctx = block->recycle_ctx;
block->valid = 0;
buff_api_atomic_dec(&ctx->p_mng.block_num);
buff_api_atomic_inc(&ctx->p_mng.free_num);
}
void proc_set_buff_invalid(void *blk)
{
struct block_mem_ctx *block = (struct block_mem_ctx *)blk;
(void)pthread_mutex_lock(&block->mutex);
block->status = 0;
(void)pthread_mutex_unlock(&block->mutex);
}
void buf_recycle_init(int pool_id)
{
struct buff_recycle_ctx *ctx = NULL;
drvError_t ret;
ret = buff_recycle_ctx_create(pool_id, &ctx);
if (ret != DRV_ERROR_NONE) {
return;
}
recycle_thread_init(ctx);
sigal_init();
}
static void list_handle_of_recycle_exit(struct list_head *node)
{
struct buff_recycle_ctx *ctx = container_of(node, struct buff_recycle_ctx, node);
if (ctx->thread != 0) {
ctx->status = RECYCLE_THREAD_STATUS_STOP;
(void)pthread_cancel(ctx->thread);
(void)pthread_join(ctx->thread, NULL);
ctx->thread = 0;
}
}
static void __attribute__((destructor)) buff_exit(void)
{
struct buff_recycle_ctx_mng *ctx_mng = buff_get_recycle_ctx_mng();
(void)pthread_rwlock_rdlock(&ctx_mng->rwlock);
drv_user_list_for_each(&ctx_mng->head, list_handle_of_recycle_exit);
(void)pthread_rwlock_unlock(&ctx_mng->rwlock);
}
drvError_t halBufferModeNotify(PSM_STATUS status, void *rsv)
{
(void)status;
(void)rsv;
return DRV_ERROR_NOT_SUPPORT;
}