Import Upstream version 1.1.1kylin1

This commit is contained in:
谢炜 2022-06-10 19:38:18 +08:00
commit 2c07017a35
78 changed files with 10016 additions and 0 deletions

35
CMakeLists.txt Normal file
View File

@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.1.3)
project(kysdk-base)
include(CMakePackageConfigHelpers)
include_directories("${PROJECT_BINARY_DIR}")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
set (CMAKE_EXPORT_COMPILE_COMMANDS ON)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
if (${CMAKE_BUILD_TYPE} STREQUAL "Release")
add_definitions(-Drelease)
set(CMAKE_C_FLAGS "$ENV{CFLAGS} -O1 -Wall")
set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} -O1 -Wall")
elseif(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_C_FLAGS "$ENV{CFLAGS} -g -O0 -Wall")
set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} -g -O0 -Wall")
endif()
message("Build Type: ${CMAKE_BUILD_TYPE}")
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set (CMAKE_INSTALL_PREFIX /usr)
set (CMAKE_INSTALL_RPATH /usr/lib/kysdk/kysdk-base)
add_subdirectory(src)

View File

@ -0,0 +1,6 @@
base_version=1.1.1
Name: libkysdk-base
Description: kysdk base layer
Requires: kysdk-log >= ${base_version} kysdk-config >= ${base_version} kysdk-timer >= ${base_version} kysdk-utils >= ${base_version}
Version: 1.1.1

View File

@ -0,0 +1,8 @@
base_version=1.1.1
Name: libkysdk-config
Description: kysdk base layer config component
Requires: kysdk-utils
Version: 1.1.1
Cflags: -I/usr/include/kysdk/kysdk-base/
Libs: -L/usr/lib/kysdk/kysdk-base/ -lkyconf -Wl,-rpath=/usr/lib/kysdk/kysdk-base/

View File

@ -0,0 +1,8 @@
base_version=1.1.1
Name: libkysdk-log
Description: kysdk base layer log component
Requires: kysdk-config kysdk-utils libsystemd
Version: 1.1.1
Cflags: -I/usr/include/kysdk/kysdk-base/
Libs: -L/usr/lib/kysdk/kysdk-base/ -lkylog -Wl,-rpath=/usr/lib/kysdk/kysdk-base/

View File

@ -0,0 +1,6 @@
Name: libkysdk-timer
Description: kysdk base layer time component
Requires: kysdk-utils
Version: 1.1.1
Cflags: -I/usr/include/kysdk/kysdk-base/
Libs: -L/usr/lib/kysdk/kysdk-base/ -lkytimer -Wl,-rpath=/usr/lib/kysdk/kysdk-base/

View File

@ -0,0 +1,5 @@
Name: libkysdk-utils
Description: kysdk base layer utils component
Version: 1.1.1
Cflags:-I/usr/include/kysdk/kysdk-base/
Libs: -L/usr/lib/kysdk/kysdk-base/ -lkydatastruct -Wl,-rpath=/usr/lib/kysdk/kysdk-base/

2533
kysdkbase.doxfile Normal file

File diff suppressed because it is too large Load Diff

13
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
include_directories(config)
include_directories(utils)
include_directories(log)
include_directories(timer)
# add_subdirectory(communication)
add_subdirectory(config)
# add_subdirectory(debbuger)
add_subdirectory(log)
# add_subdirectory(process)
# add_subdirectory(thread)
add_subdirectory(timer)
add_subdirectory(utils)

10
src/config/CMakeLists.txt Normal file
View File

@ -0,0 +1,10 @@
aux_source_directory(. SOURCESCODE)
add_library(kyconf SHARED ${SOURCESCODE})
add_executable(kyconf-test-struct test/test_structlist.c)
target_link_libraries(kyconf-test-struct kyconf kylog pthread)
install(TARGETS kyconf
DESTINATION lib/kysdk/kysdk-base)
# install(FILES libkyconf.h
# DESTINATION include/kysdk/kysdk-base)

20
src/config/Makefile Normal file
View File

@ -0,0 +1,20 @@
OBJ=gsettingsparse.o jsonparse.o structparse.o xmlparse.o
CFLAGS=-g -O0 -Wall -fPIC -I../ -I../utils/ -I../config/
CLIBS=-lpthread
CC:=$(shell bash -c 'type $(CC) &> /dev/null && echo $(CC) || echo gcc')
TARGET=libkyconf.so
LIBINST=libkyconf.so.1.0.0
LIBHEAD=kyconf.h
LIBINSTHEADER=/usr/include/kysdk/base/
all:$(OBJ)
$(CC) -o $(LIBINST) configure.c $(OBJ) $(CFLAGS) $(CLIBS) -shared
mkdir -p lib/
mv -f $(LIBINST) lib/
cd lib/ && ln -sf $(LIBINST) $(TARGET) && cd ..
-rm *.o &> /dev/null
clean:
-rm *.o &> /dev/null
-rm ../lib/$(TARGET) &> /dev/null

38
src/config/datatype.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef KYSDK_BASE_CONFIGURE_TYPE_H__
#define KYSDK_BASE_CONFIGURE_TYPE_H__
#include <stddef.h>
typedef union KconfigureValue
{
int asInt;
long long asLLong;
double asDouble;
char *asString;
}KconfigureValue;
typedef enum {
KconfigureInt,
KconfigureLLong,
KconfigureDouble,
KconfigureString
}KconfigureValueType;
typedef enum {
KconfigureNodeRoot,
KconfigureNodeGroup,
KconfigureNodeNode
}KconfigureNodeType;
typedef struct KconfigureDataNode{
char *group;
char *key;
size_t children_nums;
size_t max_children_nums;
char* value;
// KconfigureValueType valType;
KconfigureNodeType nodeType;
struct KconfigureDataNode **children;
}KconfigureDataNode;
#endif

View File

@ -0,0 +1,6 @@
#include "gsettingsparse.h"
int isgsettings(const char *conf)
{
return 0;
}

View File

@ -0,0 +1,6 @@
#ifndef KDK_BASE_CONF_GSETTINGS_H__
#define KDK_BASE_CONF_GSETTINGS_H__
extern int isgsettings(const char *conf);
#endif

6
src/config/jsonparse.c Normal file
View File

@ -0,0 +1,6 @@
#include "jsonparse.h"
int isjson(const char *conf)
{
return 0;
}

6
src/config/jsonparse.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef KDK_BASE_CONF_JSON_H__
#define KDK_BASE_CONF_JSON_H__
extern int isjson(const char *conf);
#endif

332
src/config/libkyconf.c Normal file
View File

@ -0,0 +1,332 @@
#include "libkyconf.h"
#include "structparse.h"
#include <kerr.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
typedef enum
{
KDK_CONF_XML,
KDK_CONF_JSON,
KDK_CONF_GSETTINGS,
KDK_CONF_STRUCT
}KconfigureType;
typedef struct KconfigureSettings
{
char *confpath;
unsigned int id;
int8_t watch; // 监听配置变化
KconfigureType type;
void *data; // 指向配置解析数据的指针
}KconfigureSettings;
typedef struct KconfigureList
{
pthread_mutex_t lock;
unsigned int counts;
unsigned int max_nums;
KconfigureSettings **conflist;
}KconfigureList;
static KconfigureList g_conflist;
static void init_conf_global()
{
static int inited;
// FixMe: 竞态风险
if (inited)
return;
inited = 1;
pthread_mutex_init(&g_conflist.lock, NULL);
g_conflist.counts = 0;
g_conflist.max_nums = 5;
g_conflist.conflist = NULL;
return;
}
static KconfigureType get_conf_type(const char* confpath)
{
if (isxml(confpath))
return KDK_CONF_XML;
else if (isjson(confpath))
return KDK_CONF_JSON;
else if (isgsettings(confpath))
return KDK_CONF_GSETTINGS;
return KDK_CONF_STRUCT;
}
static inline int kdk_test_file_exist(const char *file) ALWAYSINLINE;
static inline int kdk_test_file_exist(const char *file)
{
return access(file, R_OK | F_OK) ? 0 : 1;
}
static inline int lock_conf_list() ALWAYSINLINE;
static inline int unlock_conf_list() ALWAYSINLINE;
static inline int lock_conf_list()
{
return pthread_mutex_lock(&g_conflist.lock);
}
static inline int unlock_conf_list()
{
return pthread_mutex_unlock(&g_conflist.lock);
}
static KconfigureSettings* new_conf_settings()
{
KconfigureSettings *res = (KconfigureSettings *)calloc(1, sizeof(KconfigureSettings));
ASSERT_NOT_NULL(res, NULL);
lock_conf_list();
if (! g_conflist.conflist)
{
g_conflist.conflist = (KconfigureSettings **)malloc(sizeof(KconfigureSettings *) * g_conflist.max_nums);
if (! g_conflist.conflist)
goto err;
}
if (g_conflist.counts == g_conflist.max_nums)
{
g_conflist.max_nums += 5;
KconfigureSettings **tmp = g_conflist.conflist;
g_conflist.conflist = (KconfigureSettings **)realloc(g_conflist.conflist, \
sizeof(KconfigureSettings *) * g_conflist.max_nums);
if (! g_conflist.conflist)
{
g_conflist.conflist = tmp;
g_conflist.max_nums -= 5;
goto err;
}
}
g_conflist.conflist[g_conflist.counts] = res;
// counts仅单调递增
g_conflist.counts ++;
res->id = g_conflist.counts;
unlock_conf_list();
return res;
err:
unlock_conf_list();
free(res);
return NULL;
}
static void free_conf_settings(KconfigureSettings *conf)
{
if (conf)
{
lock_conf_list();
// 根据配置文件的open/close频率特性我们没有必要减少其引用计数和回收已经realloc的内存置空就行了
g_conflist.conflist[conf->id - 1] = NULL;
unlock_conf_list();
SAFE_FREE(conf->confpath);
free(conf);
}
}
int kdk_conf_init(const char* confpath)
{
if (!confpath || !kdk_test_file_exist(confpath))
return -KDK_EINVALIDARGS;
init_conf_global();
KconfigureSettings *conf = new_conf_settings();
ASSERT_NOT_NULL(conf, -1);
conf->confpath = (char *)malloc(sizeof(char) * (strlen(confpath) + 1));
if (! conf->confpath)
goto err;
strcpy(conf->confpath, confpath);
conf->type = get_conf_type(confpath);
if (conf->type == KDK_CONF_XML)
{
}
else if (conf->type == KDK_CONF_JSON)
{
}
else if (conf->type == KDK_CONF_GSETTINGS)
{
}
else
{
conf->data = S_newParse();
if (!conf->data)
goto err;
if (S_parseFile(conf->data, conf->confpath))
{
goto err;
}
}
return conf->id;
err:
free_conf_settings(conf);
return -1;
}
void kdk_conf_destroy(int id)
{
if (id > 0)
free_conf_settings(g_conflist.conflist[id - 1]);
}
int kdk_conf_reload(int id)
{
if (id <= 0)
return -KDK_EINVALIDARGS;
KconfigureSettings *conf = g_conflist.conflist[id - 1];
ASSERT_NOT_NULL(conf, -1);
if (conf->type == KDK_CONF_XML)
{
}
else if (conf->type == KDK_CONF_JSON)
{
}
else if (conf->type == KDK_CONF_GSETTINGS)
{
}
else
{
void *data = S_newParse();
if (! data)
goto err;
if (S_parseFile(data, conf->confpath))
{
goto err;
}
S_destroyParse(&conf->data);
conf->data = data;
}
return 0;
err:
return -1;
}
void kdk_conf_enable_autoreload(int id)
{
#ifdef KYSDK_FILEWATCHER_H
#endif // KYSDK_FILEWATCHER_H
return;
}
void kdk_conf_disable_autoreload(int id)
{
#ifdef KYSDK_FILEWATCHER_H
#endif // KYSDK_FILEWATCHER_H
return;
}
const char* kdk_conf_get_value(int id, const char* group, const char* key)
{
if (id <= 0 || id > g_conflist.counts || ! key)
return NULL;
if (!group || strlen(group) == 0)
group = "KDK_DefaultGroup";
const char *res = "";
KconfigureSettings *conf = g_conflist.conflist[id - 1];
ASSERT_NOT_NULL(conf, NULL);
if (conf->type == KDK_CONF_XML)
{
}
else if (conf->type == KDK_CONF_JSON)
{
}
else if (conf->type == KDK_CONF_GSETTINGS)
{
}
else
{
res = S_getValue(conf->data, group, key);
}
return res;
}
int kdk_conf_set_value(int id, const char* group, const char* key, const char* value)
{
return 0;
}
char** const kdk_conf_list_key(int id, const char* group)
{
if (id < 1 || id > g_conflist.counts || ! group)
return NULL;
char** res = NULL;
KconfigureSettings *conf = g_conflist.conflist[id - 1];
ASSERT_NOT_NULL(conf, NULL);
if (conf->type == KDK_CONF_XML)
{
}
else if (conf->type == KDK_CONF_JSON)
{
}
else if (conf->type == KDK_CONF_GSETTINGS)
{
}
else
{
res = S_getKeyList(conf->data, group);
}
return res;
}
char** const kdk_conf_list_group(int id)
{
if (id < 1)
return NULL;
char** res = NULL;
KconfigureSettings *conf = g_conflist.conflist[id - 1];
ASSERT_NOT_NULL(conf, NULL);
if (conf->type == KDK_CONF_XML)
{
}
else if (conf->type == KDK_CONF_JSON)
{
}
else if (conf->type == KDK_CONF_GSETTINGS)
{
}
else
{
res = S_getGroupList(conf->data);
}
return res;
}

123
src/config/libkyconf.h Normal file
View File

@ -0,0 +1,123 @@
#ifndef KYSDK_BASE_CONFIGURE_H__
#define KYSDK_BASE_CONFIGURE_H__
/** @defgroup 配置文件模块
* @{
*/
/**
* @file libkyconf.h
* @author liuyunhe (liuyunhe@kylinos.cn)
* @brief KYSDK配置文件处理库XML()JSON()
* @version 0.1
* @date 2021-10-28
*
* @copyright Copyright (c) 2021
*
*/
#include <sys/types.h>
#include <sdkmarcos.h>
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief
*
* @param confpath
* @return int
*/
extern int kdk_conf_init(const char* confpath);
/**
* @brief
*
* @param id kdk_conf_init返回的配置文件句柄
*/
extern void kdk_conf_destroy(int id);
/**
* @brief
*
* @param id kdk_conf_init返回的配置文件句柄
* @return int 0
*/
extern int kdk_conf_reload(int id);
/**
* @brief []
*
* @param id kdk_conf_init返回的配置文件句柄
*/
extern void kdk_conf_enable_autoreload(int id);
/**
* @brief []
*
* @param id kdk_conf_init返回的配置文件句柄
*/
extern void kdk_conf_disable_autoreload(int id);
/**
* @brief
*
* @param id kdk_conf_init返回的配置文件句柄
* @param group key所在的组名称
* @param key
* @return const char* key不存在
*/
extern const char* kdk_conf_get_value(int id, const char* group, const char* key);
/**
* @brief [] key的值
*
* @param id kdk_conf_init返回的配置文件句柄
* @param group key所对应的组名称
* @param key key的名称key原来不存在于该Group中key
* @param value
* @return int 0
*/
extern int kdk_conf_set_value(int id, const char* group, const char* key, const char* value);
/**
* @brief id对应配置文件的指定Group下的key值NULL指针表示
*
* @param id kdk_conf_init返回的句柄值
* @param group Group名称
* @return const char** const NULL结尾的字符串列表key名称alloc分配的内存free释放
*/
extern char** const kdk_conf_list_key(int id, const char* group);
/**
* @brief id对应配置文件的所有GroupNULL指针表示
*
* @param id kdk_conf_init返回的句柄值
* @return const char** const NULL结尾的字符串列表alloc分配的内存free释放
*/
extern char** const kdk_conf_list_group(int id);
#ifdef __cplusplus
}
#endif
#endif //KYSDK_BASE_CONFIGURE_H__
/**
* \example kysdk-base/src/config/test/test_structlist.c
*
*/
/**
* @}
*/

322
src/config/structparse.c Normal file
View File

