// // Created by xajhu on 2021/7/6 0006. // #include #include #include #include #include "hardware.h" #include "user_errno.h" #include "uthash/uthash.h" #include "misc.h" #include "config.h" #define CMD_MEMORY_INFO ("cat /proc/meminfo | awk \'{print $1\"|\"$2\"|\"$3}\'") #define M_SIZE (1024 * 1024) #define KEY_NAME (32) #define KEY_VALUE (32) #define VALUE_UNIT (8) typedef struct { char itemName[KEY_NAME]; char itemValue[KEY_VALUE]; char valUnit[VALUE_UNIT]; unsigned long timestamp; UT_hash_handle hh; } KERNEL_MEM_INFO, *PKERNEL_MEM_INFO; static uv_rwlock_t g_uvLock; static PKERNEL_MEM_INFO g_pMemInfo = NULL; static const char *g_memKeyName[] = {"MemTotal", "MemFree", "MemAvailable", "Buffers", "Cached"}; unsigned int get_sys_free_memory() { return uv_get_free_memory() / M_SIZE; } unsigned int get_sys_total_memory() { return uv_get_total_memory() / M_SIZE; } static int memory_info_refresh() { int errCode = ERR_SUCCESS; FILE *fp; char buf[MAX_PATH * 2]; fp = popen(CMD_MEMORY_INFO, "r"); if (fp == NULL) { return -ERR_OPEN_FILE; } while (fgets(buf, 1024, fp) != NULL) { int nItems; sds tmpStr = sdsnew(buf); sds *pToken = sdssplitlen(tmpStr, (int)sdslen(tmpStr), "|", 1, &nItems); if (nItems == 3) { PKERNEL_MEM_INFO pTmp = NULL; HASH_FIND_STR(g_pMemInfo, pToken[0], pTmp); if (pTmp) { uv_rwlock_wrlock(&g_uvLock); strcpy(pTmp->itemName, sdstrim(pToken[0], ": \n")); strcpy(pTmp->itemValue, sdstrim(pToken[1], " \n")); strcpy(pTmp->valUnit, sdstrim(pToken[2], " \n")); pTmp->timestamp = time(NULL); uv_rwlock_wrunlock(&g_uvLock); } else { pTmp = (PKERNEL_MEM_INFO)malloc(sizeof(KERNEL_MEM_INFO)); if (pTmp) { uv_rwlock_wrlock(&g_uvLock); strcpy(pTmp->itemName, sdstrim(pToken[0], ": \n")); strcpy(pTmp->itemValue, sdstrim(pToken[1], " \n")); strcpy(pTmp->valUnit, sdstrim(pToken[2], " \n")); pTmp->timestamp = time(NULL); HASH_ADD_STR(g_pMemInfo, itemName, pTmp); uv_rwlock_wrunlock(&g_uvLock); } else { errCode = -ERR_MALLOC_MEMORY; } } } sdsfreesplitres(pToken, nItems); sdsfree(tmpStr); } return errCode; } _Noreturn void memRefreshCb(void *UNUSED(pArg)) { do { unsigned int period = cfg_get_mem_refresh_period(); if (cfg_get_watch_memory()) { memory_info_refresh(); } if (period < REFRESH_MAX_PERIOD && period >= 1) { uv_sleep(1000 * period); } else { uv_sleep(1000); } } while (TRUE); } int memory_watch_init() { static uv_thread_t uvThread; uv_rwlock_init(&g_uvLock); if (memory_info_refresh() != ERR_SUCCESS) { return -ERR_SYS_DISK_GET_INFO; } uv_thread_create(&uvThread, memRefreshCb, NULL); return ERR_SUCCESS; } #define MEM_VALUE_SET(dst, src) \ do { \ if ((src) == NULL) \ continue; \ if ((src)->valUnit && strlen((src)->valUnit) > 0) { \ sprintf(dst, "%s %s", (src)->itemValue, (src)->valUnit); \ } else { \ sprintf(dst, "%s", (src)->itemValue); \ } \ } while (0) int get_memory_info(PMEMORY_INFO pInfo) { int i, n = ARRAY_SIZE(g_memKeyName); if (pInfo == NULL) { return -ERR_INPUT_PARAMS; } uv_rwlock_rdlock(&g_uvLock); for (i = 0; i < n; i++) { PKERNEL_MEM_INFO pTmp = NULL; HASH_FIND_STR(g_pMemInfo, g_memKeyName[i], pTmp); if (pTmp) { switch (i) { case 0: MEM_VALUE_SET(pInfo->totalMemSize, pTmp); break; case 1: MEM_VALUE_SET(pInfo->freeMemSize, pTmp); break; case 2: MEM_VALUE_SET(pInfo->availMemSize, pTmp); break; case 3: MEM_VALUE_SET(pInfo->bufferMemSize, pTmp); break; case 4: MEM_VALUE_SET(pInfo->cachedMemSize, pTmp); break; default: continue; } } } uv_rwlock_rdunlock(&g_uvLock); pInfo->timestamp = time(NULL); return ERR_SUCCESS; }