@ -0,0 +1,322 @@
#include "structparse.h"
#include <sdkmarcos.h>
#include <cstring-extension.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define LINEMAX 1024
static KconfigureDataNode* get_group_node(structParse *parse, const char *group)
{
KconfigureDataNode **grouplist = parse->content.groupList;
size_t groupSize = parse->content.curGroupSize;
for (size_t i = 0; i < groupSize; i ++)
{
if (strcmp(grouplist[i]->group, group) == 0)
return grouplist[i];
}
return NULL;
}
static KconfigureDataNode* get_key_node(KconfigureDataNode *groupnode, const char *key)
{
for (int i = 0; i < groupnode->children_nums; i ++)
{
if (strcmp(groupnode->children[i]->key, key) == 0)
return groupnode->children[i];
}
return NULL;
}
static KconfigureDataNode* append_group(structParse *parse, const char *group)
{
if (parse->content.maxGroupSize <= parse->content.curGroupSize)
{
KconfigureDataNode **newGroupList = (KconfigureDataNode **)realloc(parse->content.groupList, (parse->content.maxGroupSize + 4) * sizeof(KconfigureDataNode *));
if (!newGroupList)
{
parse->content.curGroupSize --;
return NULL;
}
parse->content.maxGroupSize += 4;
parse->content.groupList = newGroupList;
}
KconfigureDataNode *groupnode = (KconfigureDataNode *)calloc(1, sizeof(KconfigureDataNode));
if (!group)
return NULL;
groupnode->nodeType = KconfigureNodeGroup;
groupnode->group = (char *)group;
parse->content.groupList[parse->content.curGroupSize] = groupnode;
parse->content.curGroupSize ++;
return groupnode;
}
static KconfigureDataNode* append_key(KconfigureDataNode *groupnode, const char *key, const char *value)
{
KconfigureDataNode *keynode = NULL;
for (size_t i = 0; i < groupnode->children_nums; i ++)
{
if (strcmp(groupnode->children[i]->key, key) == 0)
{
keynode = groupnode->children[i];
break;
}
}
// 新建key
if (! keynode)
{
if (groupnode->max_children_nums <= groupnode->children_nums)
{
KconfigureDataNode **newKeyList = (KconfigureDataNode **)realloc(groupnode->children, (groupnode->max_children_nums + 4) * sizeof(KconfigureDataNode *));
if (! newKeyList)
return NULL;
groupnode->max_children_nums += 4;
groupnode->children = newKeyList;
}
keynode = (KconfigureDataNode *)calloc(1, sizeof(KconfigureDataNode));
if (!keynode)
return NULL;
groupnode->children[groupnode->children_nums] = keynode;
keynode->group = strdup(groupnode->group);
keynode->key = (char *)key;
groupnode->children_nums ++;
}
keynode->value = (char *)value;
// keynode->valType = KconfigureString;
return keynode;
}
static int parseFile(structParse *parse, const char *filepath)
{
FILE *cfp = fopen(filepath, "rt");
ASSERT_NOT_NULL(cfp, -1);
KconfigureDataNode *cur_group_node = NULL;
char buf[LINEMAX];
while (feof(cfp) == 0)
{
if (fgets(buf, LINEMAX, cfp) == NULL)
break;
#ifdef __linux__
strstrip(buf, '\n');
strskipblank(buf);
#elif defined __win32__
strstrip(buf, '\n');
strstrip(buf, '\r');
#endif
if (strlen(buf) == 0)
continue;
// Comments
if (strstartswith(buf, "#") == 0)
continue;
// Group
if (strstartswith(buf, "[") == 0 && strendwith(buf, "]") == 0)
{
cur_group_node = append_group(parse, strndup(&buf[1], strlen(buf) - 2));
if (!cur_group_node)
{
// err output
fclose(cfp);
return -1;
}
continue;
}
// Key
int depos = strfirstof(buf, parse->delimiter.assignDelimiter);
char *keyStr, *valStr;
if (depos < 0)
{
// 没有赋值符号,可能是什么情况?
keyStr = buf;
valStr = "";
strstripspace(keyStr);
}
else
{
buf[depos] = 0;
keyStr = buf;
valStr = &buf[depos + 1];
strstripspace(keyStr);
strstripspace(valStr);
}
KconfigureDataNode *groupnode = cur_group_node;
if (!groupnode)
{
// Default group
char *defaultnode = malloc(36);
if (! defaultnode)
{
// OOM
fclose(cfp);
return -1;
}
strcpy(defaultnode, "KDK_DefaultGroup");
cur_group_node = append_group(parse, defaultnode);
groupnode = cur_group_node;
}
// 多重赋值的情况
size_t multikeys = strcounts(keyStr, parse->delimiter.keyDelimiter);
if (multikeys)
{
multikeys += 1;
char **keylist = strsplit(keyStr, parse->delimiter.keyDelimiter);
if (!keylist)
{
// OOM
fclose(cfp);
return -1;
}
size_t multivals = strcounts(valStr, parse->delimiter.valueDelimiter) + 1;
char **vallist = strsplit(valStr, parse->delimiter.valueDelimiter);
if (!vallist)
{
// OOM
free(keylist);
fclose(cfp);
return -1;
}
for (size_t i = 0; i < multikeys; i ++)
{
append_key(groupnode, strdup(strskipspace(keylist[i])), strdup(i >= multivals ? "" : strskipspace(vallist[i])));
}
free(keylist);
free(vallist);
}
else
{
append_key(groupnode, strdup(keyStr), strdup(valStr));
}
}
fclose(cfp);
return 0;
}
structParse* S_newParse()
{
structParse *parse = (structParse *)calloc(1, sizeof(structParse));
ASSERT_NOT_NULL(parse, NULL);
parse->delimiter.assignDelimiter = '=';
parse->delimiter.keyDelimiter = ',';
parse->delimiter.valueDelimiter = ',';
return parse;
}
void S_setKeyDelimiter(structParse *parse, char ch)
{
parse->delimiter.keyDelimiter = ch;
}
void S_setValueDelimiter(structParse *parse, char ch)
{
parse->delimiter.valueDelimiter = ch;
}
void S_setAssignmentDelimiter(structParse *parse, char ch)
{
parse->delimiter.assignDelimiter = ch;
}
int S_parseFile(structParse *parse, const char *filename)
{
if (access(filename, F_OK))
return -1;
if (parse->confpath)
{
free(parse->confpath);
parse->confpath = NULL;
}
parse->confpath = (char*)malloc(strlen(filename) + 1);
ASSERT_NOT_NULL(parse->confpath, -1);
strcpy(parse->confpath, filename);
return parseFile(parse, parse->confpath);
}
char* const S_getValue(structParse *parse, const char *group, const char *key)
{
KconfigureDataNode *groupnode = get_group_node(parse, group);
ASSERT_NOT_NULL(groupnode, "");
KconfigureDataNode *keynode = get_key_node(groupnode, key);
ASSERT_NOT_NULL(keynode, "");
return keynode->value;
}
void S_setValue(structParse *parse, const char *group, const char *key, KconfigureValue value, KconfigureValueType valType)
{
return;
}
int S_writeBack(structParse *parse)
{
return 0;
}
int S_write2File(structParse *parse, const char *filename)
{
return 0;
}
void S_destroyParse(structParse **parse)
{
if (!parse || !*parse)
return;
SAFE_FREE((*parse)->confpath);
free(*parse);
}
char** const S_getKeyList(structParse *parse, const char *group)
{
KconfigureDataNode *pg = get_group_node(parse, group);
ASSERT_NOT_NULL(pg, NULL);
char **res = (char **)calloc(1, (pg->children_nums + 1) * sizeof(char *));
ASSERT_NOT_NULL(res, NULL);
for (size_t i = 0; i < pg->children_nums; i ++)
{
res[i] = pg->children[i]->key;
}
return res;
}
char** const S_getGroupList(structParse *parse)
{
char **res = (char **)calloc(1, (parse->content.curGroupSize + 1) * sizeof(char *));
ASSERT_NOT_NULL(res, NULL);
for (size_t i = 0; i < parse->content.curGroupSize; i ++)
{
res[i] = parse->content.groupList[i]->group;
}
return res;
}

36
src/config/structparse.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef KYSDK_BASE_CONFIGURE_STRUCT_H__
#define KYSDK_BASE_CONFIGURE_STRUCT_H__
#include "datatype.h"
typedef struct {
KconfigureDataNode **groupList; // Group List
size_t maxGroupSize;
size_t curGroupSize;
}structContenct;
typedef struct {
struct {
char keyDelimiter;
char valueDelimiter;
char assignDelimiter;
}delimiter;
char *confpath;
structContenct content;
}structParse;
extern structParse* S_newParse();
extern void S_setKeyDelimiter(structParse *parse, char ch);
extern void S_setValueDelimiter(structParse *parse, char ch);
extern void S_setAssignmentDelimiter(structParse *parse, char ch);
extern int S_parseFile(structParse *parse, const char *filename);
extern char* const S_getValue(structParse *parse, const char *group, const char *key);
extern void S_setValue(structParse *parse, const char *group, const char *key, KconfigureValue value, KconfigureValueType valType);
extern char** const S_getKeyList(structParse *parse, const char *group);
extern char** const S_getGroupList(structParse *parse);
extern int S_writeBack(structParse *parse);
extern int S_write2File(structParse *parse, const char *filename);
extern void S_destroyParse(structParse **parse);
#endif

11
src/config/test/Makefile Normal file
View File

@ -0,0 +1,11 @@
LDFLAGS =
FILE=$(file)
CFLAGS=$(cflags)
CFLAGS += -g -O0 -std=gnu11 -Wall -DPWD=\"$(PWD)\" -I/usr/include/glib-2.0/glib/ -I../ -I../../utils/
CLIBS= -lpthread
CLIBS += $(clibs)
all:list
list:test_structlist.c ../configure.c ../structparse.c ../jsonparse.c ../gsettingsparse.c ../xmlparse.c
gcc -o $(basename $<) $^ $(CFLAGS) $(CLIBS)

View File

@ -0,0 +1,15 @@
multest1, multest2, multest3 = hello1, hello2, hello3, hello4
defaultkey= 1
unreachable = false
[Testmode]
# comments : this is test mode
key1 = value1
key2 = value2
key3, key4 = value3, value4
key5, key6 = value5
key1 = override1
[System]
OS = KylinOS
Version = v10sp1

View File

@ -0,0 +1,35 @@
#include <libkyconf.h>
#include <stdio.h>
#include <string.h>
int main()
{
int id = kdk_conf_init("struct.conf");
ASSERT_NOT_NULL(id, -1);
char **grouplist = kdk_conf_list_group(id);
ASSERT_NOT_NULL(grouplist, -1);
char *tmpgroup;
int index = 0;
while ((tmpgroup = grouplist[index]))
{
printf("Group: %s\n", tmpgroup);
char **keylist = kdk_conf_list_key(id, tmpgroup);
ASSERT_NOT_NULL(keylist, -1);
char *tmpkey;
int k_index = 0;
while ((tmpkey = keylist[k_index]))
{
const char *tmpval = kdk_conf_get_value(id, tmpgroup, tmpkey);
printf("%s = %s\n", tmpkey , tmpval);
k_index ++;
}
index ++;
}
kdk_conf_destroy(id);
return 0;
}

6
src/config/xmlparse.c Normal file
View File

@ -0,0 +1,6 @@
#include "xmlparse.h"
int isxml(const char *conf)
{
return 0;
}

6
src/config/xmlparse.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef KDK_BASE_CONF_XML_H__
#define KDK_BASE_CONF_XML_H__
extern int isxml(const char *conf);
#endif

21
src/log/CMakeLists.txt Normal file
View File

@ -0,0 +1,21 @@
aux_source_directory(. SOURCESCODE)
add_library(kylog SHARED ${SOURCESCODE})
add_executable(kylog-testlog test/test-log.c)
add_executable(kylog-testsetdir test/test-setdir.c)
add_executable(kylog-testpressure test/test-pressure.c)
add_executable(kylog-testautowrap test/test-autowrap.c)
find_library(SYSTEMD_LIB systemd)
target_link_libraries(kylog kyconf pthread ${SYSTEMD_LIB})
target_link_libraries(kylog-testlog kylog)
target_link_libraries(kylog-testsetdir kylog)
target_link_libraries(kylog-testautowrap kylog)
target_link_libraries(kylog-testpressure kylog)
install(TARGETS kylog
DESTINATION lib/kysdk/kysdk-base)
install(FILES libkylog.h
DESTINATION include/kysdk/kysdk-base)
install(FILES kylog-rotate-default
DESTINATION /etc/kysdk/kysdk-base)

20
src/log/Makefile Normal file
View File

@ -0,0 +1,20 @@
OBJ=core.o format.o klog_mqueue.o kylog.o write.o writeFile.o
CFLAGS=-g -O0 -Wall -fPIC -I../ -I../utils/ -I../config/
# CLIBS=-lpthread -lsystemd
CC:=$(shell bash -c 'type $(CC) &> /dev/null && echo $(CC) || echo gcc')
TARGET=libkylog.so
LIBINST=libkylog.so.1.0.0
LIBHEAD=kylog.h
LIBINSTHEADER=/usr/include/kylog/
all:$(OBJ)
$(CC) -o $(LIBINST) $(OBJ) $(CFLAGS) $(CLIBS) -shared
mkdir -p lib/
mv -f $(LIBINST) lib/
cd lib/ && ln -sf $(LIBINST) $(TARGET) && cd ..
-rm *.o &> /dev/null
clean:
-rm *.o &> /dev/null
-rm ../lib/$(TARGET) &> /dev/null

336
src/log/core.c Normal file
View File

@ -0,0 +1,336 @@
#include "core.h"
#include "klog_dump.h"
#include <kerr.h>
#include <libkyconf.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
KLogger* logger;
const char* stringLevel[8] = {"EMERG", "ALERT", "CRIT", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"};
const char* stringLType[LTENUMMAX] = {"user." , "local3." , "syslog."};
static int _dir_exist(const char *dpath)
{
struct stat st;
if (stat(dpath, &st))
return 0;
if (S_ISDIR(st.st_mode))
return 1;
return 0;
}
static int _create_dir(const char *dpath)
{
#ifdef __linux__
char *command = malloc(strlen(dpath) + 10);
if (!command)
return -1;
sprintf(command, "mkdir -p %s", dpath);
return system(command);
#else
return 1;
#endif
}
/*
* KLogger核心结构体
*/
int initKLogger(int cid)
{
if (logger)
{
return 0;
}
logger = (KLogger*)calloc(1 , sizeof(KLogger));
if (!logger)
{
printf("kdk_logger实例内存分配失败%s\n" , strerror(errno));
return KDK_ENOMEM;
}
const char *identer , *stype , *otype , *specfile;
identer = kdk_conf_get_value(cid, "TYPE" , "identifier");
if (identer)
{
if (!strcasecmp(identer , "user"))
logger->identer = LT_USER;
else if (!strcasecmp(identer , "local3"))
logger->identer = LT_LOCAL3;
else if (!strcasecmp(identer , "syslog"))
logger->identer = LT_SYSLOG;
else
{
logger->identer = LT_SPEC;
strncpy(logger->specLogType , identer , KLOG_MAXPRIVALSIZE);
}
}
else
{
logger->identer = DEFAULT_LOGTYPE;
}
stype = kdk_conf_get_value(cid, "TYPE" , "synctype");
if (stype)
{
if (!strcasecmp(stype , "async"))
logger->stype = ASYNC;
else if (!strcasecmp(stype , "sync"))
logger->stype = SYNC;
else
logger->stype = DEFAULT_SYNCTYPE;
}
else
{
logger->stype = DEFAULT_SYNCTYPE;
}
otype = kdk_conf_get_value(cid, "TYPE" , "output");
if (otype)
{
if (!strcasecmp(otype , "syslog"))
logger->otype = OUT_SYSLOG;
else if (!strcasecmp(otype , "specfile"))
logger->otype = OUT_SPECFILE;
else if (!strcasecmp(otype , "stdout"))
logger->otype = OUT_STDOUT;
else
logger->otype = DEFAULT_OUTPUTTYPE;
}
else
{
logger->otype = DEFAULT_OUTPUTTYPE;
}
logger->levelBasedStorage = atoi(kdk_conf_get_value(cid, "CUSTOM" , "levelBasedStorage"));
if (logger->levelBasedStorage != 0)
logger->levelBasedStorage = 1;
logger->levelBasedContainHigherLevel = atoi(kdk_conf_get_value(cid, "CUSTOM" , "levelBasedContainHigherLevel"));
if (logger->levelBasedContainHigherLevel != 0)
logger->levelBasedContainHigherLevel = 1;
logger->level = atoi(kdk_conf_get_value(cid, "CUSTOM" , "logLevel"));
if (logger->level < KLOG_EMERG || logger->level > KLOG_TRACE)
logger->level = DEFAULT_LOGLEVEL;
logger->pid = getpid();
snprintf(logger->stringPID , 15 , "%d" , logger->pid);
char processPath[KLOG_MAXPATHLEN + 1] = {0};
if (readlink("/proc/self/exe" , processPath , KLOG_MAXPATHLEN) <= 0)
{
printf("无法读取可执行文件名:%s\n" , strerror(errno));
return errno;
}
char* pPName = strrchr(processPath , '/');
if (pPName)
strncpy(logger->processName , ++ pPName , KLOG_PROCESSNAME_LEN);
else
{
strcpy(logger->processName , "untagged");
}
logger->mlock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
if (!logger->mlock)
{
printf("kdk_logger实例锁初始化失败%s\n" , strerror(errno));
return errno;
}
pthread_mutex_init(logger->mlock , NULL);
memset(logger->fp.classfiedfp , 0 , sizeof(FILE*) * 8);
if (logger->otype == OUT_SYSLOG)
printf("日志记录位置SYSLOG\n");
else if (logger->otype == OUT_SPECFILE)
{
specfile = kdk_conf_get_value(cid, "CUSTOM" , "specName");
const char *dpath = kdk_conf_get_value(cid, "CUSTOM", "logDir");
if (dpath && strlen(dpath))
strcpy(logger->rootPath, dpath);
else
{
char *hpath = getenv("HOME");
if (!hpath || strcmp(hpath, "/root") == 0)
strcpy(logger->rootPath, "/var/log");
else
{
strcpy(logger->rootPath, hpath);
strcat(logger->rootPath, "/.log");
if (!_dir_exist(logger->rootPath))
{
if (_create_dir(logger->rootPath))
{
return -1;
}
}
}
}
if (!specfile || !strcmp(specfile , "")) //未指定名称,则使用进程名作为文件名称
{
if (logger->levelBasedStorage)
{
for (int i = 0 ; i < 8 ; i ++)
{
sprintf(logger->logfileName.classfiedfileName[i] , "%s-%s.log" , logger->processName , stringLevel[i]);
}
}
else
{
snprintf(logger->logfileName.commonlogfileName , KLOG_MAXPATHLEN , "%s.log" , logger->processName);
}
klog_rotate_init(cid, logger->processName, logger->rootPath);
}
else //使用指定的specName作为日志名称
{
const char* fName = strrchr(specfile , '/');
if (!fName)
{
fName = specfile;
}
else
{
fName ++;
}
strcpy(logger->specName , fName); //将指定名称保存到结构体中
if (logger->levelBasedStorage)
{
for (int i = 0 ; i < 8 ; i ++)
{
sprintf(logger->logfileName.classfiedfileName[i] , "%s-%s.log" , fName , stringLevel[i]);
}
}
else
{
snprintf(logger->logfileName.commonlogfileName , KLOG_MAXPATHLEN , "%s.log" , fName);
}
klog_rotate_init(cid, logger->specName, logger->rootPath);
}
if (logger->levelBasedStorage)
{
char logPath[(KLOG_MAXPATHLEN << 1) + 1];
for (int i = 0 ; i < 8 ; i ++)
{
snprintf(logPath, KLOG_MAXPATHLEN << 1, "%s/%s", logger->rootPath, logger->logfileName.classfiedfileName[i]);
logger->fp.classfiedfp[i] = fopen(logger->logfileName.classfiedfileName[i] , "at");
if (!logger->fp.classfiedfp[i])
{
printf("无法打开日志文件%s%s\n" , logPath, strerror(errno));
return errno;
}
}
}
else
{
char logPath[(KLOG_MAXPATHLEN << 1) + 1];
snprintf(logPath, KLOG_MAXPATHLEN << 1, "%s/%s", logger->rootPath, logger->logfileName.commonlogfileName);
logger->fp.commonfp = fopen(logPath , "at");
if (!logger->fp.commonfp)
{
printf("无法打开日志文件%s%s\n" ,logPath, strerror(errno));
return errno;
}
printf("日志记录文件:%s\n" , logPath);
}
}
return 0;
}
int setRootDir(const char *dpath)
{
if (!logger || logger->otype != OUT_SPECFILE)
return -1;
if (!_dir_exist(dpath))
{
if (_create_dir(dpath))
return -1;
}
strncpy(logger->rootPath, dpath, KLOG_MAXPATHLEN);
if (logger->levelBasedStorage)
{
char logPath[KLOG_MAXPATHLEN * 2];
for (int i = 0; i < 8; i++)
{
fclose(logger->fp.classfiedfp[i]);
sprintf(logPath, "%s/%s", logger->rootPath, logger->logfileName.classfiedfileName[i]);
logger->fp.classfiedfp[i] = fopen(logger->logfileName.classfiedfileName[i], "at");
if (!logger->fp.classfiedfp[i])
{
printf("无法打开日志文件%s%s\n", logPath, strerror(errno));
return errno;
}
}
}
else
{
char logPath[KLOG_MAXPATHLEN * 2];
fclose(logger->fp.commonfp);
sprintf(logPath, "%s/%s", logger->rootPath, logger->logfileName.commonlogfileName);
logger->fp.commonfp = fopen(logPath, "at");
if (!logger->fp.commonfp)
{
printf("无法打开日志文件%s%s\n", logPath, strerror(errno));
return errno;
}
}
printf("日志记录位置已修改:%s\n", logger->rootPath);
return 0;
}
void destroyKLogger()
{
if (logger)
{
MLOCK(logger->mlock);
if (logger->levelBasedStorage)
{
for (int i = 0 ; i < 8 ; i ++)
{
if (logger->fp.classfiedfp[i])
{
fclose(logger->fp.classfiedfp[i]);
logger->fp.classfiedfp[i] = NULL;
}
}
}
else
{
if (logger->fp.commonfp)
{
fclose(logger->fp.commonfp);
logger->fp.commonfp = NULL;
}
}
MUNLOCK(logger->mlock);
pthread_mutex_destroy(logger->mlock);
free(logger->mlock);
free(logger);
logger = NULL;
}
}
void set_autowrap(int autowrap)
{
if (! logger)
return;
MLOCK(logger->mlock);
logger->autowrap = autowrap ? 1 : 0;
MUNLOCK(logger->mlock);
}
void append_wrap(char *message)
{
if (logger->autowrap && logger->otype != OUT_SYSLOG)
strcat(message, "\n");
}

105
src/log/core.h Normal file
View File

@ -0,0 +1,105 @@
#ifndef __KLOG_CORE_H__
#define __KLOG_CORE_H__
#include <stdio.h>
#include <pthread.h>
#include "libkylog.h"
#define KLOG_DEFAULT_CONFPATH "/etc/kylog.conf"
#define KLOG_DEFAULT_MSGFLUSHINTERVAL 100
#define KLOG_DEFAULT_MSGGROWTH 4096 //消息存储超阈值后单次增长率
#define KLOG_DEFAULT_MSGGROWTHRESHOLD 204800 //消息增长阈值
#define MLOCK(x) (pthread_mutex_lock(x))
#define MTRYLOCK(x) (pthread_mutex_trylock(x))
#define MUNLOCK(x) (pthread_mutex_unlock(x))
// #ifndef RELEASE
// #define OUTPUT(fmt , ...) printf("[%s:%d]"fmt , __FUNCTION__ , __LINE__ , ##__VA_ARGS__)
// #else
// #define OUTPUT(fmt, ...)
// #endif
#define KLOG_MAXPATHLEN 1024 //文件路径最大长度
#define KLOG_MAXMSGSIZE 2048 //每条消息最大长度
#define KLOG_MAXPRIVALSIZE 128 //自定义内容最大长度
#define KLOG_PROCESSNAME_LEN 128 //可执行文件名最大长度
#define KLOG_MAXDATELEN 64 //日期最大长度
#define KLOG_CONF_GROUPSIZE 64 //配置文件Group最大长度
#define KLOG_CONF_KEYSIZE 64 //配置文件Key最大长度
#define KLOG_CONF_VALUESIZE KLOG_MAXPATHLEN //配置文件value最大长度
#define KLOG_OPT_FORMAT 0x0001
#define KLOG_OPT_LOGTYPE 0x0002
#define KLOG_OPT_SYNC 0x0003
#define KLOG_OPT_OUTPUT 0x0004
#define KLOG_OPT_SPECFILE 0x0005
#define KLOG_OPT_SPECCONTENT 0x0006
#ifndef CORE_DEFINE
#define CORE_DEFINE
enum logIdentifier{
LT_USER = 0,
LT_LOCAL3 = 1,
LT_SYSLOG = 2,
LT_SPEC,
LTENUMMAX
}; //日志类别
enum syncType{
ASYNC=1, // 异步模式会较大程度提高日志写入速度减小日志写入带来的IO等待时间但有可能出现程序崩溃时日志尚未写入的情况
SYNC, // 同步模式,每次的写入都会等待写入事件完成
STENUMMAX
}; //记录方式
enum outputType{
OUT_SYSLOG=0,
OUT_SPECFILE,
OUT_STDOUT,
OTENUMMAX
}; //日志输出位置
#endif
typedef struct KLogger
{
union
{
FILE* commonfp;
FILE* classfiedfp[8];
}fp;
enum logIdentifier identer; // 日志输出的标识符
enum syncType stype; // 标明在spec模式下刷入日志的模式异步/同步
enum outputType otype; // 标明日志输出的位置可以输出到syslog/指定文件/标准输出目前syslog尚未验证
int levelBasedStorage; //按照等级分类存储
int levelBasedContainHigherLevel; //按等级分类存储时,低优先级日志是否需要包含高优先级日志(数字越小优先级越高)
int level; //日志记录等级
int autowrap; // 自动换行
pid_t pid;
char stringPID[16];
char rootPath[KLOG_MAXPATHLEN + 1];
char specName[KLOG_MAXPATHLEN + 1];
union
{
char commonlogfileName[KLOG_MAXPATHLEN + 1]; //自定义日志文件路径
char classfiedfileName[8][KLOG_MAXPATHLEN + 1];
}logfileName;
char processName[KLOG_PROCESSNAME_LEN + 1]; //可执行文件名称
char specLogType[KLOG_MAXPRIVALSIZE + 1]; //自定义记录类型
pthread_mutex_t* mlock;
}KLogger;
#define DEFAULT_LOGTYPE LT_LOCAL3
#define DEFAULT_OUTPUTTYPE OUT_SPECFILE
#define DEFAULT_SYNCTYPE SYNC
#define DEFAULT_LOGLEVEL KLOG_DEBUG
extern int initKLogger(int cid);
extern int setRootDir(const char* dpath) NOTNULL();
extern void destroyKLogger();
extern void set_autowrap(int autowrap);
extern void append_wrap(char *message);
extern KLogger* logger;
#endif

145
src/log/format.c Normal file
View File

@ -0,0 +1,145 @@
#include "format.h"
#include "libkyconf.h"
#include <errno.h>
#include <sys/time.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
PrintFormat klog_printformat;
extern const char* stringLevel[8];
extern const char* stringLType[LTENUMMAX];
int getRecordDate(char* date) NOTNULL();
int formatMessage(int lvl , const char *filename , const char *func , int linenum , const char *message , char* result , unsigned int resultSize) NOTNULL();
int getRecordDate(char* date)
{
time_t now;
time(&now);
if (ctime_r(&now , date))
date[strlen(date) - 1] = '\0';
return 0;
}
void loadFormatOptions(int id)
{
klog_printformat.vis_execName = atoi(kdk_conf_get_value(id, "FORMAT" , "f_processname")) ? true : false;
klog_printformat.vis_filename = atoi(kdk_conf_get_value(id, "FORMAT" , "f_filename")) ? true : false;
klog_printformat.vis_funcline = atoi(kdk_conf_get_value(id, "FORMAT" , "f_funcline")) ? true : false;
klog_printformat.vis_identifier = atoi(kdk_conf_get_value(id, "FORMAT" , "f_identifier")) ? true : false;
klog_printformat.vis_pid = atoi(kdk_conf_get_value(id, "FORMAT" , "f_pid")) ? true : false;
klog_printformat.vis_tid = atoi(kdk_conf_get_value(id, "FORMAT" , "f_tid")) ? true : false;
}
int formatMessage(int lvl , const char *filename , const char *func , int linenum , const char *message , char* result , unsigned int resultSize)
{
char buffer[KLOG_MAXMSGSIZE + 1] = {"["}; //TODO:这里开4097字节可能有越界风险
char* pos = buffer;
pos ++;
//[类型.等级]
if (klog_printformat.vis_identifier)
{
if (logger->identer != LT_SPEC)
{
memcpy(pos , stringLType[logger->identer] , strlen(stringLType[logger->identer]) * sizeof(char));
pos += strlen(stringLType[logger->identer]);
}
else
{
memcpy(pos , logger->specLogType , strlen(logger->specLogType) * sizeof(char));
pos += strlen(logger->specLogType);
strcat(pos , ".");
pos ++;
}
}
memcpy(pos , stringLevel[lvl] , strlen(stringLevel[lvl]) * sizeof(char));
pos += strlen(stringLevel[lvl]);
strcpy(pos , "] ");
pos += 2;
//[日期]
strcpy(pos , "[");
pos += 1;
char nowtime[KLOG_MAXDATELEN + 1] = {0};
getRecordDate(nowtime);
memcpy(pos , nowtime , strlen(nowtime) * sizeof(char));
pos += strlen(nowtime);
strcpy(pos , "] ");
pos += 2;
//[进程名:PID-TID]
if (klog_printformat.vis_execName || klog_printformat.vis_pid)
{
strcpy(pos , "[");
pos ++;
if (klog_printformat.vis_execName)
{
memcpy(pos , logger->processName , strlen(logger->processName) * sizeof(char));
pos += strlen(logger->processName);
}
if (klog_printformat.vis_pid)
{
if (__glibc_likely(klog_printformat.vis_execName))
{
strcpy(pos , ":");
pos ++;
}
memcpy(pos , logger->stringPID , strlen(logger->stringPID) * sizeof(char));
pos += strlen(logger->stringPID);
}
if (klog_printformat.vis_tid)
{
if (__glibc_likely(klog_printformat.vis_pid))
{
strcpy(pos , "-");
pos ++;
}
char tid[32] = {0};
sprintf(tid , "%lu" , pthread_self());
memmove(pos , tid , strlen(tid) * sizeof(char));
pos += strlen(tid);
}
strcpy(pos , "] ");
pos += 2;
}
//TODO:[自定义]
//[文件:函数-行号]
if (klog_printformat.vis_filename || klog_printformat.vis_funcline)
{
strcpy(pos , "[");
pos += 1;
if (klog_printformat.vis_filename)
{
memcpy(pos , filename , strlen(filename) * sizeof(char));
pos += strlen(filename);
}
if (klog_printformat.vis_funcline)
{
if (__glibc_likely(klog_printformat.vis_filename))
{
strcpy(pos , ":");
pos += 1;
}
memcpy(pos , func , strlen(func) * sizeof(char));
pos += strlen(func);
char line[10] = {0};
snprintf(line , 9 , "-%d" , linenum);
memcpy(pos , line , strlen(line) * sizeof(char));
pos += strlen(line);
}
strcpy(pos , "] ");
pos += 2;
}
size_t remainMsgSize = KLOG_MAXMSGSIZE - strlen(buffer);
size_t rawMsgSize = strlen(message) * sizeof(char);
memcpy(pos , message , rawMsgSize > remainMsgSize ? remainMsgSize : rawMsgSize);
memcpy(result , buffer , resultSize * sizeof(char));
return 0;
}

31
src/log/format.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef __KLOG_FMT_H__
#define __KLOG_FMT_H__
#include <stdbool.h>
#include "core.h"
typedef struct format
{
bool vis_identifier;
bool vis_execName;
bool vis_pid;
bool vis_tid;
bool vis_filename;
bool vis_funcline;
}PrintFormat;
extern PrintFormat klog_printformat;
#ifndef KLOG_FORMATSET
#define KLOG_FORMATSET
#define FORMAT_LOGTYPE 0x0001
#define FORMAT_PROCESSNAME 0x0002
#define FORMAT_PID 0x0004
#define FORMAT_FILENAME 0x0008
#define FORMAT_LINENUM 0x0010
#endif
extern int getRecordDate(char* date) NOTNULL();
extern void loadFormatOptions();
extern int formatMessage(int lvl , const char *filename , const char *func , int linenum , const char *message , char* result , unsigned int resultSize) NOTNULL();
#endif

59
src/log/klog_dump.c Normal file
View File

@ -0,0 +1,59 @@
#include "klog_dump.h"
#include "libkyconf.h"
#include <ctype.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int klog_rotate_init(int cid, const char *name, const char *rootpath)
{
const char *ruler = kdk_conf_get_value(cid, "DUMP", "rules");
if (strcasecmp(ruler, "none") == 0)
return 0;
const char *oversize = kdk_conf_get_value(cid, "DUMP", "size");
int compress = atoi(kdk_conf_get_value(cid, "DUMP", "compress"));
char tmp[1025];
snprintf(tmp, 1024, "/etc/kysdk/kysdk-base/logrotate.d/%s", name);
FILE *fp = fopen(tmp, "wt+");
if (!fp)
return -1;
snprintf(tmp, 1024, "%s/%s* {\n", rootpath, name);
fputs(tmp, fp);
if (strcasecmp(ruler, "daily") == 0)
fputs("\tdaily\n", fp);
else if (strcasecmp(ruler, "weekly") == 0)
fputs("\tweekly\n", fp);
else
fputs("\tmonthly\n", fp);
fputs("\trotate 7\n", fp);
fputs("\tnotifempty\n", fp);
fputs("\tnocopytruncate\n", fp);
if (compress)
fputs("\tcompress\n", fp);
else
fputs("\tnocompress\n", fp);
if (strcasecmp(ruler, "size") == 0)
{
int size = atoi(oversize);
snprintf(tmp, 1024, "\tsize %d", size);
char *p = oversize;
while (*p && isdigit(p))
p ++;
if (strncasecmp(p, "M", 1) == 0)
strcat(tmp, "M");
else if (strncasecmp(p, "K", 1) == 0)
strcat(tmp, "k");
else if (strncasecmp(p, "G", 1) == 0)
strcat(tmp, "G");
strcat(tmp, "\n");
fputs(tmp, fp);
}
fputs("}", fp);
fclose(fp);
return 0;
}

6
src/log/klog_dump.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef KDK_BASE_LOG_DUMP_H__
#define KDK_BASE_LOG_DUMP_H__
extern int klog_rotate_init(int cid, const char *name, const char *rootpath);
#endif

266
src/log/klog_mqueue.c Normal file
View File

@ -0,0 +1,266 @@
#include "klog_mqueue.h"
#include "writeFile.h"
#include "core.h"
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
int initMessageQueue(int flushInterval , int autoIncrement);
int insertMessage(int lvl , const char *message);
int flushMessageQueue(int locked);
void emptyMessageQueue();
void destroyMessageQueue();
void* startMQDaemon(void* msec);
void recycle() DESTRUCTOR;
static KLMessageQueue* pMQ;
int initMessageQueue(int flushInterval , int autoIncrement)
{
if (pMQ)
return 0;
pMQ = (KLMessageQueue*)calloc(1 , sizeof(KLMessageQueue));
if (!pMQ)
{
return errno;
}
pMQ->interval = flushInterval > 0 ? flushInterval : KLOG_DEFAULT_MSGFLUSHINTERVAL;
pMQ->autoIncrementQueueSize = autoIncrement != 0 ? 1 : 0;
pMQ->mnum = 0;
pMQ->mlock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
if (!pMQ->mlock)
{
printf("消息队列锁分配失败!%s" , strerror(errno));
return errno;
}
pthread_mutex_init(pMQ->mlock , NULL);
pMQ->message = (KL_MessageNode**)calloc(1 , sizeof(KL_MessageNode*) * KLOG_DEFAULT_MSGGROWTH);
if (!pMQ->message)
{
printf("消息缓冲内存申请失败:%s\n" , strerror(errno));
return errno;
}
pMQ->maxmessage = KLOG_DEFAULT_MSGGROWTH;
//创建异步刷新线程
pMQ->thread_id = 0;
pthread_attr_t attr;
pthread_attr_init(&attr);
if (pthread_create(&pMQ->thread_id , &attr , startMQDaemon , &pMQ->interval))
{
printf("异步刷新线程创建失败:%s\n" , strerror(errno));
return errno;
}
return 0;
}
int insertMessage(int lvl , const char *message)
{
if (!pMQ && initMessageQueue(0 , 0))
return errno;
int retv = 0;
//构造MessageNode
KL_MessageNode *node = (KL_MessageNode*)calloc(1 , sizeof(KL_MessageNode));
if (!node)
{
retv = errno;
goto clean_up;
}
node->lvl = lvl;
node->bufSize = strlen(message);
node->bufSize = node->bufSize > sizeof(node->buf) ? sizeof(node->buf) : node->bufSize;
memcpy(node->buf , message , node->bufSize * sizeof(char));
//插入消息队列
MLOCK(pMQ->mlock);
if (__glibc_unlikely(pMQ->mnum >= pMQ->maxmessage)) //当前消息缓冲已满,扩充缓冲区
{
// OUTPUT("缓冲区满\n");
if (pMQ->autoIncrementQueueSize)
{
KL_MessageNode** old = pMQ->message;
unsigned long nextsize = pMQ->maxmessage;
if (nextsize >= KLOG_DEFAULT_MSGGROWTHRESHOLD) //若已达到指定阈值,则降低为缓慢扩充模式
nextsize += KLOG_DEFAULT_MSGGROWTH;
else
{
nextsize <<= 1; //以乘二的速率扩充
}
pMQ->message = (KL_MessageNode**)realloc(pMQ->message , sizeof(KL_MessageNode*) * nextsize);
if (!pMQ->message)
{
char errmsg[1024] = {0};
sprintf(errmsg , "[SYSTEM.emerg]消息队列缓冲扩充失败:%s\n" , strerror(errno));
// OUTPUT("[SYSTEM.emerg]消息队列缓冲扩充失败:%s\n" , strerror(errno));
if (logger->levelBasedStorage)
{
fwrite(errmsg , sizeof(char) , strlen(errmsg) , logger->fp.classfiedfp[KLOG_EMERG]);
fflush(logger->fp.classfiedfp[KLOG_EMERG]);
if (logger->levelBasedContainHigherLevel)
{
for (int i = KLOG_EMERG + 1 ; i < 8 ; i ++)
{
fwrite(errmsg , sizeof(char) , strlen(errmsg) , logger->fp.classfiedfp[i]);
fflush(logger->fp.classfiedfp[i]);
}
}
}
else
{
fwrite(errmsg , sizeof(char) , strlen(errmsg) , logger->fp.commonfp);
fflush(logger->fp.commonfp);
}
pMQ->message = old;
flushMessageQueue(1);
}
else
{
pMQ->maxmessage = nextsize;
// OUTPUT("扩充缓冲至%lu\n" , pMQ->maxmessage);
}
}
else
{
// OUTPUT("缓冲区满,正在刷新缓冲区\n");
flushMessageQueue(1);
}
}
pMQ->message[pMQ->mnum] = node;
pMQ->mnum ++;
MUNLOCK(pMQ->mlock);
clean_up:
return retv;
}
int flushMessageQueue(int locked)
{
if (!pMQ && initMessageQueue(0 , 0))
return errno;
if (!locked)
MLOCK(pMQ->mlock);
unsigned long msgcounts = pMQ->mnum;
if (pMQ->mnum == 0)
{
if (!locked)
MUNLOCK(pMQ->mlock);
return 0;
}
//将整个链表内存拷贝到另一个位置,然后清空原链表
KL_MessageNode** list = pMQ->message;
if (pMQ->autoIncrementQueueSize)
{
pMQ->maxmessage >>= 1; //折半重新开始扩充
pMQ->message = (KL_MessageNode**)calloc(1 , sizeof(KL_MessageNode*) * pMQ->maxmessage);
if (!pMQ->message)
{
char errmsg[1024] = {0};
sprintf(errmsg , "[SYSTEM.emerg]消息队列缩减失败:%s\n" , strerror(errno));
if (logger->levelBasedStorage)
{
fwrite(errmsg , sizeof(char) , strlen(errmsg) , logger->fp.classfiedfp[KLOG_EMERG]);
fflush(logger->fp.classfiedfp[KLOG_EMERG]);
if (logger->levelBasedContainHigherLevel)
{
for (int i = KLOG_EMERG + 1 ; i < 8 ; i ++)
{
fwrite(errmsg , sizeof(char) , strlen(errmsg) , logger->fp.classfiedfp[i]);
fflush(logger->fp.classfiedfp[i]);
}
}
}
else
{
fwrite(errmsg , sizeof(char) , strlen(errmsg) , logger->fp.commonfp);
fflush(logger->fp.commonfp);
}
pMQ->maxmessage = 0;
}
// OUTPUT("消息队列缓冲重置为%lu\n" , pMQ->maxmessage);
}
else
{
pMQ->message = (KL_MessageNode**)calloc(1 , sizeof(KL_MessageNode*) * pMQ->maxmessage);
}
pMQ->mnum = 0;
if (!locked)
MUNLOCK(pMQ->mlock);
//处理拷贝后的内容,逐条写入
KL_MessageNode* node = NULL;
for (unsigned long i = 0 ; i < msgcounts ; i ++)
{
node = list[i];
if (writeFile(node->lvl , node->buf , node->bufSize))
insertMessage(node->lvl , node->buf); //写入不成功的,重新插入队列
free(node);
}
free(list);
if (logger->levelBasedStorage)
{
for (int i = 0 ; i < 8 ; i ++)
fflush(logger->fp.classfiedfp[i]);
}
else
fflush(logger->fp.commonfp);
return 0;
}
void emptyMessageQueue()
{
if (!pMQ)
return;
MLOCK(pMQ->mlock);
for (unsigned long i = 0 ; i < pMQ->mnum ; i ++)
{
free(pMQ->message[i]);
pMQ->message[i] = NULL;
}
pMQ->mnum = 0;
MUNLOCK(pMQ->mlock);
}
void destroyMessageQueue()
{
if (!pMQ)
return;
pthread_cancel(pMQ->thread_id);
pthread_join(pMQ->thread_id ,NULL);
while (pMQ->mnum)
{
flushMessageQueue(0);
}
pthread_mutex_destroy(pMQ->mlock);
free(pMQ->mlock);
free(pMQ);
pMQ = NULL;
}
void recycle()
{
destroyMessageQueue();
}
void* startMQDaemon(void* msec)
{
int interval = *(int*)msec;
while (1)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE , NULL);
pthread_testcancel();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE , NULL);
usleep(interval * 1000);
flushMessageQueue(0);
}
}

29
src/log/klog_mqueue.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef __KLOG_MQ_H__
#define __KLOG_MQ_H__
#include "core.h"
#include <pthread.h>
#include <stdbool.h>
typedef struct _KL_MessageNode{
int lvl;
unsigned int bufSize;
char buf[KLOG_MAXMSGSIZE];
}KL_MessageNode;
typedef struct _KL_MessageQueue{
pthread_mutex_t* mlock; //用于在操作队列时锁定
int autoIncrementQueueSize; //是否自动扩充消息队列
unsigned long maxmessage; //当前最大可接受消息数量该数量超限后会以每次KLOG_DEFAULT_MSGGROWTH的数量扩充
unsigned long mnum; //队列中消息的数量
pthread_t thread_id; //后台刷新线程ID
int interval; //刷新间隔
KL_MessageNode** message; //消息缓冲
}KLMessageQueue;
extern int initMessageQueue(int flushInterval , int autoIncrement);
extern int insertMessage(int lvl , const char *message);
extern int flushMessageQueue(int locked);
extern void emptyMessageQueue();
extern void destroyMessageQueue();
#endif

View File

@ -0,0 +1,44 @@
[TYPE]
#日志标识有user、Local3等类型也可以自定义但自定义只能使用specfile的输出模式
identifier=user
#写入方式有SYNC和ASYNC两种
synctype=sync
#日志输出位置有syslog、specfile、stdout三种目前syslog还未支持
output=specfile
[CUSTOM]
logLevel=7
#当日志输出位置为specfile时可以指定输出名称若不指定则使用“进程名.log”作为日志名称。日志均保存在~/.log下
specName=
#日志按照等级分类存储
levelBasedStorage=0
#当按照等级分类存储时低优先级日志是否需要包含高优先级日志logLevel数字越小优先级越高。这会显著的降低写入效率
levelBasedContainHigherLevel=1
[FORMAT]
#输出中是否包含日志类型
f_identifier=1
#输出中是否包含进程名称
f_processname=0
#输出中是否包含PID号
f_pid=1
#输出中是否包含TID号
f_tid=0
#输出中是否包含日志所在的源码文件名称
f_filename=0
#输出中是否包含日志所在的函数与行信息
f_funcline=0
[MSGQUEUE]
#异步模式下的消息刷新频率,单位毫秒
flushInterval=100
#是否自动扩充消息队列(若写入速率极高,自动扩充会占用大量内存)
autoIncrementQueueSize=0
[DUMP]
#转储规则取值有daily(每日转储)weekly(每周转储)size(按大小转储)none不转储
rules=daily
#当转储规则为按大小转储时转储阈值设置。支持GB、MB、KB的写法若不加后缀则默认是以B为单位
thresholdAsSizeRules=1GB
#转储后是否需要压缩1表示需要压缩
compress=1

View File

@ -0,0 +1 @@
include /etc/kysdk/kysdk-base/logrotate.d

87
src/log/libkylog.c Normal file
View File

@ -0,0 +1,87 @@
#include "libkylog.h"
#include "klog_mqueue.h"
#include "write.h"
#include "format.h"
#include "core.h"
#include <libkyconf.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
int kdk_logger_init(const char *ini)
{
int retv = 0;
if (!ini)
{
ini = "/etc/kysdk/kysdk-base/kylog-default.conf";
}
int confid = kdk_conf_init(ini);
if (confid <= 0)
{
printf("%s配置文件加载失败\n", ini);
retv = -1;
goto clean_up;
}
loadFormatOptions(confid);
retv = initKLogger(confid);
if (retv)
{
printf("kdk_logger初始化失败%d\n" , retv);
goto clean_up;
}
if (logger->otype == OUT_SPECFILE && logger->stype == ASYNC)
{
retv = initMessageQueue(atoi(kdk_conf_get_value(confid, "MSGQUEUE" , "flushInterval")) , atoi(kdk_conf_get_value(confid, "MSGQUEUE" , "autoIncrementQueueSize")));
if (retv)
{
printf("消息队列初始化失败!%d\n" , retv);
goto clean_up;
}
}
clean_up:
return retv;
}
int kdk_logger_setdir(const char* dpath)
{
return setRootDir(dpath);
}
int kdk_logger_write(int lvl , const char *filename , const char *func , int linenum , const char *fmt , ...)
{
if (!logger && kdk_logger_init(NULL))
{
printf("kdk_logger尚未初始化\n");
return -1;
}
if (lvl > logger->level)
return 0;
char message[KLOG_MAXMSGSIZE + 1] = {0};
va_list vl;
va_start(vl , fmt);
vsnprintf(message , sizeof(char) * KLOG_MAXMSGSIZE , fmt , vl);
va_end(vl);
append_wrap(message);
return writeLog(lvl , filename , func , linenum , message);
}
void kdk_logger_flush()
{
if (!logger)
{
return;
}
if (logger->stype == ASYNC)
flushMessageQueue(0);
}
void kdk_logger_set_autowrap(int autowrap)
{
set_autowrap(autowrap);
}

153
src/log/libkylog.h Normal file
View File

@ -0,0 +1,153 @@
#ifndef KYSDK_BASE_LOG_H__
#define KYSDK_BASE_LOG_H__
/** @defgroup 日志模块
* @{
*/
/**
* @file libkylog.h
* @author liuyunhe (liuyunhe@kylinos.cn)
* @brief KYSDK日志模块
* @version 0.1
* @date 2021-10-28
*
* @copyright Copyright (c) 2021
*
*/
#include <sdkmarcos.h>
#define KLOG_TRACE 8
#define KLOG_DEBUG 7
#define KLOG_INFO 6
#define KLOG_NOTICE 5
#define KLOG_WARNING 4
#define KLOG_ERROR 3
#define KLOG_CRIT 2
#define KLOG_ALERT 1
#define KLOG_EMERG 0
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief
*
*/
#define klog_trace(fmt , ...) (klog(KLOG_TRACE , fmt , ##__VA_ARGS__))
/**
* @brief debug级别日志
*
*/
#define klog_debug(fmt , ...) (klog(KLOG_DEBUG , fmt , ##__VA_ARGS__))
/**
* @brief info级别日志
*
*/
#define klog_info(fmt , ...) (klog(KLOG_INFO , fmt , ##__VA_ARGS__))
/**
* @brief notice级别日志
*
*/
#define klog_notice(fmt , ...) (klog(KLOG_NOTICE , fmt , ##__VA_ARGS__))
/**
* @brief warning级别日志
*
*/
#define klog_warning(fmt , ...) (klog(KLOG_WARNING , fmt , ##__VA_ARGS__))
/**
* @brief error级别日志
*
*/
#define klog_err(fmt , ...) (klog(KLOG_ERROR , fmt , ##__VA_ARGS__))
/**
* @brief crit级别日志
*
*/
#define klog_crit(fmt , ...) (klog(KLOG_CRIT , fmt , ##__VA_ARGS__))
/**
* @brief alert级别日志
*
*/
#define klog_alert(fmt , ...) (klog(KLOG_ALERT , fmt , ##__VA_ARGS__))
/**
* @brief emerg级别日志
*
*/
#define klog_emerg(fmt , ...) (klog(KLOG_EMERG , fmt , ##__VA_ARGS__))
#ifndef NOCALLTRACE
#define klog_calltrace() (klog_trace("[CALLTRACE]Enter %s\n" , __FUNCTION__))
#else
#define klog_calltrace()
#endif
/**
* @brief 使
*
*/
#define klog(lvl , fmt , ...) kdk_logger_write(lvl , __FILE__ , __FUNCTION__ , __LINE__ , fmt , ##__VA_ARGS__)
/**
* @brief 使使
*
* @param iniNULL则会使用默认的日志配置文件
* @return int00
*/
extern int kdk_logger_init(const char *ini);
/**
* @brief
*
*/
extern void kdk_logger_flush() DESTRUCTOR; //当使用异步日志记录方式时,该函数可以手动将日志刷新到文件中
/**
* @brief 使
*
*/
extern int kdk_logger_write(int lvl , const char *filename , const char *func , int linenum , const char *fmt , ...) NOTNULL() CHECK_FMT(5 , 6);
/**
* @brief root程序会被记录在~/.log下root程序会被记录在/var/log下
*
* @param dpath
* @return int
*/
extern int kdk_logger_setdir(const char* dpath);
/**
* @brief
*
* @param autowarp 10
*/
extern void kdk_logger_set_autowrap(int autowarp);
#ifdef __cplusplus
}
#endif
#endif
/**
* \example kysdk-base/src/log/test/test-log.c
* \example kysdk-base/src/log/test/test-pressure.c
* \example kysdk-base/src/log/test/test-setdir.c
*/
/**
* @}
*/

2
src/log/logrotate.cron Normal file
View File

@ -0,0 +1,2 @@
00 0 * * * /usr/bin/logrotate -s /tmp/kylog-rotate-tmp /etc/kysdk/kysdk-base/kylog-rotate-default

7
src/log/test/Makefile Normal file
View File

@ -0,0 +1,7 @@
all:
gcc -o test-log test-log.c -g -O0 -I../ -I../../utils/ -L../lib -L../../config/lib/ -lkylog -lkyconf -lpthread -lsystemd -Wl,-rpath=../lib:../../config/lib/
gcc -o test-setdir test-setdir.c -g -O0 -I../ -I../../utils/ -L../lib -L../../config/lib/ -lkylog -lkyconf -lpthread -lsystemd -Wl,-rpath=../lib:../../config/lib/
gcc -o test-pressure test-pressure.c -g -O0 -I../ -I../../utils/ -L../lib -L../../config/lib/ -lkylog -lkyconf -lpthread -lsystemd -Wl,-rpath=../lib:../../config/lib/
clean:
-rm test-log test-setdir test-pressure

39
src/log/test/checkmiss.sh Executable file
View File

@ -0,0 +1,39 @@
#!/bin/bash
function testmiss ()
{
let count=1
oldIFS=${IFS}
IFS=$'\n'
let missline=0
let flag=0
for line in `cat $1`;do
value=`echo ${line} | awk '{print $NF}'`
while [ ${value} -ne ${count} ];do
echo "missing ${count}" >> /tmp/logtest-missing-${TID[${index} - 1]}.rec
echo "TID - ${TID[${index} - 1]} : ${count} missmatch with ${count}"
((count ++))
((missline ++))
done
if [ $flag -eq 0 ];then
echo ""
((flag ++))
fi
printf "\rTID - ${TID[${index} - 1]} : ${count} matched."
((count ++))
done
return missline
}
LOGFILE=/home/kylin/.log/test-pressure.log
TID=(`awk -F '[]-]' '{print $5}' ${LOGFILE} | sort -n | uniq`)
oldIFS=${IFS}
for index in `seq ${#TID[@]}`;do
grep ${TID[${index} - 1]} ${LOGFILE} > /tmp/logtest-${TID[${index} - 1]}.log
testmiss "/tmp/logtest-${TID[${index} - 1]}.log" &
done
wait

44
src/log/test/logtest.conf Normal file
View File

@ -0,0 +1,44 @@
[TYPE]
#日志标识有User、Local3等类型也可以自定义字符串但自定义只能使用specfile的输出模式
identifier=test
#写入方式有SYNC和ASYNC两种
synctype=async
#日志输出位置有syslog、specfile、stdout三种
output=specfile
[CUSTOM]
logLevel=7
#当日志输出位置为specfile时可以指定输出名称若不指定则使用“进程名.log”作为日志名称。日志均保存在/var/log/下
specName=
#日志按照等级分类存储
levelBasedStorage=0
#当按照等级分类存储时低优先级日志是否需要包含高优先级日志logLevel数字越小优先级越高。这会显著的降低写入效率
levelBasedContainHigherLevel=1
[FORMAT]
#输出中是否包含日志类型
f_identifier=1
#输出中是否包含进程名称
f_processname=1
#输出中是否包含PID号
f_pid=1
#输出中是否包含TID号
f_tid=1
#输出中是否包含日志所在的源码文件名称
f_filename=1
#输出中是否包含日志所在的函数与行信息
f_funcline=1
[MSGQUEUE]
#异步模式下的消息刷新频率,单位毫秒
flushInterval=100
#是否自动扩充消息队列(若写入速率极高,自动扩充会占用大量内存)
autoIncrementQueueSize=0
[DUMP]
#转储规则取值有daily(每日转储)size(按大小转储)
rules=daily
#当转储规则为按大小转储时转储阈值设置。支持GB、MB、KB的写法若不加后缀则默认是以B为单位
thresholdAsSizeRules=1GB
#转储后是否需要压缩1表示需要压缩
compress=1

View File

@ -0,0 +1,19 @@
#include <libkylog.h>
#include <assert.h>
int main(int argc , char** argv)
{
assert(kdk_logger_init("./logtest.conf") == 0);
kdk_logger_set_autowrap(1);
klog_calltrace();
klog_debug("Debug");
klog_info("Info");
klog_notice("Notice");
klog_warning("Warning");
klog_err("Error");
klog_crit("Crit");
klog_alert("Alert");
klog_emerg("Emerg");
return 0;
}

19
src/log/test/test-log.c Normal file
View File

@ -0,0 +1,19 @@
#include <libkylog.h>
#include <assert.h>
int main(int argc , char** argv)
{
assert(kdk_logger_init("./logtest.conf") == 0);
klog_calltrace();
klog_debug("Debug\n");
klog_info("Info\n");
klog_notice("Notice\n");
klog_warning("Warning\n");
klog_err("Error\n");
klog_crit("Crit\n");
klog_alert("Alert\n");
klog_emerg("Emerg\n");
return 0;
}

View File

@ -0,0 +1,101 @@
#include <libkylog.h>
#include <time.h>
#include <sys/time.h>
#include <signal.h>
#include <assert.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int stop = 0;
int start = 0;
pthread_mutex_t lock;
unsigned int counts = 0;
void stopHandler(int sig)
{
stop = 1;
}
void startTimer()
{
alarm(10);
}
void* startlog(void* arg)
{
while (!start);
unsigned int count = 0;
srand(time(NULL));
while (!stop)
{
int lvl = rand() % 8;
switch (lvl)
{
case 0 :{
assert(klog_emerg("this is emerg count %d\n" , ++ count) == 0);
}break;
case 1 : {
assert(klog_alert("this is alert count %d\n" , ++ count) == 0);
}break;
case 2:{
assert(klog_crit("this is crit count %d\n" , ++ count) == 0);
}break;
case 3:{
assert(klog_err("this is err count %d\n" , ++ count) == 0);
}break;
case 4:{
assert(klog_warning("this is warning count %d\n" , ++ count) == 0);
}break;
case 5:{
assert(klog_notice("this is notice count %d\n" , ++ count) == 0);
}break;
case 6:{
assert(klog_info("this is info count %d\n" , ++ count) == 0);
}break;
case 7:{
assert(klog_debug("this is debug count %d\n" , ++ count) == 0);
}break;
}
}
pthread_mutex_lock(&lock);
counts += count;
pthread_mutex_unlock(&lock);
printf("共写入%d条日志\n" , count);
return NULL;
}
int main(int argc , char** argv)
{
assert(kdk_logger_init("./logtest.conf") == 0);
// //越界测试
// char msg[4096];
// memset(msg , 'F' , sizeof(char) * 4096);
// klog_debug(msg);
//压力测试
signal(SIGALRM, stopHandler);
pthread_mutex_init(&lock, NULL);
pthread_t children[7] = {0};
for (int i = 0; i < 7; i++)
{
pthread_create(&children[i], NULL, startlog, NULL);
}
start = 1;
startTimer();
for (int i = 0; i < 7; i++)
{
pthread_join(children[i], NULL);
}
kdk_logger_flush();
pthread_mutex_lock(&lock);
printf("所有线程写入总量:%u\n", counts);
pthread_mutex_unlock(&lock);
return system("cat /var/log/logtest.log | wc -l");
}

View File

@ -0,0 +1,21 @@
#include <libkylog.h>
#include <assert.h>
int main(int argc , char** argv)
{
assert(kdk_logger_init("./logtest.conf") == 0);
assert(kdk_logger_setdir("/tmp") == 0);
klog_calltrace();
klog_debug("Debug\n");
klog_info("Info\n");
klog_notice("Notice\n");
klog_warning("Warning\n");
klog_err("Error\n");
klog_crit("Crit\n");
klog_alert("Alert\n");
klog_emerg("Emerg\n");
return 0;
}

66
src/log/write.c Normal file
View File

@ -0,0 +1,66 @@
#include "write.h"
#include "klog_mqueue.h"
#include "writeFile.h"
#include <stdarg.h>
#include <errno.h>
#include <syslog.h>
#include <systemd/sd-journal.h>
static inline void writeSyslog(int lvl , const char *message)
{
#ifndef __loongarch__
sd_journal_send("MESSAGE=%s", message , "PRIORITY=%i" , lvl ,\
"SYSLOG_FACILITY=%i" , 19 , NULL);
#else
// TODO: loongarch64 's syslog write
return;
#endif
}
static int writeSpecFile(int lvl , const char *filename , const char *func , int linenum , const char *message)
{
char buffer[KLOG_MAXMSGSIZE + 1] = {0};
formatMessage(lvl , filename , func , linenum , message , buffer , KLOG_MAXMSGSIZE);
if (logger->stype == SYNC)
{
if (logger->levelBasedStorage)
return writeFile(lvl , buffer , strlen(buffer)) || fflush(logger->fp.classfiedfp[lvl]);
else
return writeFile(lvl , buffer , strlen(buffer)) || fflush(logger->fp.commonfp);
}
else
{
insertMessage(lvl , buffer);
}
return 0;
}
static void writeStdout(int lvl , const char *filename , const char *func , int linenum , const char *message)
{
char buffer[KLOG_MAXMSGSIZE + 1] = {0};
formatMessage(lvl , filename , func , linenum , message , buffer , KLOG_MAXMSGSIZE);
fprintf(stdout , "%s" , buffer);
}
int writeLog(int lvl , const char *filename , const char *func , int linenum , const char *message)
{
switch (logger->otype)
{
case OUT_SYSLOG:
{
writeSyslog(lvl , message);
}break;
case OUT_SPECFILE:{
writeSpecFile(lvl , filename , func , linenum , message);
}break;
case OUT_STDOUT:{
writeStdout(lvl , filename , func , linenum , message);
}break;
default:{
printf("输出类别无效!%d\n" , logger->otype);
return EINVAL;
}break;
}
return 0;
}

8
src/log/write.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __KLOG_WRITE_H__
#define __KLOG_WRITE_H__
#include "format.h"
#include "core.h"
extern int writeLog(int lvl , const char *filename , const char *func , int linenum , const char *message) NOTNULL();
#endif

64
src/log/writeFile.c Normal file
View File

@ -0,0 +1,64 @@
#include "writeFile.h"
#include "core.h"
#include <errno.h>
#include <string.h>
#include <stdio.h>
int writeFile(int lvl , const char *message , unsigned int len)
{
if (logger->levelBasedStorage)
{
if (!logger->fp.classfiedfp[lvl])
{
logger->fp.classfiedfp[lvl] = fopen(logger->logfileName.classfiedfileName[lvl] , "at");
if (!logger->fp.classfiedfp[lvl])
{
printf("无法打开日志文件%s%s\n" , logger->logfileName.classfiedfileName[lvl] , strerror(errno));
return errno;
}
}
if (fwrite(message , sizeof(char) , len , logger->fp.classfiedfp[lvl]) < len)
{
printf("日志写入错误,%s\n" , strerror(errno));
return errno;
}
if (logger->levelBasedContainHigherLevel) //当要求低优先级日志需要包含更高优先级的日志时,逐个写入日志文件
{
for (int i = lvl + 1 ; i < 8 ; i ++)
{
if (!logger->fp.classfiedfp[i])
{
logger->fp.classfiedfp[i] = fopen(logger->logfileName.classfiedfileName[i] , "at");
if (!logger->fp.classfiedfp[i])
{
printf("无法打开日志文件%s%s\n" , logger->logfileName.classfiedfileName[i] , strerror(errno));
continue;
}
}
if (fwrite(message , sizeof(char) , len , logger->fp.classfiedfp[i]) < len)
{
printf("日志写入错误,%s\n" , strerror(errno));
return errno;
}
}
}
}
else
{
if (!logger->fp.commonfp)
{
logger->fp.commonfp = fopen(logger->logfileName.commonlogfileName , "at");
if (!logger->fp.commonfp)
{
printf("无法打开日志文件:%s\n" , strerror(errno));
return errno;
}
}
if (fwrite(message , sizeof(char) , len , logger->fp.commonfp) < len)
{
printf("日志写入错误,%s\n" , strerror(errno));
return errno;
}
}
return 0;
}

7
src/log/writeFile.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef __KLOG_WRITEFILE_H__
#define __KLOG_WRITEFILE_H__
#include <sdkmarcos.h>
extern int writeFile(int lvl , const char *message , unsigned int len) NOTNULL();
#endif

View File

@ -0,0 +1,115 @@
#include "processdaemon.h"
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <limits.h>
namespace KYSDK_BASE {
static int g_dogID;
static char g_pipeName[64]; //管道名称
static void daemon(unsigned int interval, daemon_callback func, void* args)
{
static int pipefd = open(g_pipeName, O_RDONLY);
if (pipefd <= 0)
return;
fd_set read_fds, write_fds, except_fds;
while (1)
{
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&except_fds);
FD_SET(pipefd, &read_fds);
struct timeval timeout;
timeout.tv_sec = interval;
timeout.tv_usec = 0;
char buf[24];
if (select(pipefd + 1, &read_fds, &write_fds, &except_fds, &timeout) > 0)
{
read(pipefd, buf, sizeof(buf));
printf("got %s\n", buf);
if (strcmp(buf, "quit") == 0)
break;
continue;
}
else
{
// timeout
if (func)
func(args);
}
}
close(pipefd);
}
int startProcDaemon(unsigned int interval, daemon_callback func, void* args)
{
if (g_dogID > 0)
return -1;
sprintf(g_pipeName, "/tmp/pipe_procdaemon_%d", getpid());
if (mkfifo(g_pipeName, 0770) < 0)
return -2;
pid_t pid = fork();
if (pid == 0)
{
g_dogID = pid;
daemon(interval, func, args);
exit(0);
}
return 0;
}
void feedDog()
{
static int pipefd = open(g_pipeName, O_RDWR);
if (pipefd <= 0)
return;
static unsigned long feedCounts = 0;
char buf[24];
sprintf(buf, "%023lu", feedCounts);
write(pipefd, buf, sizeof(buf));
feedCounts ++;
}
int stopProcDaemon()
{
if (g_dogID <= 0)
return -1;
int pipefd = open(g_pipeName, O_RDWR);
if (pipefd <= 0)
return -1;
char buf[24] = {0};
strcpy(buf, "quit");
write(pipefd, buf, sizeof(buf));
close(pipefd);
int status;
waitpid(g_dogID, &status, 0);
g_dogID = 0;
remove(g_pipeName);
printf("dog quit.\n");
return 0;
}
}

View File

@ -0,0 +1,17 @@
#ifndef KYSDK_BASE_PROCESSDAEMON_H__
#define KYSDK_BASE_PROCESSDAEMON_H__
namespace KYSDK_BASE
{
typedef void (*daemon_callback)(void *args);
extern int startProcDaemon(unsigned int interval, daemon_callback func, void* args);
extern void feedDog();
extern int stopProcDaemon();
} // namespace KYSDK_BASE
#endif
/**
* \example kysdk-base/src/process/test/main.cpp
*
*/

View File

@ -0,0 +1,9 @@
CXXFLAGS += -g -O0 --std=c++11 -I../
VPATH=../:./
all:processdaemon.o
g++ -o processdaemon $(CXXFLAGS) main.cpp ../processdaemon.cpp
.PHONY:processdaemon.o
processdaemon.o:processdaemon.cpp
g++ -c -o processdaemon.o $(CXXFLAGS) ../processdaemon.cpp

32
src/process/test/main.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "processdaemon.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
int quit;
void func(void* data)
{
printf("dog fake.\n");
quit = 1;
KYSDK_BASE::stopProcDaemon();
}
int main()
{
KYSDK_BASE::startProcDaemon(5, func, NULL);
int counts = 0;
srand(time(NULL));
while (!quit)
{
int stime = rand() % 7;
printf("sleep %d\n", stime);
sleep(stime);
KYSDK_BASE::feedDog();
}
printf("quit.\n");
KYSDK_BASE::stopProcDaemon();
return 0;
}

11
src/timer/CMakeLists.txt Normal file
View File

@ -0,0 +1,11 @@
aux_source_directory(. SOURCESCODE)
add_library(kytimer SHARED ${SOURCESCODE})
add_executable(test-kytimer test/test-kytimer.c)
target_link_libraries(kytimer pthread)
target_link_libraries(test-kytimer kytimer)
install(TARGETS kytimer
DESTINATION lib/kysdk/kysdk-base)
# install(FILES libkytimer.h
# DESTINATION include/kysdk/kysdk-base)

26
src/timer/Makefile Normal file
View File

@ -0,0 +1,26 @@
CLIBS=-lpthread -lrt
CFLAGS=-g -O0 -Wall -fPIC -shared
CC=cc
TARGET=libkytimer.so
LIBINSTALLNAME=libkytimer.so.1.0.0
LIBINSTALLDIR=/usr/lib/
HEADERINSTALLDIR=/usr/include/
HEADERS=kytimer.h
.PHONY:all
.PHONY:clean
.PHONY:lib
all:lib
lib:
$(CC) $(CFLAGS) $(CLIBS) -o $(TARGET) libkytimer.c
mkdir -p lib/
mv $(TARGET) lib/$(LIBINSTALLNAME)
clean:
-rm ../lib/$(LIBINSTALLNAME)
target_install:TARGET
cp $(LIBINSTALLNAME) $(LIBINSTALLDIR)

362
src/timer/libkytimer.c Normal file
View File

@ -0,0 +1,362 @@
#include <stdio.h>
#include <string.h>
#include <sys/timerfd.h>
#include <time.h>
#include <pthread.h>
#include <stdint.h>
#include <poll.h>
#include <errno.h>
#include <unistd.h>
#include <sys/epoll.h>
#include "libkytimer.h"
#include <sdkmarcos.h>
static void* timerCoreThread(void* data); //定时器循环核心
static KTimerNode* findNodeByFD(unsigned int fd); //根据fd查找节点
static KTimerNode* newTimerNode();
static void freeTimerNode(KTimerNode* node);
static int testNodeInList(KTimerNode* node);
static void insertIntoList(KTimerNode* node); //插入节点,按照间隔时间的顺序从小到大排序
static void deleteFromList(KTimerNode* node , int locked); //从链表中删除节点
static pthread_t g_coreThreadID; //核心循环线程
static KTimerNode* g_list = NULL;
static int epollfd; //事件池句柄
static int curTimerCounts; //当前已注册定时器数量
int kdk_timer_init(); //初始化定时器核心
size_t kdk_timer_start(unsigned int intervalms, time_handler callback, KTimerAttribute attr, KTimerType type, void* userdata, int freeOnDelete); //注册并开始一个定时器,返回定时器句柄号
void kdk_timer_stop(size_t timerfd); //停止一个定时器
void kdk_timer_reset(size_t timerfd , unsigned int intervalms);
void kdk_timer_destroy() DESTRUCTOR; //销毁定时器核心
#ifndef TFD_TIMER_CANCEL_ON_SET
#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
#endif
int kdk_timer_init()
{
if (g_coreThreadID > 0)
return 0;
epollfd = epoll_create1(EPOLL_CLOEXEC);
if (epollfd <= 0)
{
printf("Epoll事件池创建失败%s\n" , strerror(errno));
return errno;
}
if (pthread_create(&g_coreThreadID , NULL , timerCoreThread , NULL))
{
printf("kyTimer 定时器核心初始化失败:%s\n" , strerror(errno));
return errno;
}
return 0;
}
size_t kdk_timer_start(unsigned int intervalms, time_handler callback, KTimerAttribute attr, KTimerType type, void* userdata, int freeOnDelete)
{
if (g_coreThreadID <= 0 && kdk_timer_init())
{
printf("定时器注册失败:定时器全局句柄初始化失败!\n");
return 0;
}
if (curTimerCounts >= KTIMER_MAXTIMERFD)
{
printf("定时器注册失败:定时器注册数量已超限!\n");
return 0;
}
KTimerNode* node = newTimerNode();
if (!node)
{
printf("定时器注册失败:无法分配内存,%s\n" , strerror(errno));
return 0;
}
node->callback = callback;
node->userdata = userdata;
node->intervalms = intervalms;
node->attr = attr;
node->type = type;
node->freeOnDelete = freeOnDelete;
if (type == KTIMER_ABSOLUTE)
node->fd = timerfd_create(CLOCK_MONOTONIC , TFD_CLOEXEC|TFD_NONBLOCK);
else
node->fd = timerfd_create(CLOCK_REALTIME , TFD_CLOEXEC|TFD_NONBLOCK);
if ((int)node->fd <= 0)
{
printf("定时器注册失败timerfd_create失败%s\n" , strerror(errno));
freeTimerNode(node);
return 0;
}
struct itimerspec tval;
tval.it_value.tv_sec = intervalms / 1000;
tval.it_value.tv_nsec = (intervalms % 1000) * 1000000;
if (attr == KTIMER_PERIODIC) //多次触发时设置interval项
{
tval.it_interval.tv_sec = tval.it_value.tv_sec;
tval.it_interval.tv_nsec = tval.it_value.tv_nsec;
}
else
{
tval.it_interval.tv_sec = 0;
tval.it_interval.tv_nsec = 0;
}
timerfd_settime(node->fd, 0, &tval, NULL);
//注册到Epoll池中
struct epoll_event ev;
memset(&ev , 0 , sizeof(struct epoll_event));
if (attr == KTIMER_SINGLESHOT)
ev.events = EPOLLIN | EPOLLONESHOT;
else
ev.events = EPOLLIN;
ev.data.ptr = node;
if (epoll_ctl(epollfd , EPOLL_CTL_ADD , node->fd , &ev))
{
printf("定时器注册失败epoll_ctl错误%s\n" , strerror(errno));
freeTimerNode(node);
return 0;
}
insertIntoList(node);
return node->fd;
}
//停止一个定时器,并从列表中移除
void kdk_timer_stop(size_t timerfd)
{
if (timerfd <= 0)
return;
KTimerNode* node = findNodeByFD(timerfd);
if (node)
{
if (epoll_ctl(epollfd , EPOLL_CTL_DEL , timerfd , NULL))
{
printf("无法注销文件句柄%zd : %s\n" , timerfd , strerror(errno));
return;
}
deleteFromList(node , 0);
}
return;
}
//定时器核心线程,负责循环处理已到期的定时器
static void* timerCoreThread(void* data)
{
pthread_detach(pthread_self());
KTimerNode* knode = NULL;
int read_fds = 0;
while (1)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE , NULL);
pthread_testcancel();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE , NULL);
struct epoll_event activeEvs[KTIMER_MAXTIMERFD];
read_fds = epoll_wait(epollfd , activeEvs , KTIMER_MAXTIMERFD , -1);
if (read_fds < 0)
{
printf("epoll wait error , %s\n" , strerror(errno));
continue;
}
for (int i = 0 ; i < read_fds ; i ++)
{
knode = activeEvs[i].data.ptr;
pthread_mutex_lock(&knode->lock);
if (!testNodeInList(knode))
continue;
uint64_t dep;
size_t rd = read(knode->fd , &dep , sizeof(uint64_t));
if (rd <= 0)
continue;
if (knode && knode->attr != KTIMER_NEVER && knode->callback)
{
#if 1
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr , PTHREAD_CREATE_DETACHED);
pthread_create(&tid , &attr , knode->callback , knode->userdata);
knode->freeOnDelete = 0;
#else
knode->callback(knode->userdata);
#endif
}
if (knode->attr == KTIMER_SINGLESHOT) //单次触发的在触发后就从链表中移除
{
// FixMe: 如果设置了freeOnDelete并且采用上面的线程执行模式
// 则会发生段错误。因此只能在启用线程执行模式的时候强制禁止
// freeOnDelete。
deleteFromList(knode , 1);
}
if (testNodeInList(knode))
pthread_mutex_unlock(&knode->lock);
}
}
return NULL;
}
static KTimerNode* findNodeByFD(unsigned int fd)
{
KTimerNode* tmp = g_list;
while (tmp)
{
if (tmp->fd == fd)
return tmp;
tmp = tmp->next;
}
return NULL;
}
static int testNodeInList(KTimerNode* node)
{
KTimerNode* pos = g_list;
while (pos)
{
if (pos == node)
return 1;
pos = pos->next;
}
return 0;
}
static void insertIntoList(KTimerNode* node)
{
curTimerCounts ++;
if (!g_list)
{
g_list = node;
}
else
{
if (g_list->intervalms > node->intervalms)
{
node->next = g_list;
g_list = node;
return;
}
KTimerNode* cur = g_list->next;
KTimerNode* prev = g_list;
while (cur)
{
if (cur->intervalms > node->intervalms)
{
node->next = cur;
prev->next = node;
return;
}
prev = cur;
cur = cur->next;
}
prev->next = node;
node->next = NULL;
}
return;
}
static void deleteFromList(KTimerNode* node , int locked)
{
if (!g_list)
return;
curTimerCounts --;
if (!locked)
pthread_mutex_lock(&node->lock);
if (node == g_list)
{
g_list = g_list->next;
freeTimerNode(node);
return;
}
KTimerNode* pos = g_list;
while (pos)
{
if (pos->next && pos->next == node)
{
pos->next = pos->next->next;
freeTimerNode(node);
return;
}
pos = pos->next;
}
return;
}
static KTimerNode* newTimerNode()
{
KTimerNode *node = (KTimerNode*)calloc(1 , sizeof(KTimerNode));
if (!node)
return NULL;
pthread_mutex_init(&node->lock , NULL);
return node;
}
static void freeTimerNode(KTimerNode *node)
{
if (! node)
return;
if (node->fd > 0)
close(node->fd);
if (node->userdata && node->freeOnDelete)
free(node->userdata);
free(node);
}
void kdk_timer_reset(size_t timerfd , unsigned int intervalms)
{
KTimerNode* node = findNodeByFD(timerfd);
if (!node)
return;
node->intervalms = intervalms;
struct itimerspec tval;
tval.it_value.tv_sec = intervalms / 1000;
tval.it_value.tv_nsec = (intervalms % 1000) * 1000000;
if (node->attr == KTIMER_PERIODIC) //多次触发时设置interval项
{
tval.it_interval.tv_sec = tval.it_value.tv_sec;
tval.it_interval.tv_nsec = tval.it_value.tv_nsec;
}
else
{
tval.it_interval.tv_sec = 0;
tval.it_interval.tv_nsec = 0;
}
timerfd_settime(timerfd , 0 , &tval , NULL);
return;
}
void kdk_timer_destroy() //停止所有定时器,并销毁定时器核心
{
//终止线程运行
if (g_coreThreadID > 0)
pthread_cancel(g_coreThreadID);
//销毁链表
KTimerNode* node = g_list;
while (node)
{
deleteFromList(node , 0);
node = g_list;
}
//关闭epoll池
if (epollfd > 0)
close(epollfd);
return;
}

111
src/timer/libkytimer.h Normal file
View File

@ -0,0 +1,111 @@
#ifndef KYSDK_BASE_TIMER_H__
#define KYSDK_BASE_TIMER_H__
/** @defgroup 定时器模块
* @{
*/
/**
* @file libkytimer.h
* @author liuyunhe (liuyunhe@kylinos.cn)
* @brief KYSDK C语言定时器模块
* @version 0.1
* @date 2021-10-28
*
* @copyright Copyright (c) 2021
*
*/
#include <stdlib.h>
#include <pthread.h>
typedef enum
{
KTIMER_SINGLESHOT = 0,
KTIMER_PERIODIC = 1,
KTIMER_NEVER = 2
}KTimerAttribute;
typedef enum
{
KTIMER_ABSOLUTE = 0,
KTIMER_RELATIVE
}KTimerType;
#define KTIMER_MAXTIMERFD 1000 //最多支持注册1000个定时器
typedef void* (*time_handler)(void* user_data); //回调函数规则
typedef struct _KTimerNode{
pthread_mutex_t lock;
size_t fd; //序列号
time_handler callback; //到期后执行的函数
int freeOnDelete; //删除定时器时自动释放userdata
void* userdata; //callback使用的参数外部使用alloc分配内存在delete定时器的时候会根据配置自动释放
unsigned int intervalms; //定时器间隔时间,单位毫秒
KTimerAttribute attr; //触发类型,单次触发或多次触发
KTimerType type; //时钟类型,绝对时间还是相对时间
struct _KTimerNode* next;
}KTimerNode;
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief
*
* @return int 0
*/
extern int kdk_timer_init();
/**
* @brief
*
* @param intervalms
* @param callback
* @param attr KTIMER_SINGLESHOT表示一次性定时器KTIMER_PERIODIC表示周期性定时器KTIMER_NEVER表示不会被触发的定时器
* @param type KTIMER_ABSOLUTE表示绝对时间定时器KTIMER_RELATIVE表示相对时间定时器
* @param userdata
* @param freeOnDelete []
* @return size_t ID
*/
extern size_t kdk_timer_start(unsigned int intervalms, time_handler callback, KTimerAttribute attr, KTimerType type, void* userdata, int freeOnDelete);
/**
* @brief
*
* @param timerfd kdk_timer_start返回的定时器ID
*/
extern void kdk_timer_stop(size_t timerfd);
/**
* @brief intervalms
*
* @param timerfd kdk_timer_start返回的定时器ID
* @param intervalms ms为单位
*/
extern void kdk_timer_reset(size_t timerfd , unsigned int intervalms);
/**
* @brief
*
*/
extern void kdk_timer_destroy();
#ifdef __cplusplus
}
#endif
#endif //KYSDK_BASE_TIMER_H__
/**
* \example kysdk-base/src/timer/test/test-kytimer.c
*
*/
/**
* @}
*/

5
src/timer/test/Makefile Normal file
View File

@ -0,0 +1,5 @@
all:
gcc -g -O0 -o test-kytimer test-kytimer.c -lkytimer -lpthread
clean:
rm demo

View File

@ -0,0 +1,62 @@
#include <libkytimer.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
void func(char* comment)
{
char date[32] = {0};
time_t now;
time(&now);
if (ctime_r(&now , date))
date[strlen(date) - 1] = '\0';
printf("[%s]这是%s\n" , date , comment);
}
void stop(size_t* fdpoll)
{
printf("开始停止定时器\n");
for (int i = 0 ; i < 10 ; i ++)
{
kdk_timer_stop(fdpoll[i]);
}
}
int main()
{
assert(kdk_timer_init() == 0);
//测试1 -- 基本功能
size_t fdpoll[10] = {0};
for (int i = 1 ; i <= 10 ; i ++)
{
char* data = (char*)malloc(10);
assert(data);
sprintf(data , "%d号" , i);
fdpoll[i - 1] = kdk_timer_start(i * 1000 , (time_handler)func , KTIMER_PERIODIC , KTIMER_ABSOLUTE, (void*)data , 1);
assert(fdpoll[i - 1]);
}
kdk_timer_start(10000 , (time_handler)stop , KTIMER_SINGLESHOT , KTIMER_ABSOLUTE, (void*)fdpoll , 0);
sleep(11);
//测试3 -- 单次触发
printf("单次触发测试:\n");
kdk_timer_start(2000 , (time_handler)func , KTIMER_SINGLESHOT , KTIMER_ABSOLUTE, "2号" , 0);
sleep(5);
//测试2 -- 重置定时器时间
printf("修改时间测试:\n");
int persec = kdk_timer_start(1000 , (time_handler)func , KTIMER_PERIODIC , KTIMER_ABSOLUTE, "1号" , 0);
int sec3 = kdk_timer_start(3000 , (time_handler)func , KTIMER_SINGLESHOT , KTIMER_ABSOLUTE, "3号" , 0);
sleep(2);
kdk_timer_reset(sec3 , 4000);
printf("sec3 时钟已被重置为4000ms\n");
sleep(10);
printf("正在销毁定时器核心...\n");
kdk_timer_destroy();
return 0;
}

4
src/utils/CMakeLists.txt Normal file
View File

@ -0,0 +1,4 @@
add_subdirectory(data-structure)
# install(FILES sdkmarcos.h kerr.h cstring-extension.h
# DESTINATION include/kysdk/kysdk-base)

View File

@ -0,0 +1,322 @@
#ifndef KYSDK_BASE_UTILS_STREXT_H__
#define KYSDK_BASE_UTILS_STREXT_H__
/** @defgroup C语言字符串扩展模块
* @{
*/
/**
* @file cstring-extension.h
* @author liuyunhe (liuyunhe@kylinos.cn)
* @brief KYSDK C语言字符串操作扩展
* @version 0.1
* @date 2021-10-28
*
* @copyright Copyright (c) 2021
*
*/
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief strip操作
*
* @param str strip的字符串指针
* @param ch
*/
static inline void strstrip(char *str, char ch)
{
if (strlen(str) == 0)
return;
char *startPos = str;
while (*startPos != '\0' && *startPos == ch)
startPos++;
if (*startPos == '\0')
{
str[0] = 0;
return;
}
char *endPos = str + strlen(str) - 1;
while (endPos != str && *endPos == ch)
endPos --;
memmove(str, startPos, endPos - startPos + 1);
*(str + (endPos - startPos) + 1) = 0;
}
/**
* @brief
*
* @param str strip操作的字符串指针
*/
static inline void strstripspace(char *str)
{
if (strlen(str) == 0)
return;
char *startPos = str;
while (*startPos != '\0' && isspace(*startPos))
startPos++;
if (*startPos == '\0')
{
str[0] = 0;
return;
}
char *endPos = str + strlen(str) - 1;
while (endPos != str && isspace(*endPos))
endPos --;
memmove(str, startPos, endPos - startPos + 1);
*(str + (endPos - startPos) + 1) = 0;
}
/**
* @brief tab
*
* @param str
*/
static inline void strstripblank(char *str)
{
if (strlen(str) == 0)
return;
char *startPos = str;
while (*startPos != '\0' && isblank(*startPos))
startPos++;
if (*startPos == '\0')
{
str[0] = 0;
return;
}
char *endPos = str + strlen(str) - 1;
while (endPos != str && isblank(*endPos))
endPos --;
memmove(str, startPos, endPos - startPos + 1);
*(str + (endPos - startPos) + 1) = 0;
}
/**
* @brief
*
* @param p
* @return const char* space后的字符串指针
*/
static inline const char *strskipspace(const char *p)
{
while (isspace(*p))
++p;
return p;
}
/**
* @brief tab
*
* @param p
* @return const char* space后的字符串指针
*/
static inline const char *strskipblank(const char *p)
{
while (isblank(*p))
++p;
return p;
}
/**
* @brief
*
* @param str
*/
static inline void str2upper(char *str)
{
char *pos = str;
while (*pos)
{
if (isalpha(*pos))
*pos &= 0xDF;
pos ++;
}
}
/**
* @brief
*
* @param str
*/
static inline void str2lower(char *str)
{
char *pos = str;
while (*pos)
{
if (isalpha(*pos))
*pos |= 0x20;
pos ++;
}
}
/**
* @brief 0
*
* @param str
* @param ch
* @return int -1
*/
static inline int strfirstof(const char* str, char ch)
{
const char* pos = str;
while (*pos)
{
if (*pos == ch)
return pos - str;
pos ++;
}
return -1;
}
/**
* @brief 0
*
* @param str
* @param ch
* @return int -1
*/
static inline int strlastof(const char* str, char ch)
{
const char* pos = str;
while (*pos)
pos ++;
pos --;
while (pos != str)
{
if (*pos == ch)
return pos - str + 1;
pos --;
}
return -1;
}
/**
* @brief str是否以prefix开头
*
* @param str
* @param prefix
* @return int str以prefix开头01
*/
static inline int strstartswith(const char *str, const char *prefix)
{
size_t sz = prefix ? strlen(prefix) : 0;
if (str && sz && strncmp(str, prefix, sz) == 0)
return 0;
return 1;
}
/**
* @brief str是否以prefix开头
*
* @param str
* @param prefix
* @return int str以prefix开头01
*/
static inline int strstartswith_nocase(const char *str, const char *prefix)
{
size_t sz = prefix ? strlen(prefix) : 0;
if (str && sz && strncasecmp(str, prefix, sz) == 0)
return 0;
return 1;
}
/**
* @brief str是否以postfix结尾
*
* @param str
* @param postfix
* @return int str以postfix结尾01
*/
static inline int strendwith(const char *str, const char *postfix)
{
size_t sl = str ? strlen(str) : 0;
size_t pl = postfix ? strlen(postfix) : 0;
if (pl == 0)
return 0;
if (sl < pl)
return 1;
if (memcmp(str + sl - pl, postfix, pl) != 0)
return 1;
return 0;
}
static inline int strendwith_nocase(const char *str, const char *postfix)
{
return 0;
}
/**
* @brief
*
* @param str
* @param ch
* @return size_t
*/
static inline size_t strcounts(const char *str, char ch)
{
const char *p = str;
int counts = 0;
while (*p)
{
if (*p == ch)
counts ++;
p ++;
}
return counts;
}
/**
* @brief
*
* @param str
* @param delim
* @return char** NULL结尾alloc申请的内存使
* freefree
*/
static inline char** strsplit(char *str, char delim)
{
size_t size = strcounts(str, delim) + 1;
char **res = (char **)calloc(1, sizeof(char *) * (size + 1));
if (!res)
return NULL;
if (size < 2)
{
res[0] = str;
return res;
}
char *leftstr;
res[0] = strtok_r(str, &delim, &leftstr);
for (size_t i = 1; i < size; i ++)
{
res[i] = strtok_r(NULL, &delim, &leftstr);
}
return res;
}
#ifdef __cplusplus
}
#endif
#endif
/**
* @}
*/

View File

@ -0,0 +1,17 @@
aux_source_directory(linklist/skip_linklist SOURCESCODE)
add_library(kydatastruct SHARED ${SOURCESCODE})
add_subdirectory(linklist)
include_directories(linklist)
include_directories(linklist/skip_linklist)
add_executable(test-delete linklist/skip_linklist/test/delete_test.c)
add_executable(test-insert linklist/skip_linklist/test/insert_test.c)
add_executable(test-search linklist/skip_linklist/test/search_test.c)
target_link_libraries(test-delete kydatastruct)
target_link_libraries(test-insert kydatastruct)
target_link_libraries(test-search kydatastruct)
install(TARGETS kydatastruct
DESTINATION lib/kysdk/kysdk-base)

View File

@ -0,0 +1,18 @@
{
"editor.tokenColorCustomizations": {
"textMateRules": [
{
"scope": "kunpeng.func",
"settings": {
"foreground": "#28a745"
}
},
{
"scope": "kunpeng.intrinsics",
"settings": {
"foreground": "#28a745"
}
}
]
}
}

View File

@ -0,0 +1,2 @@
install(FILES listdata.h skip_linklist/skip_linklist.h
DESTINATION include/kysdk/kysdk-base)

View File

@ -0,0 +1,11 @@
#ifndef KYSDK_BASE_UTILS_LIST_DATA_H__
#define KYSDK_BASE_UTILS_LIST_DATA_H__
typedef union _kysdk_listdata
{
void *ptr;
int num;
}kysdk_listdata;
#endif

View File

@ -0,0 +1,228 @@
#include <sdkmarcos.h>
#include "skip_linklist.h"
#include <stdlib.h>
#include <time.h>
static kysdk_skiplist_node* malloc_skiplist_node(unsigned int maxlvl)
{
kysdk_skiplist_node *res = malloc(sizeof(kysdk_skiplist_node));
ASSERT_NOT_NULL(res, NULL);
res->data.num = 0;
res->key = 0;
res->next = malloc(sizeof(kysdk_skiplist_node*) * maxlvl);
if (! res->next)
{
free(res);
return NULL;
}
for (int i = 0; i < maxlvl; i ++)
res->next[i] = NULL;
return res;
}
kysdk_skiplist* kysdk_create_skiplist()
{
kysdk_skiplist *res = malloc(sizeof(kysdk_skiplist));
ASSERT_NOT_NULL(res, NULL);
res->counts = 0;
res->max_levels = 3;
res->children = calloc(0, sizeof(kysdk_skiplist_node *) * res->max_levels);
if (!res->children)
{
free(res);
return NULL;
}
return res;
}
void kysdk_destroy_skiplist(kysdk_skiplist *list)
{
// delete all node
kysdk_skiplist_node *curnode = list->children[0];
while (curnode)
{
list->children[0] = curnode->next[0];
SAFE_FREE(curnode->next);
SAFE_FREE(curnode);
curnode = list->children[0];
list->counts --;
}
SAFE_FREE(list->children);
SAFE_FREE(list);
}
int kysdk_skiplist_setmaxlevels(kysdk_skiplist *list, unsigned int maxlevels)
{
if (!list || list->counts)
return -1;
list->max_levels = maxlevels;
kysdk_skiplist_node **tmp = list->children;
list->children = realloc(list->children, sizeof(kysdk_skiplist_node *) * list->max_levels);
if (!list->children)
{
list->children = tmp;
return -1;
}
for (int i = 0; i < maxlevels; i ++)
list->children[i] = NULL;
return 0;
}
int kysdk_skiplist_insert(kysdk_skiplist *list, int key, kysdk_listdata data)
{
kysdk_skiplist_node *node = malloc_skiplist_node(list->max_levels);
ASSERT_NOT_NULL(node, -1);
node->key = key;
node->data = data;
if (! list->children[0] || list->children[0]->key > key)
{
node->next[0] = list->children[0];
list->children[0] = node;
}
else
{
kysdk_skiplist_node *prevnode = NULL, *curnode = NULL;
// 找到插入位置
for (int i = list->max_levels - 1; i >= 0; i --)
{
if (prevnode)
curnode = prevnode;
else
curnode = list->children[i];
if (! curnode || curnode->key > key)
continue;
while (curnode->next[i] && curnode->next[i]->key <= key)
curnode = curnode->next[i];
prevnode = curnode;
}
if (prevnode)
{
node->next[0] = prevnode->next[0];
prevnode->next[0] = node;
}
else
{
node->next[0] = list->children[0];
list->children[0] = node;
}
}
// 决定是否升层
srand(time(NULL));
for (int i = 1; i < list->max_levels; i ++)
{
if (random() & 1)
break;
if (! list->children[i] || list->children[i]->key > key)
{
node->next[i] = list->children[i];
list->children[i] = node;
}
else
{
kysdk_skiplist_node *prevnode = list->children[i];
while (prevnode->next[i] && prevnode->next[i]->key <= key)
prevnode = prevnode->next[i];
node->next[i] = prevnode->next[i];
prevnode->next[i] = node;
}
}
list->counts ++;
return 0;
}
int kysdk_skiplist_delete(kysdk_skiplist *list, int key)
{
kysdk_skiplist_node *node = NULL;
if (! list->children[0] || list->children[0]->key > key)
{
// no target found
return -1;
}
else
{
kysdk_skiplist_node *prevnode = NULL, *curnode = NULL;
// 找到删除位置
for (int i = list->max_levels - 1; i >= 0; i --)
{
if (prevnode)
curnode = prevnode;
else
curnode = list->children[i];
if (! curnode || curnode->key > key)
continue;
while (curnode->next[i] && curnode->next[i]->key < key)
curnode = curnode->next[i];
prevnode = curnode;
if (prevnode->next[i] && prevnode->next[i]->key == key)
{
node = prevnode->next[i];
prevnode->next[i] = prevnode->next[i]->next[i];
}
}
}
if (node)
{
SAFE_FREE(node->next);
SAFE_FREE(node);
list->counts --;
return 0;
}
return -1;
}
kysdk_listdata kysdk_skiplist_search(kysdk_skiplist *list, int key)
{
kysdk_skiplist_node *curnode = NULL, *res = NULL;
for (int i = list->max_levels - 1; i >= 0; i --)
{
if (!list->children[i] || list->children[i]->key > key)
continue;
if (! curnode)
curnode = list->children[i];
while (curnode->next[i] && curnode->next[i]->key <= key)
curnode = curnode->next[i];
if (curnode && curnode->key == key)
{
res = curnode;
break;
}
}
if (res)
return res->data;
return (kysdk_listdata)-1;
}

View File

@ -0,0 +1,97 @@
#ifndef KYSDK_BASE_UTILS_SKIPLISK_H__
#define KYSDK_BASE_UTILS_SKIPLISK_H__
/** @defgroup 链表模块
* @{
*/
/**
* @file skip_linklist.h
* @author liuyunhe (liuyunhe@kylinos.cn)
* @brief :
* : O(log(n))
* : O(log(n))
* : O(log(n))
* :
* O(n)
* @version 0.1
* @date 2021-09-07
*
* @copyright Copyright (c) 2021
*
*/
#include <listdata.h>
typedef struct _kysdk_skiplist_node{
int key;
kysdk_listdata data;
struct _kysdk_skiplist_node **next;
}kysdk_skiplist_node;
typedef struct _kysdk_skiplist{
unsigned int counts; // 节点个数
unsigned int max_levels; // 最高层数
kysdk_skiplist_node **children;
}kysdk_skiplist;
/**
* @brief
*
* @return kysdk_skiplist*
*/
extern kysdk_skiplist* kysdk_create_skiplist();
/**
* @brief data.ptr指向的内存
*
* @param list
*/
extern void kysdk_destroy_skiplist(kysdk_skiplist *list);
/**
* @brief 使
*
* @param list
* @param maxlevels
* @return int
*/
extern int kysdk_skiplist_setmaxlevels(kysdk_skiplist *list, unsigned int maxlevels);
/**
* @brief
*
* @param list
* @param key
* @param data
* @return int 0-1
*/
extern int kysdk_skiplist_insert(kysdk_skiplist *list, int key, kysdk_listdata data);
/**
* @brief key值对应的节点
*
* @param list
* @param key
* @return int, 0-1
*/
extern int kysdk_skiplist_delete(kysdk_skiplist *list, int key);
/**
* @brief key搜索data内容
*
* @param list
* @param key
* @return kysdk_listdata key不存在时data.num值为-1
*/
extern kysdk_listdata kysdk_skiplist_search(kysdk_skiplist *list, int key);
#endif
/**
* @}
*/

View File

@ -0,0 +1,5 @@
#!/bin/bash
gcc -o search_test search_test.c ../skip_linklist.c -I/data/git-local-storage/kysdk/kysdk-base/src/utils/ -I/data/git-local-storage/kysdk/kysdk-base/src/utils/data-structure/linklist/skip_linklist -I/data/git-local-storage/kysdk/kysdk-base/src/utils/data-structure/linklist/ -g -O0
gcc -o insert_test insert_test.c ../skip_linklist.c -I/data/git-local-storage/kysdk/kysdk-base/src/utils/ -I/data/git-local-storage/kysdk/kysdk-base/src/utils/data-structure/linklist/skip_linklist -I/data/git-local-storage/kysdk/kysdk-base/src/utils/data-structure/linklist/ -g -O0
gcc -o delete_test delete_test.c ../skip_linklist.c -I/data/git-local-storage/kysdk/kysdk-base/src/utils/ -I/data/git-local-storage/kysdk/kysdk-base/src/utils/data-structure/linklist/skip_linklist -I/data/git-local-storage/kysdk/kysdk-base/src/utils/data-structure/linklist/ -g -O0

View File

@ -0,0 +1,78 @@
#include <skip_linklist.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#define ARRAY_SIZE 20
int array[ARRAY_SIZE];
int del_flag[ARRAY_SIZE];
void print_list(kysdk_skiplist *list)
{
for (int i = list->max_levels - 1; i >= 0; i --)
{
kysdk_skiplist_node *curnode = list->children[i];
printf("Level[%d]: ", i);
while (curnode)
{
printf("%d->", curnode->key);
curnode = curnode->next[i];
}
printf("NULL\n");
}
}
int test_list_delete(kysdk_skiplist *list)
{
for (int i = 0; i < ARRAY_SIZE; i ++)
{
if (random() % 2)
{
del_flag[i] = 1;
kysdk_skiplist_delete(list, array[i]);
printf("Deleted %d\n", array[i]);
}
}
for (int i = 0; i < ARRAY_SIZE; i ++)
{
if (del_flag[i] && kysdk_skiplist_search(list, array[i]).num != -1)
{
printf("Skiplist delete test failed.\n");
return -1;
}
}
printf("Skiplist order test pass.\n");
return 0;
}
int main()
{
kysdk_skiplist *list = kysdk_create_skiplist();
kysdk_skiplist_setmaxlevels(list, 5);
srand(time(NULL));
for (int i = 0; i < ARRAY_SIZE; i ++)
{
array[i] = i;
kysdk_skiplist_insert(list, i, (kysdk_listdata)i);
printf("%d has been insert.\n", i);
sleep(1);
}
print_list(list);
int res = test_list_delete(list);
print_list(list);
kysdk_destroy_skiplist(list);
return res;
}

View File

@ -0,0 +1,65 @@
#include <skip_linklist.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
void print_list(kysdk_skiplist *list)
{
for (int i = list->max_levels - 1; i >= 0; i --)
{
kysdk_skiplist_node *curnode = list->children[i];
printf("Level[%d]: ", i);
while (curnode)
{
printf("%d->", curnode->key);
curnode = curnode->next[i];
}
printf("NULL\n");
}
}
int test_list_order(kysdk_skiplist *list)
{
kysdk_skiplist_node *node = list->children[0];
while (node)
{
if (node->next[0])
{
if (node->key > node->next[0]->key)
{
printf("Skiplist order test failed.\n");
return -1;
}
}
node = node->next[0];
}
printf("Skiplist order test pass.\n");
return 0;
}
int main()
{
kysdk_skiplist *list = kysdk_create_skiplist();
kysdk_skiplist_setmaxlevels(list, 5);
srand(time(NULL));
for (int i = 0; i < 100; i ++)
{
int num = random() % 500 + 1;
kysdk_skiplist_insert(list, num, (kysdk_listdata)i);
printf("%d has been insert.\n", num);
sleep(1);
}
print_list(list);
int res = test_list_order(list);
kysdk_destroy_skiplist(list);
return res;
}

View File

@ -0,0 +1,78 @@
#include <skip_linklist.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
void print_list(kysdk_skiplist *list)
{
for (int i = list->max_levels - 1; i >= 0; i --)
{
kysdk_skiplist_node *curnode = list->children[i];
printf("Level[%d]: ", i);
while (curnode)
{
printf("%d->", curnode->key);
curnode = curnode->next[i];
}
printf("NULL\n");
}
}
int test_list_search(kysdk_skiplist *list)
{
for (int i = 0; i < 5; i ++)
{
int target = random() % 50 + 1;
kysdk_listdata data = kysdk_skiplist_search(list, target);
printf("Searching for %d, data is %d\n", target, data.num);
kysdk_skiplist_node *curnode = list->children[0];
short finded = 0;
while (curnode)
{
if (curnode->key == target)
{
finded = 1;
break;
}
curnode = curnode->next[0];
}
if (finded && data.num == -1)
{
printf("Skiplist search test failed.\n");
return -1;
}
}
printf("Skiplist search test pass.\n");
return 0;
}
int main()
{
kysdk_skiplist *list = kysdk_create_skiplist();
kysdk_skiplist_setmaxlevels(list, 5);
srand(time(NULL));
for (int i = 0; i < 20; i ++)
{
int num = random() % 50 + 1;
kysdk_listdata data;
data.num = i;
kysdk_skiplist_insert(list, num, data);
printf("[%d] %d has been insert.\n", i, num);
sleep(1);
}
print_list(list);
int res = test_list_search(list);
kysdk_destroy_skiplist(list);
return res;
}

12
src/utils/kerr.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef KYSDK_BASE_UTILS_ERR_H__
#define KYSDK_BASE_UTILS_ERR_H__
#ifdef __linux__
#include <errno.h>
#define KDK_EINVALIDARGS EINVAL
#define KDK_ENOMEM ENOMEM
#define KDK_PERM EPERM
#define KDK_EUNKNOW 65535
#endif
#endif

354
src/utils/kyutils.c Normal file
View File

@ -0,0 +1,354 @@
/**
* @file kyutils.c
* @brief
* @author liuyang <liuyang@kylinos.cn>
* @version 1.0
* @date 2021-09-01
*
* @copyright Copyright: 2021,KylinSoft Co.,Ltd.
*
*/
#include "kyutils.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef __uint8_t uint8_t;
typedef __uint16_t uint16_t;
typedef __uint32_t uint32_t;
typedef __uint64_t uint64_t;
typedef __intmax_t intmax_t;
typedef __uintmax_t uintmax_t;
#define PRIu64 __PRI64_PREFIX "u"
# if __WORDSIZE == 64
# define __PRI64_PREFIX "l"
# define __PRIPTR_PREFIX "l"
# else
# define __PRI64_PREFIX "ll"
# define __PRIPTR_PREFIX
# endif
enum
{
SIZE_SUFFIX_1LETTER = 0, // 进制单位(保留一个字母如M
SIZE_SUFFIX_3LETTER = (1 << 0), // 进制单位(保留三个字母如MiB)
SIZE_SUFFIX_SPACE = (1 << 1), // 数据与单位间保留空格
SIZE_DECIMAL_2DIGITS = (1 << 2) // 保留两位小数
};
int kdkVolumeBaseCharacterConvert(const char* origin_data, KDKVolumeBaseType result_base, char* result_data);
int kdkVolumeBaseNumericalConvert(double origin_numerical, KDKVolumeBaseType origin_base, KDKVolumeBaseType result_base, double* result_numerical);
static int do_scale_by_power (uintmax_t *x, int base, int power)
{
while (power--) {
if (UINTMAX_MAX / base < *x)
return -ERANGE;
*x *= base;
}
return 0;
}
static int get_exp2(uint64_t n, KDKVolumeBaseType base)
{
int shft;
for (shft = 10; shft <= base * 10; shft += 10) {
if (n < (1ULL << shft))
break;
}
return shft - 10;
}
int parse_size(const char *str, uintmax_t *res, int *power)
{
const char *p;
char *end;
uintmax_t x, frac = 0;
int base = 1024, rc = 0, pwr = 0, frac_zeros = 0;
static const char *suf = "KMGTPEZY";
static const char *suf2 = "kmgtpezy";
const char *sp;
*res = 0;
if (!str || !*str) {
//rc = -EINVAL;
rc = -KDK_INVAILD_ARGUMENT;
goto err;
}
/* Only positive numbers are acceptable
*
* Note that this check is not perfect, it would be better to
* use lconv->negative_sign. But coreutils use the same solution,
* so it's probably good enough...
*/
p = str;
while (isspace((unsigned char) *p))
p++;
if (*p == '-') {
//rc = -EINVAL;
rc = -KDK_INVAILD_ARGUMENT;
goto err;
}
errno = 0, end = NULL;
x = strtoumax(str, &end, 0); //强制类型转换
if (end == str ||
(errno != 0 && (x == UINTMAX_MAX || x == 0))) {
rc = errno ? -errno : -KDK_INVAILD_ARGUMENT;
goto err;
}
if (!end || !*end)
goto done; /* without suffix */
p = end;
check_suffix:
if (*(p + 1) == 'i' && (*(p + 2) == 'B' || *(p + 2) == 'b') && !*(p + 3))
base = 1024; /* XiB, 2^N */
else if ((*(p + 1) == 'B' || *(p + 1) == 'b') && !*(p + 2))
base = 1024; /* XB, 10^N */
// 消除 iBB的区别
else if (*(p + 1)) {
struct lconv const *l = localeconv();
const char *dp = l ? l->decimal_point : NULL;
size_t dpsz = dp ? strlen(dp) : 0;
if (frac == 0 && *p && dp && strncmp(dp, p, dpsz) == 0) {
const char *fstr = p + dpsz;
for (p = fstr; *p == '0'; p++)
frac_zeros++;
fstr = p;
if (isdigit(*fstr)) {
errno = 0, end = NULL;
frac = strtoumax(fstr, &end, 0);
if (end == fstr ||
(errno != 0 && (frac == UINTMAX_MAX || frac == 0))) {
//rc = errno ? -errno : -EINVAL;
rc = errno ? -errno : -KDK_INVAILD_ARGUMENT;
goto err;
}
} else
end = (char *) p;
if (frac && (!end || !*end)) {
rc = -KDK_INVAILD_ARGUMENT;
goto err; /* without suffix, but with frac */
}
p = end;
goto check_suffix;
}
rc = -KDK_INVAILD_ARGUMENT;
goto err; /* unexpected suffix */
}
sp = strchr(suf, *p);
if (sp)
pwr = (sp - suf) + 1;
else {
sp = strchr(suf2, *p);
if (sp)
pwr = (sp - suf2) + 1;
else {
rc = -EINVAL;
goto err;
}
}
rc = do_scale_by_power(&x, base, pwr);
if (power)
*power = pwr;
if (frac && pwr) {
int i;
uintmax_t frac_div = 10, frac_poz = 1, frac_base = 1;
/* mega, giga, ... */
do_scale_by_power(&frac_base, base, pwr);
/* maximal divisor for last digit (e.g. for 0.05 is
* frac_div=100, for 0.054 is frac_div=1000, etc.)
*/
while (frac_div < frac)
frac_div *= 10;
/* 'frac' is without zeros (5 means 0.5 as well as 0.05) */
for (i = 0; i < frac_zeros; i++)
frac_div *= 10;
/*
* Go backwardly from last digit and add to result what the
* digit represents in the frac_base. For example 0.25G
*
* 5 means 1GiB / (100/5)
* 2 means 1GiB / (10/2)
*/
do {
unsigned int seg = frac % 10; /* last digit of the frac */
uintmax_t seg_div = frac_div / frac_poz; /* what represents the segment 1000, 100, .. */
frac /= 10; /* remove last digit from frac */
frac_poz *= 10;
if (seg)
x += frac_base / (seg_div / seg);
} while (frac);
}
done:
*res = x;
err:
if (rc < 0)
errno = -rc;
return rc;
}
char *size_to_human_string(int options, uint64_t bytes, int base)
{
char buf[32];
int dec, exp;
uint64_t frac;
const char *letters = "BKMGTPE";
char suffix[sizeof(" KiB")], *psuf = suffix;
char c;
if (options & SIZE_SUFFIX_SPACE)
*psuf++ = ' ';
exp = get_exp2(bytes, base);
c = *(letters + (exp ? exp / 10 : 0));
dec = exp ? bytes / (1ULL << exp) : bytes;
frac = exp ? bytes % (1ULL << exp) : 0;
*psuf++ = c;
if ((options & SIZE_SUFFIX_3LETTER) && (c != 'B')) {
*psuf++ = 'i';
*psuf++ = 'B';
}
*psuf = '\0';
if (frac) {
if (options & SIZE_DECIMAL_2DIGITS) {
frac = (frac / (1ULL << (exp - 10)) + 5) / 10;
if (frac % 10 == 0)
frac /= 10; /* convert N.90 to N.9 */
} else {
frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
if (frac == 10)
dec++, frac = 0;
}
}
if (frac) {
struct lconv const *l = localeconv();
char *dp = l ? l->decimal_point : NULL;
if (!dp || !*dp)
dp = ".";
snprintf(buf, sizeof(buf), "%d%s%" PRIu64 "%s", dec, dp, frac, suffix);
} else
snprintf(buf, sizeof(buf), "%d%s", dec, suffix);
return strdup(buf);
}
int kdkVolumeBaseCharacterConvert(const char* origin_data, KDKVolumeBaseType result_base, char* result_data)
{
int ret = 0;
uintmax_t basic_data;
int power;
// 入参检查
if (origin_data == NULL)
{
syslog(LOG_ERR, "[KYSDK:utils:%s] in parameter error please check usage",__FUNCTION__);
return KDK_INVAILD_ARGUMENT;
}
// 出参检查
if (result_data == NULL)
{
syslog(LOG_ERR, "[KYSDK:utils:%s] out parameter error, please check memory application situation!",__FUNCTION__);
return KDK_INVAILD_ARGUMENT;
}
ret = parse_size(origin_data, &basic_data, &power);
if (ret != 0)
{
syslog(LOG_ERR, "[KYSDK:utils:%s] parse origin data failed, please contact developer, origin data = %s, errcode = %d\n", __FUNCTION__, origin_data ,ret);
return KDK_INVAILD_DATA_FORMAT;
}
printf("%lu\n", basic_data);
char *temp;
temp = size_to_human_string(SIZE_SUFFIX_1LETTER | SIZE_DECIMAL_2DIGITS, basic_data, result_base);
strcpy(result_data, temp);
if (temp != NULL)
free(temp);
return ret;
}
int kdkVolumeBaseNumericalConvert(double origin_numerical, KDKVolumeBaseType origin_base, KDKVolumeBaseType result_base, double* result_numerical)
{
int ret = 0;
//将数据转化构建成字符串
char unit[4] = {0};
switch (origin_base)
{
case KDK_KILOBYTE:
/* code */
strcpy(unit, "KB");
break;
case KDK_MEGABYTE:
strcpy(unit, "MB");
break;
case KDK_GIGABYTE:
strcpy(unit, "GB");
break;
case KDK_TERABYTE:
strcpy(unit, "TB");
break;
case KDK_PETABYTE:
strcpy(unit, "PB");
break;
case KDK_EXABYTE:
strcpy(unit, "EB");
break;
default:
strcpy(unit, "B");
break;
}
char origin_string[200] = {0};
sprintf(origin_string, "%.2f%s",origin_numerical, unit);
// 后续重复解析过程
uintmax_t basic_data;
int power;
ret = parse_size(origin_string, &basic_data, &power);
if (ret != 0)
{
syslog(LOG_ERR, "[KYSDK:utils:%s] parse origin data failed, please contact developer, origin data = %s, errcode = %d\n", __FUNCTION__, origin_string ,ret);
return KDK_INVAILD_DATA_FORMAT;
}
char *temp;
temp = size_to_human_string(SIZE_DECIMAL_2DIGITS, basic_data, result_base);
*result_numerical = atof(temp);
if(temp != NULL)
free(temp);
return ret;
}

2534
src/utils/kyutils.dot Normal file

File diff suppressed because it is too large Load Diff

87
src/utils/kyutils.h Normal file
View File

@ -0,0 +1,87 @@
/**
* @file kyutils.h
* @brief
* @author liuyang <liuyang@kylinos.cn>
* @version 1.0
* @date 2021-09-01
* @example kysdk-base/src/utils/sample/kyutils_sample.c
*
* @copyright Copyright: 2021,KylinSoft Co.,Ltd.
*
*/
#ifndef KYSDK_UTILS_H__
#define KYSDK_UTILS_H__
#include <stdint.h>
#include <ctype.h>
#include <inttypes.h>
#include <bits/types.h>
#include <locale.h>
#include <errno.h>
#include <stddef.h>
#include <sys/syslog.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup 单位进制转换组件
* @{
*/
/** KDKUtilsErrCode */
typedef enum{
KDK_NOERR, /**< 无异常 */
KDK_INVAILD_BASE, /**< 非法进制 */
KDK_INVAILD_ARGUMENT, /**< 非法参数 */
KDK_INVAILD_DATA_FORMAT, /**< 非法数据格式 */
KDK_SYSTEM_UNKOWNERR, /**< 系统运行异常引发的未知错误 */
}KDKUtilsErrCode;
/** KDKVolumeBaseType */
typedef enum{
KDK_KILOBYTE = 1, /**< KB */
KDK_MEGABYTE, /**< MB */
KDK_GIGABYTE, /**< GB */
KDK_TERABYTE, /**< TB */
KDK_PETABYTE, /**< PB */
KDK_EXABYTE, /**< EB */
}KDKVolumeBaseType;
/**
* @brief
* @param[in] origin_data B
* @param[in] result_base
* @param[out] result_data
* @return int
*
*/
extern int kdkVolumeBaseCharacterConvert(const char* origin_data, KDKVolumeBaseType result_base, char* result_data);
/**
* @brief
* @param[in] origin_numerical
* @param[in] origin_base
* @param[in] result_base
* @param[out] result_numerical
* @return int
*/
extern int kdkVolumeBaseNumericalConvert(double origin_numerical, KDKVolumeBaseType origin_base, KDKVolumeBaseType result_base, double* result_numerical);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,37 @@
/**
* @file kyutils_sample.c
* @brief
* @author Fnoily <liuyang@kylinos.cn>
* @version 1.0
* @date 2021-10-29
* Copyright: 2021,KylinSoft Co.,Ltd.
*
*/
#include "../kyutils.h"
#include <stdio.h>
#include <string.h>
int main()
{
int ret = 0;
// 调用字符型数据单位转换接口
char origin_data [20] = "10000.24MB";
char result_data [50] = {0};
ret = kdkVolumeBaseCharacterConvert(origin_data, KDK_GIGABYTE, result_data);
printf("%s\n", result_data);
// 调用数字型数据单位转换接口
// 此例亦可说明,在低进制不足以向高进制转换时,进制保持不变
double origin_numberical = 100.24;
double result_numberical;
ret = kdkVolumeBaseNumericalConvert(origin_numberical, KDK_MEGABYTE, KDK_GIGABYTE, &result_numberical);
printf("%.2f\n", result_numberical);
return 0;
}

25
src/utils/sdkmarcos.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef KYSDK_BASE_UTILS_MARCOS_H__
#define KYSDK_BASE_UTILS_MARCOS_H__
/*
GNU Attribute
*/
#define DEPRECATED __attribute__((deprecated))
#define CONSTRUCTOR __attribute__((constructor))
#define DESTRUCTOR __attribute__((destructor))
#define FORMAT(type, fmtindex, argindex) __attribute__((format(type, fmtindex, argindex)))
#define WARNUNSEDRET __attribute__((warn_unused_result))
#define WEAK __attribute__((weak))
#define ALWAYSINLINE __attribute__((always_inline))
#define CHECK_FMT(x,y) __attribute__((format(printf,x,y)))
#define NOINLINE __attribute__((noinline))
#define NOTNULL(...) __attribute__((nonnull(__VA_ARGS__)))
#define MUSTCHECKRESULT __attribute__((warn_unused_result))
/*
Customize
*/
#define ASSERT_NOT_NULL(x, ret) if (!x) {return ret;}
#define SAFE_FREE(x) if (x) {free(x); x = NULL;}
#endif