initial commit

This commit is contained in:
2025-08-05 15:53:44 +08:00
commit 09dc02ae52
553 changed files with 137665 additions and 0 deletions

25
common/config.mk Executable file
View File

@@ -0,0 +1,25 @@
HEADERS += $(COM_DIR)/*.h\
$(COM_DIR)/slab/*.h\
$(COM_DIR)/xbuf/*.h\
$(COM_DIR)/iobuffer/*.h\
$(COM_DIR)/ringbuffer/*.h\
$(COM_DIR)/utils/*.h\
$(COM_DIR)/crc32/*.h\
$(COM_DIR)/threadpool/*.h\
$(COM_DIR)/workqueue/*.h\
$(COM_DIR)/jsonpacket/*h
SRCDIRS += $(COM_DIR)
SRCDIRS += $(COM_DIR)/slab
SRCDIRS += $(COM_DIR)/threadpool
SRCDIRS += $(COM_DIR)/workqueue
SRCDIRS += $(COM_DIR)/xbuf
SRCDIRS += $(COM_DIR)/iobuffer
SRCDIRS += $(COM_DIR)/ringbuffer
SRCDIRS += $(COM_DIR)/utils
SRCDIRS += $(COM_DIR)/crc32
SRCDIRS += $(COM_DIR)/jsonpacket
LIBHV_HEADERS += $(HEADERS)
CORE_SRCDIRS += $(SRCDIRS)

154
common/iobuffer/iobuffer.c Executable file
View File

@@ -0,0 +1,154 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "iobuffer.h"
#define ALIGN(x, a) (((x) + (a)-1) & ~((a)-1))
static int pow2gt (int x) {
--x;
x|=x>>1;
x|=x>>2;
x|=x>>4;
x|=x>>8;
x|=x>>16;
return x+1;
}
void iobuffer_init(iobuffer* p) {
p->iodata = NULL;
p->size = 0;
p->capacity = 0;
}
void iobuffer_deinit(iobuffer* p) {
free(p->iodata);
p->iodata = NULL;
p->size = 0;
p->capacity = 0;
}
int iobuffer_reserve(iobuffer* p, int cap) {
if (cap > p->capacity) {
// round up
//extra 1 byte for null-terminated char,
int alloc = pow2gt(cap+1);
printf(" allcate iobuffer %d=>%d\n", cap, alloc);
// at least 16 byte align for AES encrypt
alloc = ALIGN(alloc,16);
assert(alloc >= cap + 1);
assert(alloc >= p->size + 1);
char* new_data = (char*)realloc(p->iodata, alloc);
if (!new_data) {
printf("can't allcate iobuffer %d=>%d\n", p->capacity, alloc);
return ENOMEM;
}
p->iodata = new_data;
p->capacity = alloc - 1;
p->iodata[p->size] = '\0';
}
return 0;
}
int iobuffer_freesize(iobuffer* p){
assert(p->capacity >= p->size);
return p->capacity - p->size;
}
int iobuffer_appendData(iobuffer* p, const void* data, int count) {
if (count <= 0)
return EINVAL;
int ret = iobuffer_reserve(p, p->size + count);
if (ret == 0) {
memcpy(p->iodata + p->size, data, count);
p->size += count;
p->iodata[p->size] = '\0';
}
return ret;
}
int iobuffer_append_string(iobuffer* p, const void* str)
{
return iobuffer_appendData(p, str, strlen(str));
}
int iobuffer_prependData(iobuffer* p, const void* data, int count) {
int ret = iobuffer_reserve(p, p->size + count);
if (ret == 0) {
memmove(p->iodata + count, p->iodata, p->size);
memcpy(p->iodata, data, count);
p->size += count;
p->iodata[p->size] = '\0';
}
return ret;
}
void iobuffer_erase(iobuffer* p, int from, int to) {
int n = to - from;
if (n > 0) {
if ( n != p->size ){
memmove(p->iodata + from, p->iodata + to, p->size - to);
}
p->size -= n;
p->iodata[p->size] = '\0';
}
}
void iobuffer_eraseall(iobuffer* p)
{
iobuffer_erase(p, 0, p->size);
}
static int ioprintf(iobuffer* this, const char *format, va_list ap)
{
int n;
int buflen = this->capacity - this->size;
if ( buflen < 128) {
if ( 0 != iobuffer_reserve(this, this->size + 1024))
return ENOMEM;
buflen = this->capacity - this->size;
}
while(1) {
char * buf = this->iodata + this->size;
n = vsnprintf(buf, buflen, format, ap);
if ( n <= 0) {
printf("vsnprintf err %d/%d,format=%s", n, errno, format);
return -2;
}
if ( n > buflen) {
if ( 0 != iobuffer_reserve(this, this->size + n + 1024))
return ENOMEM;
buflen = this->capacity - this->size;
}
else {
this->size += n;
return 0;
}
}
}
int iobuffer_printf(iobuffer* p, const char *format, ...){
int result;
va_list ap;
va_start(ap, format);
result = ioprintf(p, format, ap);
va_end(ap);
return result;
}
void iobuffer_read(iobuffer* this, void* to, int size)
{
memcpy(to, this->iodata, size);
iobuffer_erase(this, 0, size);
}

42
common/iobuffer/iobuffer.h Executable file
View File

@@ -0,0 +1,42 @@
#ifndef IOBUFFER_H_INCLUDED
#define IOBUFFER_H_INCLUDED
typedef struct {
char* iodata; //if not null, always 16 byte alignment for better AES encrypt
int size;
int capacity; //capacity, always >= size
} iobuffer;
void iobuffer_init(iobuffer* p);
void iobuffer_deinit(iobuffer* p);
/* 申请cap大小的缓冲 */
int iobuffer_reserve(iobuffer* p, int cap);
/* 获取剩余缓冲的大小 */
int iobuffer_freesize(iobuffer* p);
/* to后的data移到from位置 */
void iobuffer_erase(iobuffer* p, int from, int to);
/* 设置size=0 清除所有data */
void iobuffer_eraseall(iobuffer* p);
/* 读size大小的数据到to的内存 */
void iobuffer_read(iobuffer* p, void* to, int size);
/* 插入字符串 */
int iobuffer_append_string(iobuffer* p, const void* str);
/* 插入数据 */
int iobuffer_appendData(iobuffer* p, const void* iodata, int count);
/* 插入格式打印iobuffer_printf(p, "i m %s, years old", "liming", 5)*/
int iobuffer_printf(iobuffer* p, const char *format, ...) __attribute__((__format__ (printf, 2, 3)));/* first arg is this pointer */
// Don't call it but change your code logic
// int iobuffer_prependData(iobuffer* p, const void* iodata, int count);
#endif /* IOBUFFER_H_INCLUDED */

224
common/jsonpacket/json_packet.c Executable file
View File

@@ -0,0 +1,224 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "json_packet.h"
#include "kpacket.h"
#include "hlog.h"
#define json_simple_free_size(json) (json->cap - json_simple_len(json))
static uint32_t json_simple_suffix(json_simple *json){
uint32_t free_size = json_simple_free_size(json);
if ( free_size > 1 ) {
*json->pos = '}';
*(json->pos+1) = '\0';
return OK;
}
return NG;
}
json_simple json_simple_init(char *pos, uint16_t cap){
json_simple json;
json.buf = pos;
json.cap = cap;
json.pos = pos;
*json.pos = '{';
json.pos++;
json_simple_suffix(&json);
return json;
}
#define json_snprintf(json, fmt, key, val) ({\
uint32_t free_size = json_simple_free_size(json);\
uint32_t n = snprintf(json->pos, free_size, fmt, key, val);\
uint32_t ret;\
if ( n < free_size ) {\
json->pos += n;\
ret = json_simple_suffix(json);\
} else ret = NG;\
ret;\
})
uint32_t json_simple_add_int(json_simple *json, char *key, int32_t val){
return json_snprintf(json, json->pos - json->buf > 2 ? ",\"%s\":%d" : "\"%s\":%d", key, val);
}
uint32_t json_simple_add_str(json_simple *json, char *key, char *val){
return json_snprintf(json, json->pos - json->buf > 2 ? ",\"%s\":\"%s\"" : "\"%s\":\"%s\"", key, val);
}
const char *json_simple_tostring(json_simple *json){
return json->buf;
}
const uint32_t json_simple_len(json_simple *json){
return json->pos - json->buf + 2;
}
void json_simple_test(){
char tmp_buf[512];
TLV *tlv = (TLV *)tmp_buf;
json_simple json = json_simple_init(tlv->V, sizeof(tmp_buf) - sizeof(TLV));
tlv->T = 0x01; /*cmd*/
json_simple_add_int(&json, "cmd", tlv->T);
json_simple_add_str(&json, "udid", "my_uuid");
json_simple_add_str(&json, "wakeup_type", "pir");
tlv->L = json_simple_len(&json);
hlogd(">>> %s json_simple_tostring:%s %u", __func__, json_simple_tostring(&json), json_simple_len(&json));
}
uint8_t json_pkt_parse(json_pkt *packet, const char *str, const char *cmd_sign){
json_pkt_reset(packet);
if ((packet->json = cJSON_Parse(str)) == NULL){
hloge("%s error:%s", __func__, str);
return 0;
}
if (cmd_sign){
const uint16_t cmd = json_pkt_get_int(packet, cmd_sign, 0);
json_pkt_setcmd(packet, cmd);
}
return 1;
}
void json_pkt_reset(json_pkt *packet){
if (packet->json){
cJSON *json = packet->json;
cJSON_Delete(json);
}
memset(packet, 0, sizeof(json_pkt));
}
void json_pkt_setcmd(json_pkt *packet, const uint16_t cmd){
packet->cmd = cmd;
}
uint8_t json_pkt_isValid(json_pkt *packet){
return packet && packet->json!=NULL && packet->cmd!=-1;
}
//the following functions will act to mJson
void json_pkt_add_int(json_pkt *packet, const char *key, const int val){
if (json_pkt_get_item(packet, key))
cJSON_Delete_itemFromObject(packet->json, key);
if (packet->json == NULL)
packet->json = cJSON_CreateObject();
cJSON_AddNumberToObject(packet->json, key, val);
}
void json_pkt_add_str(json_pkt *packet, const char *key, const char *val){
if (json_pkt_get_string(packet, key, NULL) == val){
//__log("%s same:%s", __func__, val);
return;
}
if (json_pkt_get_item(packet, key))
cJSON_Delete_itemFromObject(packet->json, key);
if (packet->json == NULL)
packet->json = cJSON_CreateObject();
cJSON_Add_stringToObject(packet->json, key, val);
}
void json_pkt_add_item(json_pkt *packet, const char *key, cJSON *val){
if (json_pkt_get_item(packet, key) == val){
return;
}
if (json_pkt_get_item(packet, key))
cJSON_Delete_itemFromObject(packet->json, key);
if (packet->json == NULL)
packet->json = cJSON_CreateObject();
cJSON_Add_itemToObject(packet->json, key, val);
}
void json_pkt_add_item_int(json_pkt *packet, const char *item, const char *key, const int val){
if (packet->json == NULL)
packet->json = cJSON_CreateObject();
cJSON *json_item = json_pkt_get_item(packet, item);
if (!json_item){
json_item = cJSON_CreateObject();
cJSON_Add_itemToObject(packet->json, item, json_item);
}
cJSON_AddNumberToObject(json_item, key, val);
}
void json_pkt_add_item_str(json_pkt *packet, const char *item, const char *key, const char *val){
if (packet->json == NULL)
packet->json = cJSON_CreateObject();
cJSON *json_item = json_pkt_get_item(packet, item);
if (!json_item){
json_item = cJSON_CreateObject();
cJSON_Add_itemToObject(packet->json, item, json_item);
}
cJSON_Add_stringToObject(json_item, key, val);
}
void json_pkt_remove(json_pkt *packet, const char *key){
if (json_pkt_get_item(packet, key))
cJSON_Delete_itemFromObject(packet->json, key);
else
hloge("%s not found item:%s",__func__, key);
}
cJSON *json_pkt_detach(json_pkt *packet, const char *key){
if (json_pkt_get_item(packet, key))
return cJSON_Detach_itemFromObject(packet->json, key);
return NULL;
}
cJSON * json_pkt_get_item(json_pkt *packet, const char *key){
return packet->json == NULL?NULL:cJSON_GetObject_item(packet->json, key);
}
const char *json_pkt_get_string(json_pkt *packet, const char *key, const char *defaultVal){
return cJSON_get_string(packet->json, key, defaultVal);
}
int json_pkt_get_int(json_pkt *packet, const char *key, const int defaultVal){
return json_pkt_get_item_int(packet, packet->json, key, defaultVal);
}
uint8_t json_pkt_get_bool(json_pkt *packet, const char *key,const uint8_t defaultVal){
return cJSON_get_bool(packet->json, key, defaultVal);
}
float json_pkt_get_float(json_pkt *packet, const char *key, const double defaultVal){
double value = cJSON_getDouble(packet->json, key, defaultVal);
if (value == defaultVal) {
//add for compitable
cJSON * json = json_pkt_get_item(packet, key);
if (json && (json->type == cJSON_True || json->type == cJSON_False)) {
return json->valuedouble;
}
}
return value;
}
int json_pkt_get_item_int(json_pkt *packet, cJSON * item, const char *key, const int defaultVal){
int value = cJSON_get_int(item, key, defaultVal);
if (value == defaultVal) {
//add for compitable
cJSON * json = json_pkt_get_item(packet, key);
if (json && (json->type == cJSON_True || json->type == cJSON_False)) {
return json->valueint;
}
}
return value;
}
int json_pkt_get_intArray(json_pkt *packet, const char *key, int *array, const int size){
cJSON * list = json_pkt_get_item(packet, key);
if (list){
int s = cJSON_GetArraySize(list);
int i=0;
for(; i<size && i<s;i++){
cJSON *item = cJSON_GetArray_item(list, i);
array[i] = item->valueint;
}
return s>size?size:s;
}
return 0;
}
//convert current packet->mJson object to string and append to mPacketBuffer, and do not call twice.
char *json_pkt_toJson_string(json_pkt *packet){
if (packet->json){
char* buffer = cJSON_PrintUnformatted(packet->json);
return buffer;
}
return NULL;
}
/*
int json_pkt_printf(json_pkt *packet, const char *format, ...){
int result;
va_list ap;
va_start(ap, format);
result = packet->mPacketBuffer.vprintf(format, ap);
va_end(ap);
return result;
}*/

77
common/jsonpacket/json_packet.h Executable file
View File

@@ -0,0 +1,77 @@
#ifndef _JSON_PACKET_H_INCLUDED_
#define _JSON_PACKET_H_INCLUDED_
#include <stdint.h>
#include "cJSON.h"
#include "iobuffer.h"
/**
* inout: a input/output arguments, if return NO_REPLY the output is ignored.
*/
/*
* simple json function packet
* 简单的json pack
*/
typedef struct{
uint16_t cap; /*capacity*/
char *buf;
char *pos;
}json_simple;
json_simple json_simple_init(char *pos, uint16_t cap);
/*
** return NG or OK
**/
uint32_t json_simple_add_int(json_simple *json, char *key, int32_t val);
uint32_t json_simple_add_str(json_simple *json, char *key, char *val);
/*json_simple_tostring
** no need to free
**/
const char *json_simple_tostring(json_simple *json);
const uint32_t json_simple_len(json_simple *json);
/*
使用例子
char buf[256];
json_simple json = json_simple_init(buf, sizeof(buf));
json_simple_add_int(&json, "cmd", 0x11);
json_simple_add_str(&json, "uuid", "my_uuid");
char *str = json_simple_tostring(&json);
**/
/*
* Json function packet
*/
typedef struct{
uint16_t cmd; //value of cmd_sign, max 65535
int16_t ret; ///NO_REPLY this packet will not be sent back.
cJSON *json;
}json_pkt;
uint8_t json_pkt_parse(json_pkt *packet, const char *str, const char *cmd_sign); //func according to funcMark.
#define json_pkt_deinit json_pkt_reset//also deinit, make the mjson, func NULL and mPacketBuffer.size = 0
void json_pkt_reset(json_pkt *packet); //also deinit, make the mjson, func NULL and mPacketBuffer.size = 0
void json_pkt_setcmd(json_pkt *packet, const uint16_t cmd); //str will be strdup
//the following functions will act to mJson
void json_pkt_add_int(json_pkt *packet, const char *key, const int val);
void json_pkt_add_str(json_pkt *packet, const char *key, const char *val);
void json_pkt_add_item(json_pkt *packet, const char *key, cJSON *val);
void json_pkt_add_item_int(json_pkt *packet, const char *item, const char *key, const int val);
void json_pkt_add_item_str(json_pkt *packet, const char *item, const char *key, const char *val);
void json_pkt_remove(json_pkt *packet, const char *key);
cJSON *json_pkt_detach(json_pkt *packet, const char *key);
cJSON *json_pkt_get_item(json_pkt *packet, const char *key);
const char *json_pkt_get_string(json_pkt *packet, const char *key, const char *defaultVal);
int json_pkt_get_int(json_pkt *packet, const char *key, const int defaultVal);
uint8_t json_pkt_get_bool(json_pkt *packet, const char *key,const uint8_t defaultVal);
float json_pkt_get_float(json_pkt *packet, const char *key, const double defaultVal);
int json_pkt_get_item_int(json_pkt *packet, cJSON * obj, const char *key, const int defaultVal);
int json_pkt_get_intArray(json_pkt *packet, const char *key, int *array, const int size);
//convert current mJson object to string and append to mPacketBuffer, and do not call twice. free it.
char* json_pkt_toJson_string(json_pkt *packet);
#endif

171
common/kpacket.c Executable file
View File

@@ -0,0 +1,171 @@
#include "kpacket.h"
#include "ngx_slab.h"
#include "hlog.h"
#include "crc16.h"
static ngx_slab_pool_t *slab;
TLV *TLV_init(char *buf, uint32_t cap){
TLV *tlv = (TLV*)buf;
}
void kpacket_init(uint32_t packet_pool_size){
slab = ngx_slab_sizes_init(packet_pool_size);
}
uint16_t kpacket_calc_checksum(kpacket *packet){
char *p = (char*)&packet->tlv.magic;
return crc16(p, packet->tlv.L + sizeof(packet->tlv) -sizeof(packet->tlv.checksum));
}
uint16_t kpacket_checksum(kpacket *packet){
packet->tlv.checksum = kpacket_calc_checksum(packet);
return packet->tlv.checksum;
}
kpacket *kpacket_slab_alloc(uint32_t size){
if (slab) {
kpacket * p = (kpacket *)ngx_slab_alloc(slab, size);
return p;
}
hloge("%s err kpacket_init first ", __func__);
return NULL;
}
void kpacket_slab_free(kpacket *packet){
ngx_slab_free(slab, packet);
}
static uint32_t put_rawdata(kpacket *p, const void *data, uint32_t size){
if (p){
if (kpacket_get_freesize(p) >= size){
char *payload = p->tlv.V;
memcpy(payload + p->tlv.L, data, size);
p->tlv.L += size;
return 0;
}else{
hloge("%s error outofmemory kpacket_get_freesize:%d, need:%u", __func__, kpacket_get_freesize(p), size);
exit(0);
}
}else{
hloge("%s error p NULL", __func__);
}
return 1;
}
uint32_t kpacket_put_int(kpacket *p, int32_t val){
return put_rawdata(p, &val, sizeof(val));
}
uint32_t kpacket_put_string(kpacket *p, const char *str){
return put_rawdata(p, str, strlen(str) + 1);
}
uint32_t kpacket_put_data(kpacket *p, const char *data, uint32_t len){
uint32_t ret = 0;
ret += put_rawdata(p, &len, sizeof(len)) ;
ret += put_rawdata(p, data, len);
if (ret){
hloge("%s len err capacity:%u, and len:%u, tatal:%d, request:%u",
__func__, p->capacity, p->tlv.L, (uint32_t)(len+sizeof(len)), (uint32_t)(p->tlv.L + len + sizeof(len) - p->capacity));
}
return ret;
}
uint32_t kpacket_put_data1data2(kpacket *p, const char *data, uint32_t len, const char *data2, uint32_t len2){
uint32_t ret = 0;
uint32_t total = len + len2;
ret += put_rawdata(p, &total, sizeof(total));
ret += put_rawdata(p, data, len);
ret += put_rawdata(p, data2, len2);
if (ret){
hloge("%s len err capacity:%u, and len:%u, tatal:%d, need:%u",
__func__, p->capacity, p->tlv.L, (uint32_t)(len+sizeof(len)), (uint32_t)(p->tlv.L + len + sizeof(len) - p->capacity));
}
return ret;
}
void kpacket_reset(kpacket *p){
if (p){
p->tlv.L = 0;
}
}
uint32_t kpacket_get_freesize(const kpacket *p){
return p->capacity - p->tlv.L;
}
uint32_t kpacket_pop_int(kpacket *p, const int32_t defVal){
uint32_t val = defVal;
if (p && (p->tlv.L - p->offset >= sizeof(val))){
memcpy(&val, p->tlv.V + p->offset, sizeof(val));
p->offset += sizeof(val);
}
return val;
}
const char *kpacket_pop_string(kpacket *p, const char *defVal){
char *str = (char *)defVal;
uint32_t val;
if (p && p->tlv.L - p->offset > 1 && (val = strlen(p->tlv.V + p->offset)+1) <= p->tlv.L - p->offset){
str = p->tlv.V + p->offset;
p->offset += val;
}
return (const char *)str;
}
uint32_t kpacket_pop_data(kpacket *p, char **data){
uint32_t len = 0;
if (p && p->tlv.L - p->offset > sizeof(len)){
memcpy(&len, p->tlv.V + p->offset, sizeof(len));
if (len + sizeof(len) <= p->tlv.L - p->offset){
p->offset += sizeof(len);
*data = p->tlv.V + p->offset;
p->offset += len;
}else{
len = 0;
}
}
return len;
}
uint32_t kpacket_pop_reset(kpacket *p){
if (p){
p->offset = 0;
return 0;
}
return 1;
}
void kpacket_dump(kpacket *p){
hlogi("ref:%u capacity:%u magic:0x%X event:%u pay_loadsize:%u", p->ref, p->capacity, p->tlv.magic, p->tlv.T, p->tlv.L);
}
void kpacket_test(void){
#define TEST_STR "123456\r\n"
kpacket *packet = kpacket(0, 100);
kpacket_put_int(packet, 987);
kpacket_put_int(packet, 789);
kpacket_put_data(packet, TEST_STR, strlen(TEST_STR));
kpacket_put_data1data2(packet, TEST_STR, strlen(TEST_STR), TEST_STR, strlen(TEST_STR));
kpacket_put_string(packet, TEST_STR);
kpacket_dump(packet);
char *data;
int len;
hlogi("kpacket kpacket_pop_int:%d", kpacket_pop_int(packet, 0));
hlogi("kpacket kpacket_pop_int:%d", kpacket_pop_int(packet, 0));
len = kpacket_pop_data(packet, &data);
hlogi("kpacket kpacket_pop_data sz:%d %s", len, data);
len = kpacket_pop_data(packet, &data);
hlogi("kpacket kpacket_pop_data sz:%d %s", len, data);
hlogi("kpacket kpacket_pop_string:%s", kpacket_pop_string(packet, "err"));
kpacket_dec(packet);
}

184
common/kpacket.h Executable file
View File

@@ -0,0 +1,184 @@
/*************************************************
File name : kpacket.h
Module : pal
Author : amir.liang
Version : 0.1
Created on : 2021-09-16
Description :
included files required by os environment
Modify History:
1. Date: Author: Modification:
20230424 amir use os_lock instead of mutex.
*************************************************/
#ifndef __PACKET_H__
#define __PACKET_H__
#include <stdint.h>
#include "hdef.h"
#include "hmutex.h"
#include "hatomic.h"
#ifndef OK
#define OK (char)(0)
#endif
#ifndef NG
#define NG (char)(1)
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*===========================================*/
/*1. do not use kpacket with stack memory */
/*2. payload address must be algin 4 */
/*===========================================*/
#define KPACKET_DEBUG 1U
#if KPACKET_DEBUG
#define KPACKET_LOG hlogd
#else
#define KPACKET_LOG(...)
#endif
#define OS_PACKET_MAGIC 0xcafe
/*
*kpacket_put_int: 按int推数据到value, 协议方pop_int对应有即可
*如: kpacket_put_int(kp, 123); val = kpacket_pop_int(kp, -1) val应该是123
*/
typedef struct {
uint16_t checksum; /* crc16 , just for TLV, include OS_PACKET_MAGIC */
uint16_t magic; /* OS_PACKET_MAGIC */
uint16_t T; /*TLV T: 0~65535 */
uint32_t L; /*TLV L: total size of value */
char V[0]; /*TLV V: the addr of value */
}TLV;
TLV *TLV_init(char *buf, uint32_t cap);
typedef struct{
hatomic_t ref; /*引用计数, 创建时为1, 当减到值为0时将释放kpacket内存 */
uint32_t capacity; /*内存容量,主要是 value能存的数据大小 = sizeof(kpacket) + len(value) */
uint32_t offset; /*仅用于标识 value的offset*/
TLV tlv;
}kpacket;
/*
* packet_pool_size recommend 4K
* 初始化时必先 init
*/
void kpacket_init(uint32_t packet_pool_size);
/*
*
* 填充完所有数时计算并保存checksum到kpacket, 返回checksum
*/
uint16_t kpacket_checksum(kpacket *packet);
/*
*
* 仅计算并返回checksum 并不保存在kpacket
*/
uint16_t kpacket_calc_checksum(kpacket *packet);
/*
*
*/
kpacket *kpacket_slab_alloc(uint32_t size);
/*
*
*/
void kpacket_slab_free(kpacket *packet);
#define kpacket_inc(_packet) ({\
hatomic_inc(&_packet->ref);/*没锁,有风险*/\
KPACKET_LOG("%s packet:%p, inc_ref:%d\n", __func__, _packet, _packet->ref);\
})
#define kpacket_dec(_packet) ({\
if (_packet->ref == 0){\
hloge("%s Error... hv_free_packet:%p, dec_ref should not be:%d\n", __func__, _packet, _packet->ref);\
}\
hatomic_dec(&_packet->ref);/*没锁,可能有风险*/\
if (_packet->ref == 0){\
KPACKET_LOG("%s free_packet:%p, dec_ref:%d ..............\n", __func__, _packet, _packet->ref);\
kpacket_slab_free(_packet);/*os_packet_delete(_packet);*/\
}else KPACKET_LOG("%s :%p, dec_ref:%d\n", __func__, _packet, _packet->ref);\
})
#define os_packet_valid(__packet) ({int32_t _ret;\
if (__packet && __packet-->tlv.magic == OS_PACKET_MAGIC){\
_ret = 1;\
}else{\
KPACKET_LOG("%s err packet:%p(!NULL), packet magic:%X(=%X)\n",__func__, __packet, __packet?__packet-->tlv.magic:0, OS_PACKET_MAGIC);\
_ret = 0;\
}\
_ret;})
#define kpacket(_event, _capacity)({\
kpacket *_packet = kpacket_slab_alloc(sizeof(kpacket) + _capacity);\
if (_packet){\
_packet->tlv.magic = OS_PACKET_MAGIC;\
_packet->tlv.T = _event;\
_packet->ref = 1;\
_packet->capacity = _capacity;\
_packet->tlv.L = 0;\
_packet->offset = 0;\
}else{\
hloge("%s kpacket_create outofmemory", __func__);\
}\
_packet;})
/*do not call os_packet_delete normally, use atomic_dec(packet) instead */
#if 0
#define os_packet_delete(_hv_free_packet)({\
if (os_packet_valid(_hv_free_packet)){\
if (_hv_free_packet->ref == 0) {\
hv_free(_hv_free_packet);\
hloge("%s os_packet_hv_free packet:%p",__func__, _hv_free_packet);\
}else{\
hloge("%s os_packet_hv_free error packet->ref:%d",__func__, _hv_free_packet->ref);\
}\
}else{\
hloge("%s os_packet_hv_free error",__func__);\
}\
})
#endif
uint32_t kpacket_put_int(kpacket *p, int32_t val);
uint32_t kpacket_put_string(kpacket *p, const char *str);//including '\0'
uint32_t kpacket_put_data(kpacket *p, const char *data, uint32_t len);
uint32_t kpacket_put_data1data2(kpacket *p, const char *data, uint32_t len, const char *data2, uint32_t len2);
//data move to 'zero' and dataLen be 0
void kpacket_reset(kpacket *p);
uint32_t kpacket_get_freesize(const kpacket *p);
uint32_t kpacket_pop_int(kpacket *p_box, const int32_t defVal);
const char *kpacket_pop_string(kpacket *p_box, const char *defVal);
uint32_t kpacket_pop_data(kpacket *p_box, char **data);
uint32_t kpacket_pop_reset(kpacket *p_box);
void kpacket_dump(kpacket *p);
void kpacket_test(void);
#ifdef __cplusplus
}
#endif
#endif /*_OS_TYPE_H__ */

116
common/ringbuffer/av_ringbuffer.c Executable file
View File

@@ -0,0 +1,116 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "list.h"
#include "av_ringbuffer.h"
#include "iot_math.h"
/*
* 不用移动rb->read指针, 只是复制出来
* 尽可能减少数据的复制, 如只为了判断类型时只要复制结构体
*/
static int32_t av_ringbuffer_get_frame_locked(ringbuffer *rb, ring_item *item, void *to, int8_t size){
const int32_t end_pos = (item->pos + size) - (rb->buffer + rb->capacity);
if (end_pos <= 0){
memcpy(to, item->pos, size);
}else{
memcpy(to, item->pos, size - end_pos);
memcpy(to + size - end_pos, rb->buffer, end_pos);
}
}
#if 0
uint32_t av_ringbuffer_get_video_frame(ringbuffer *rb, av_cookie *cookie, video_frame *to, uint32_t max_len, uint32_t timeout){
int32_t ret = NG;
ring_item *item = NULL;
hmutex_lock(&rb->mutex);
if (!list_empty(&rb->list[RING_LIST_USING])){
if (cookie->item && /* 正常情况直接获取下一个帧, 否则进入后面的异常情况去搜索 */
(cookie->item->seq > rb->last_drop_seq || rb->last_drop_seq == UINT32_MAX) && cookie->item->seq < ringbuffer_get_lastseq_locked(rb)) {/* 直接获取下一个*/
item = list_entry(cookie->item->link.next, ring_item, link);
}else if (cookie->dir == LATEST_IFRAME){/*直播查找最新的关键帧*/
struct list_head *pos, *n;
list_for_each_prev_safe(pos, n, &rb->list[RING_LIST_USING])
{
ring_item* tmp_item = list_entry(pos, ring_item, link);
av_ringbuffer_get_frame_locked(rb, tmp_item, to, sizeof(video_frame));
if((to->type & FRAME_TYPE_IFRAME) && (!cookie->item || tmp_item->seq >= cookie->item->seq)){
item = tmp_item;
break;
}
}
}else{/* dir = NEXT_IFRAME 查找比cookie->item新的关键帧, 如oss, 又不想丢太多 */
struct list_head *pos, *n;
list_for_each_safe(pos, n, &rb->list[RING_LIST_USING])
{
ring_item* tmp_item = list_entry(pos, ring_item, link);
av_ringbuffer_get_frame_locked(rb, tmp_item, to, sizeof(video_frame));
if((to->type & FRAME_TYPE_IFRAME) && (!cookie->item || tmp_item->seq >= cookie->item->seq) /*&& (to->ts >= cookie->startPTS)*/) {/*头一个, 或者 下一个*/
item = tmp_item;
break;
}
}
}
}
hmutex_unlock(&rb->mutex);
if ( item ) {
cookie->item = item;
av_ringbuffer_get_frame_locked(rb, item, to, sizeof(video_frame) + item->size);
//hlogd("av_ringbuffer_get_video_frame %u %X %u\n", cookie->item->seq, rb->last_drop_seq, ringbuffer_get_lastseq_locked(rb));
ret = OK;
} else {
ret = NG;
if (timeout) {
if ( hsem_wait_for(&rb->sem, timeout) ){ /* 没有数据,调用端再重新call */
/* 正常, 收到了sem, 有新的av帧送入 */
} else {
/* 超时没收到 sem */
}
}
}
return ret;
}
#endif
#if 1
void av_ringbuffer_test()
{
hlogi("test_av_ringbuffer\n");
#define TEST_CNT (10)
av_ringbuffer *v_ring = av_ringbuffer_init(3*1024*1024);
int i;
for(i=0;i<TEST_CNT;i++){
video_frame *vframe = avframe_create(video_frame, i+10);
vframe->chn = 0;
vframe->type = i % 15 == 0 ? FRAME_TYPE_IFRAME : FRAME_TYPE_PBFRAME;
vframe->format = VIDEO_FORMAT_H264;
vframe->seq = i;
sprintf(vframe->data, "im %d", i);
if (!av_ringbuffer_put(v_ring, vframe, vframe->data)){
hlogi("av_ringbuffer_put err:%u read:%p\n", vframe->size);
}
free(vframe);
}
hlogi("av_ringbuffer_put\n");
av_ringbuffer_dump(v_ring);
av_cookie cookie = {0};
cookie.dir = NEXT_IFRAME;
av_cookie *pcookie = &cookie;
video_frame *vframe = (video_frame*)calloc(1, sizeof(video_frame)+MAX_VFRAME_SIZE);
for(i=0;i<TEST_CNT;i++){
if (OK == av_ringbuffer_get_frame(v_ring, pcookie, vframe, i+10, 1000)){
hlogi("1 av_ringbuffer_get_video_frame i:%d seq:%u, size:%u cookie->item->seq:%u data:%s\n", i, vframe->seq, vframe->size, cookie.item->seq, vframe->data);
}else{
hlogi("1 av_ringbuffer_get_video_frame err:%d\n", i);
//break;
}
}
free(vframe);
hlogi("test_av_ringbuffer end\n");
}
#endif

113
common/ringbuffer/av_ringbuffer.h Executable file
View File

@@ -0,0 +1,113 @@
/*************************************************
File name : av_ringbuffer.h
Module : audio and video library functions
Author : amir
Created on : 2022-01-27
Description :
主要是每个"caller"可以带自己的index向一份共享的av_buffer取自己预期的内容(有的caller快,有的慢), 如果没有数了就sem等待.
Modify History:
1. Date: Author: Modification:
*************************************************/
#ifndef AV_RINGBUFFER
#define AV_RINGBUFFER
#include <stdint.h>
#include "ringbuffer.h"
#include "hal_interface_video.h"
enum{
NEXT_IFRAME = 0, /* next key frame */
LATEST_IFRAME /* latest key frame */
};
typedef struct{
ring_item *item; /* 根据item->seq来向前搜索, 这样不同的任务带自己的cookie可以取自己期望的下一帧 */
uint8_t dir; //dir = NEXT_IFRAME, 向前搜索大于seq和pts的帧(最旧的一个I帧); dir = LATEST_IFRAME, 相反如直播需要实时(最新的一个I帧)
}av_cookie;
#define avframe_create(_frame_type, _size) ({\
_frame_type *frame = (_frame_type *)malloc(sizeof(_frame_type) + _size);\
if (frame){frame->size = _size;}\
frame;\
})
typedef ringbuffer av_ringbuffer;
//init an av_ringbuffer
//return av_ringbuffer if success
/*
* 通常audio 和 video 各申请一个av_ringbuffer
*/
#define av_ringbuffer_init(_size) ringbuffer_init(_size)
//deinit an av_ringbuffer
#define av_ringbuffer_deinit(_av) ringbuffer_deinit(_av)
//put a pointer of a frame, special for a frame from lower callback and frame strcut and data in seperate memory
//eg: frame.size = av.size;
// av_ringbuffer_put(&frame, av.data)
/*
* put vframe_s 或 aframe_s
*/
#define av_ringbuffer_put(_av, _pframe, _data) ({\
ring_item *item = ringbuffer_put2(_av, (int8_t*)_pframe, sizeof(*_pframe), _data, _pframe->size);\
item;})
/*
* 根据cookie来移动自己的next_seq, audio and video frame 共用
**/
#define av_ringbuffer_get_frame(rb, cookie, to, max_len,timeout) ({\
uint32_t ret = NG;\
ring_item *item = NULL;\
hmutex_lock(&rb->mutex);\
if (!list_empty(&rb->list[RING_LIST_USING])){\
if (cookie->item && /* 正常情况直接获取下一个帧, 否则进入后面的异常情况去搜索 */\
(cookie->item->seq > rb->last_drop_seq || rb->last_drop_seq == UINT32_MAX) && cookie->item->seq < ringbuffer_get_lastseq_locked(rb)) {/* 直接获取下一个*/\
item = list_entry(cookie->item->link.next, ring_item, link);\
}else if (cookie->dir == LATEST_IFRAME){/*直播查找最新的关键帧*/\
struct list_head *pos, *n;\
list_for_each_prev_safe(pos, n, &rb->list[RING_LIST_USING])\
{\
ring_item* tmp_item = list_entry(pos, ring_item, link);\
av_ringbuffer_get_frame_locked(rb, tmp_item, to, sizeof(*to));\
if((to->type & FRAME_TYPE_IFRAME) && (!cookie->item || tmp_item->seq >= cookie->item->seq)){\
item = tmp_item;\
break;\
}\
}\
}else{/* dir = NEXT_IFRAME 查找比cookie->item新的关键帧, 如oss, 又不想丢太多 */\
struct list_head *pos, *n;\
list_for_each_safe(pos, n, &rb->list[RING_LIST_USING])\
{\
ring_item* tmp_item = list_entry(pos, ring_item, link);\
av_ringbuffer_get_frame_locked(rb, tmp_item, to, sizeof(*to));\
if(((to->type & FRAME_TYPE_IFRAME)||(to->type & FRAME_TYPE_AUDIO)) && (!cookie->item || tmp_item->seq >= cookie->item->seq)/*&& (to->ts >= cookie->startPTS)*/) {/*头一个, 或者 下一个*/\
item = tmp_item;\
break;\
}\
}\
}\
}\
hmutex_unlock(&rb->mutex);\
if ( item ) {\
cookie->item = item;\
av_ringbuffer_get_frame_locked(rb, item, to, sizeof(*to) + item->size);\
/*hlogd("av_ringbuffer_get_video_frame %u %X %u\n", cookie->item->seq, rb->last_drop_seq, ringbuffer_get_lastseq_locked(rb));*/\
ret = OK;\
} else {\
ret = NG;\
if (timeout) {\
if ( hsem_wait_for(&rb->sem, timeout) ){/* 没有数据,调用端再重新call */\
/* 正常, 收到了sem, 有新的av帧送入 */\
} else {\
/* 超时没收到 sem */\
}\
}\
}\
ret;})
#define av_ringbuffer_dump ringbuffer_dump
void av_ringbuffer_test();
#endif

320
common/ringbuffer/ringbuffer.c Executable file
View File

@@ -0,0 +1,320 @@
/*************************************************
File name : ringbuffer.c
Module : audio and video library functions
Author : amir
Created on : 2022-01-25
Description :
Function implement required by the mutex interface
Modify History:
1. Date: Author: Modification:
202405 罗启宏 增加lock需求
*************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "util.h"
#include "ringbuffer.h"
#include "iot_math.h"
#include "hlog.h"
/**
* @brief
*
* @param size
*
* @return
*/
ringbuffer *ringbuffer_init(uint32_t capacity/*, gfp_t gfp_mask*/)
{
#if 0
/* 检查时候是2的指数倍 */
if (size & (size-1))
{
// size = 1UL << (roundup_pow_of_two(size) + 1);
size = roundup_pow_of_two(size);
}
#endif
ringbuffer *rb = (ringbuffer*)calloc(1, sizeof(ringbuffer));
int8_t *buffer = (int8_t *)malloc(capacity);
if (rb && buffer){
hmutex_init(&rb->mutex);
if (!buffer)
{
free(rb);
rb = NULL;
}else{
rb->capacity = capacity;
rb->buffer = buffer;
INIT_LIST_HEAD(&rb->list[RING_LIST_USING]);
INIT_LIST_HEAD(&rb->list[RING_LIST_FREE]);
ringbuffer_reset(rb);
hsem_init(&rb->sem, 0);
}
}else{
free(rb);
free(buffer);
rb = NULL;
buffer = NULL;
}
return rb;
}
void ringbuffer_deinit(ringbuffer *rb){
hmutex_t mutex = rb->mutex;
ringbuffer_reset(rb);
hmutex_lock(&mutex);
hsem_destroy(&rb->sem);
free(rb->buffer);
free(rb);
hmutex_unlock(&mutex);
hmutex_destroy(&mutex);
}
void ringbuffer_reset(ringbuffer *rb)
{
hmutex_lock(&rb->mutex);
uint16_t i = 0;
for(i=0; i<RING_LIST_MAX; i++){
struct list_head *pos, *n;
list_for_each_safe(pos, n, &rb->list[i]) {
ring_item *item = list_entry(rb->list[i].next, ring_item, link);
list_del(&item->link);
free(item);
}
}
rb->last_drop_seq = UINT32_MAX;
rb->latest_item = NULL;
rb->write = rb->read = rb->buffer;
hmutex_unlock(&rb->mutex);
}
int32_t ringbuffer_size(ringbuffer *rb){
//hloge("rb->write:%u rb->read:%u\n", rb->write, rb->read);
uint32_t size;
hmutex_lock(&rb->mutex);
if (rb->write >= rb->read){
size = (rb->write - rb->read);
}else{
size = rb->capacity - (rb->read - rb->write);
}
hmutex_unlock(&rb->mutex);
return size;
}
int32_t ringbuffer_get_freesize(ringbuffer *rb){
hmutex_lock(&rb->mutex);
uint32_t freesize = rb->write >= rb->read ? rb->capacity - (rb->write - rb->read) : ( rb->read - rb->write);
hmutex_unlock(&rb->mutex);
return freesize;
}
uint32_t ringbuffer_get_lastseq_locked(ringbuffer *rb){
uint32_t seq = rb->latest_item ? rb->latest_item->seq : UINT32_MAX;
return seq;
}
#define ringbuffer_freesize_locked(rb)(\
rb->write >= rb->read ? rb->capacity - (rb->write - rb->read) : ( rb->read - rb->write)\
)
//get the count of items in ringbuffer
int32_t ringbuffer_item_count(ringbuffer *rb){
uint32_t count = 0;
hmutex_lock(&rb->mutex);
struct list_head *pos, *n;
list_for_each_safe(pos, n, &rb->list[RING_LIST_USING]) {
count++;
}
hmutex_unlock(&rb->mutex);
return count;
}
//put in data
ring_item *ringbuffer_put2(ringbuffer *rb, const char *data1, uint32_t data1_size, const char *data2, uint32_t data2_size){
ring_item *item = NULL;
uint32_t total_size = data1_size + data2_size;
if (total_size > rb->capacity){
return item;
}
hmutex_lock(&rb->mutex);
if (list_empty(&rb->list[RING_LIST_FREE])){//if no free item then to malloc one
item = (ring_item *)malloc(sizeof(ring_item));
}else{//get free item
item = list_entry(rb->list[RING_LIST_FREE].next, ring_item, link);
list_del(&item->link);
}
if (item){
//hloge("ringbuffer_put2:%u:%u:%u:%u\n", rb->write, rb->write + total_size, rb->read, rb->buffer + rb->capacity);
if (rb->write == rb->read && rb->read == rb->buffer + rb->capacity ){
rb->write = rb->read = rb->buffer;
//hloge("reset ringbuffer_put2:%u:%u:%u\n", rb->write, rb->read, rb->buffer + rb->capacity);
if (!list_empty(&rb->list[RING_LIST_USING])){
hloge("error RING_LIST_USING should be empty \n\n");
}
}
/*round to remove oldest item until there is enought space to add new one*/
while(!list_empty(&rb->list[RING_LIST_USING]) && ringbuffer_freesize_locked(rb) < total_size){
ring_item *item_oldest = list_entry(rb->list[RING_LIST_USING].next, ring_item, link);
list_del(&item_oldest->link);
list_add_tail(&item_oldest->link, &rb->list[RING_LIST_FREE]);
rb->last_drop_seq = item_oldest->seq;
/*move read to next item.pos*/
ring_item *next = list_entry(rb->list[RING_LIST_USING].next, ring_item, link);
rb->read = next->pos;
}
item->pos = rb->write;//data write here
item->size = total_size;
item->seq = rb->latest_item ? rb->latest_item->seq + 1 : 0; /* +1 */
rb->latest_item = item; /*记录最新的一个, 且不会被删除, 同时seq已是最新的*/
list_add_tail(&item->link, &rb->list[RING_LIST_USING]);
/*buffer---read---write----end*/
/*|---------|-------|--------|*/
/*tail_left = end - write */
uint32_t tail_left = (rb->capacity - (rb->write - rb->buffer));
if (tail_left >= total_size){
memcpy(item->pos, data1, data1_size);
if (data2 && data2_size){
memcpy(item->pos + data1_size, data2, data2_size);
}
rb->write += total_size;
}else{
if (tail_left >= data1_size){
memcpy(item->pos, data1, data1_size);//write to tail
if (data2 && data2_size){
memcpy(item->pos + data1_size, data2, tail_left - data1_size);
memcpy(rb->buffer, data2 + (tail_left - data1_size), data2_size - (tail_left - data1_size));
}
}else{
memcpy(item->pos, data1, tail_left);//write to tail
memcpy(rb->buffer, data1 + tail_left, data1_size - tail_left);
if (data2 && data2_size){
memcpy(rb->buffer + (data1_size - tail_left), data2, data2_size);
}
}
rb->write = rb->buffer + total_size - tail_left;// write = buffer + left
}
hsem_post(&rb->sem);
}
hmutex_unlock(&rb->mutex);
//hloge("rb->write:%p item->size:%u read:%p\n", rb->write, item->size, rb->read);
return item;
}
/**
* @brief
*
* @param rb
* @param to
* @param len
*
* @return success(0) or fail(-1)
*/
int32_t ringbuffer_pop(ringbuffer *rb, char *to, uint32_t *len)
{
int32_t ret = -1;
hmutex_lock(&rb->mutex);
if (!list_empty(&rb->list[RING_LIST_USING])){
ring_item *item = list_entry(rb->list[RING_LIST_USING].next, ring_item, link);
list_del(&item->link);
/*buffer-----read-----write----end*/
/*|---------|---------|----------|*/
/*item->pos + item->size > end ? */
/*then end_pos = item->pos + item->size - end */
const int32_t end_pos = (item->pos + item->size) - (rb->buffer + rb->capacity);/* 如果 end 没到尾 */
if (end_pos <=0){
rb->read = item->pos + item->size;
memcpy(to, item->pos, item->size);
}else{
memcpy(to, item->pos, item->size - end_pos);
memcpy(to + item->size - end_pos, rb->buffer, end_pos);
rb->read = rb->buffer + end_pos;
}
//hloge("ringbuffer_pop end_pos:%d item->size:%u pos:%u, buffer:%u, read:%u\n", end_pos, item->size,item->pos, rb->capacity,rb->read);
if (len){
*len = item->size;
}
list_add_tail(&item->link, &rb->list[RING_LIST_FREE]);
ret = 0;
}
hmutex_unlock(&rb->mutex);
return ret;
}
void ringbuffer_dump(ringbuffer *rb){
uint32_t i = 0;
struct list_head *pos, *n;
hmutex_lock(&rb->mutex);
list_for_each_safe(pos, n, &rb->list[RING_LIST_USING]) {
ring_item *item = list_entry(pos, ring_item, link);
hlogw("%s %02u item:%p size:%u pos:%p seq:%u\n", __func__, i++, item, item->size, item->pos, item->pos);
}
hmutex_unlock(&rb->mutex);
}
/*
* === FUNCTION ======================================================================
* Name: main
* Description:
* =====================================================================================
*/
int32_t ringbuffer_test()
{
#define BUF_SIZE (64)
#define TEST_STR "1234567891234567891234567891234567891234567891234567544656"
char *ssss = malloc(64);
ringbuffer * rb = ringbuffer_init(600);
if (rb == NULL )
{
return -1;
}
int i;
for(i=0; i<10;i++){
ringbuffer_put(rb, TEST_STR, 60);
}
for(i=0; i<10;i++){
uint32_t len;
ringbuffer_pop(rb, ssss, &len);
hlogd("%02d ssss:%s", i, ssss);
}
ringbuffer_dump(rb);
hlogd("1 ringbuffer_test ringbuffer_size:%d\n\n", ringbuffer_size(rb));
for(i=0; i<10;i++){
ringbuffer_put(rb, TEST_STR, 60);
}
hlogd("11 ringbuffer_tes ringbuffer_size:%d\n\n", ringbuffer_size(rb));
for(i=0; i<10;i++){
ringbuffer_put(rb, TEST_STR, 60);
}
ringbuffer_dump(rb);
hlogd("2 ringbuffer_test ringbuffer_size:%d\n\n", ringbuffer_size(rb));
for(i=0; i<10;i++){
uint32_t len;
char outbuf[100]={0};
ringbuffer_pop(rb, outbuf, &len);
hlogd("i:02%d len:%d, outbuf:%s\n", i, len, outbuf);
}
ringbuffer_deinit(rb);
return EXIT_SUCCESS;
}
#if 0
https://blog.csdn.net/u011569253/article/details/71637100
https://www.linuxidc.com/Linux/2016-12/137936.htm
#endif

94
common/ringbuffer/ringbuffer.h Executable file
View File

@@ -0,0 +1,94 @@
/*
* =====================================================================================
* Copyright (c), 2013-2020, Jz.
* Filename: ringbuffer.h
* Author: linux kernel,
* Organization: jz
*
* =====================================================================================
*/
/*************************************************
File name : ringbuffer.h
Module : common
Author : amir
Created on : 2023-01-6
Description :
a ringbuffer to store data(copy)
Modify History:
1. Date: Author: Modification:
*************************************************/
#ifndef __RINGBUFFER_H__
#define __RINGBUFFER_H__
#include <stdint.h>
#include "list.h"
#include "hmutex.h"
#include "hbase.h"
enum{
RING_LIST_FREE = 0,
RING_LIST_USING,
RING_LIST_MAX,
};
typedef struct{
struct list_head link;
int8_t *pos;
uint32_t size;
uint32_t seq; /* start from 0, 不是视频的seq, ringbuffer 内部的seq */
}ring_item;
typedef struct{
struct list_head list[RING_LIST_MAX];
hmutex_t mutex;
hsem_t sem;
int8_t *buffer;/* the buffer holding the data */
uint32_t capacity;/* the capacity of the allocated buffer */
int8_t *write;/* data is added at offset (write % size) */
int8_t *read;/* data is extracted from off. (read % size) */
ring_item *latest_item; /* 最新一个 item, seq 第一个为0, 并自增, 无的时候是 UINT32_MAX*/
uint32_t last_drop_seq; /* 最后因buffer不足,被丢弃的seq*/
}ringbuffer;
ringbuffer * ringbuffer_init(uint32_t size);
void ringbuffer_deinit(ringbuffer *rb);
void ringbuffer_reset(ringbuffer *rb);
//put in data
/*
* 返回被最后丢掉的seq
*/
#define ringbuffer_put(_fifo, _data, _size) ringbuffer_put2(_fifo, _data, _size, NULL, 0)
//put in 2 data
/*
* 返回被最后新增的item
*/
ring_item *ringbuffer_put2(ringbuffer *rb, const char *data1, uint32_t data1_size, const char *data2, uint32_t data2_size);
//pop out data
int32_t ringbuffer_pop(ringbuffer *rb, char *to, uint32_t *len);
//get the size of data in ringbuffer
int32_t ringbuffer_size(ringbuffer *rb);
//get the hv_free size of data in ringbuffer
int32_t ringbuffer_get_freesize(ringbuffer *rb);
/*
* 返回UINT32_MAX无数据
*/
uint32_t ringbuffer_get_lastseq_locked(ringbuffer *rb);
//get the count of items in ringbuffer
int32_t ringbuffer_item_count(ringbuffer *rb);
void ringbuffer_dump(ringbuffer *rb);
int32_t ringbuffer_test();
#endif

837
common/slab/ngx_slab.c Executable file
View File

@@ -0,0 +1,837 @@
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include "ngx_slab.h"
#include "hlog.h"
ngx_uint_t ngx_pagesize = 1024;
ngx_uint_t ngx_pagesize_shift;
#define NGX_SLAB_PAGE_MASK 3
#define NGX_SLAB_PAGE 0
#define NGX_SLAB_BIG 1
#define NGX_SLAB_EXACT 2
#define NGX_SLAB_SMALL 3
#if (NGX_PTR_SIZE == 4)
#define NGX_SLAB_PAGE_FREE 0
#define NGX_SLAB_PAGE_BUSY 0xffffffff
#define NGX_SLAB_PAGE_START 0x80000000
#define NGX_SLAB_SHIFT_MASK 0x0000000f
#define NGX_SLAB_MAP_MASK 0xffff0000
#define NGX_SLAB_MAP_SHIFT 16
#define NGX_SLAB_BUSY 0xffffffff
#else /* (NGX_PTR_SIZE == 8) */
#define NGX_SLAB_PAGE_FREE 0
#define NGX_SLAB_PAGE_BUSY 0xffffffffffffffff
#define NGX_SLAB_PAGE_START 0x8000000000000000
#define NGX_SLAB_SHIFT_MASK 0x000000000000000f
#define NGX_SLAB_MAP_MASK 0xffffffff00000000
#define NGX_SLAB_MAP_SHIFT 32
#define NGX_SLAB_BUSY 0xffffffffffffffff
#endif
#define NGX_LOG_ALERT 0
#define NGX_LOG_CRIT 0
#define ngx_slab_slots(pool) \
(ngx_slab_page_t *) ((u_char *) (pool) + sizeof(ngx_slab_pool_t))
#define ngx_slab_page_type(page) ((page)->prev & NGX_SLAB_PAGE_MASK)
#define ngx_slab_page_prev(page) \
(ngx_slab_page_t *) ((page)->prev & ~NGX_SLAB_PAGE_MASK)
#define ngx_slab_page_addr(pool, page) \
((((page) - (pool)->pages) << ngx_pagesize_shift) \
+ (uintptr_t) (pool)->start)
#if (NGX_DEBUG_MALLOC)
#define ngx_slab_junk(p, size) ngx_memset(p, 0xA5, size)
#elif (NGX_HAVE_DEBUG_MALLOC)
#define ngx_slab_junk(p, size) \
if (ngx_debug_malloc) ngx_memset(p, 0xA5, size)
#else
#define ngx_slab_junk(p, size)
#endif
static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool,
ngx_uint_t pages);
static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
ngx_uint_t pages);
static void ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level,
char *text);
static ngx_uint_t ngx_slab_max_size;
static ngx_uint_t ngx_slab_exact_size;
static ngx_uint_t ngx_slab_exact_shift;
ngx_slab_pool_t *ngx_slab_sizes_init(uint32_t pool_size)
{
ngx_slab_pool_t *slab = (ngx_slab_pool_t *)malloc(sizeof(ngx_slab_pool_t) + pool_size);
slab->addr = slab;
slab->end = slab->addr + pool_size;
slab->min_shift = 3;
if ( !ngx_slab_max_size ) {
ngx_uint_t n;
for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ }
ngx_slab_max_size = ngx_pagesize / 2;
ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t));
for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) {
/* void */
}
}
ngx_slab_init(slab);
}
void
ngx_slab_init(ngx_slab_pool_t *pool)
{
u_char *p;
size_t size;
ngx_int_t m;
ngx_uint_t i, n, pages;
ngx_slab_page_t *slots, *page;
hmutex_init(&pool->mutex);
pool->min_size = (size_t) 1 << pool->min_shift;
slots = ngx_slab_slots(pool);
p = (u_char *) slots;
size = pool->end - p;
ngx_slab_junk(p, size);
n = ngx_pagesize_shift - pool->min_shift;
for (i = 0; i < n; i++) {
/* only "next" is used in list head */
slots[i].slab = 0;
slots[i].next = &slots[i];
slots[i].prev = 0;
}
p += n * sizeof(ngx_slab_page_t);
pool->stats = (ngx_slab_stat_t *) p;
ngx_memzero(pool->stats, n * sizeof(ngx_slab_stat_t));
p += n * sizeof(ngx_slab_stat_t);
size -= n * (sizeof(ngx_slab_page_t) + sizeof(ngx_slab_stat_t));
pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t)));
pool->pages = (ngx_slab_page_t *) p;
ngx_memzero(pool->pages, pages * sizeof(ngx_slab_page_t));
page = pool->pages;
/* only "next" is used in list head */
pool->free.slab = 0;
pool->free.next = page;
pool->free.prev = 0;
page->slab = pages;
page->next = &pool->free;
page->prev = (uintptr_t) &pool->free;
pool->start = ngx_align_ptr(p + pages * sizeof(ngx_slab_page_t),
ngx_pagesize);
m = pages - (pool->end - pool->start) / ngx_pagesize;
if (m > 0) {
pages -= m;
page->slab = pages;
}
pool->last = pool->pages + pages;
pool->pfree = pages;
pool->log_nomem = 1;
pool->log_ctx = &pool->zero;
pool->zero = '\0';
}
void *
ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
{
void *p;
ngx_shmtx_lock(&pool->mutex);
p = ngx_slab_alloc_locked(pool, size);
ngx_shmtx_unlock(&pool->mutex);
return p;
}
void *
ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)
{
size_t s;
uintptr_t p, m, mask, *bitmap;
ngx_uint_t i, n, slot, shift, map;
ngx_slab_page_t *page, *prev, *slots;
if (size > ngx_slab_max_size) {
//ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab alloc: %uz", size);
page = ngx_slab_alloc_pages(pool, (size >> ngx_pagesize_shift)
+ ((size % ngx_pagesize) ? 1 : 0));
if (page) {
p = ngx_slab_page_addr(pool, page);
} else {
p = 0;
}
goto done;
}
if (size > pool->min_size) {
shift = 1;
for (s = size - 1; s >>= 1; shift++) { /* void */ }
slot = shift - pool->min_shift;
} else {
shift = pool->min_shift;
slot = 0;
}
pool->stats[slot].reqs++;
//ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,"slab alloc: %uz slot: %ui", size, slot);
slots = ngx_slab_slots(pool);
page = slots[slot].next;
if (page->next != page) {
if (shift < ngx_slab_exact_shift) {
bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page);
map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t));
for (n = 0; n < map; n++) {
if (bitmap[n] != NGX_SLAB_BUSY) {
for (m = 1, i = 0; m; m <<= 1, i++) {
if (bitmap[n] & m) {
continue;
}
bitmap[n] |= m;
i = (n * 8 * sizeof(uintptr_t) + i) << shift;
p = (uintptr_t) bitmap + i;
pool->stats[slot].used++;
if (bitmap[n] == NGX_SLAB_BUSY) {
for (n = n + 1; n < map; n++) {
if (bitmap[n] != NGX_SLAB_BUSY) {
goto done;
}
}
prev = ngx_slab_page_prev(page);
prev->next = page->next;
page->next->prev = page->prev;
page->next = NULL;
page->prev = NGX_SLAB_SMALL;
}
goto done;
}
}
}
} else if (shift == ngx_slab_exact_shift) {
for (m = 1, i = 0; m; m <<= 1, i++) {
if (page->slab & m) {
continue;
}
page->slab |= m;
if (page->slab == NGX_SLAB_BUSY) {
prev = ngx_slab_page_prev(page);
prev->next = page->next;
page->next->prev = page->prev;
page->next = NULL;
page->prev = NGX_SLAB_EXACT;
}
p = ngx_slab_page_addr(pool, page) + (i << shift);
pool->stats[slot].used++;
goto done;
}
} else { /* shift > ngx_slab_exact_shift */
mask = ((uintptr_t) 1 << (ngx_pagesize >> shift)) - 1;
mask <<= NGX_SLAB_MAP_SHIFT;
for (m = (uintptr_t) 1 << NGX_SLAB_MAP_SHIFT, i = 0;
m & mask;
m <<= 1, i++)
{
if (page->slab & m) {
continue;
}
page->slab |= m;
if ((page->slab & NGX_SLAB_MAP_MASK) == mask) {
prev = ngx_slab_page_prev(page);
prev->next = page->next;
page->next->prev = page->prev;
page->next = NULL;
page->prev = NGX_SLAB_BIG;
}
p = ngx_slab_page_addr(pool, page) + (i << shift);
pool->stats[slot].used++;
goto done;
}
}
ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_alloc(): page is busy");
//ngx_debug_point();
}
page = ngx_slab_alloc_pages(pool, 1);
if (page) {
if (shift < ngx_slab_exact_shift) {
bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page);
n = (ngx_pagesize >> shift) / ((1 << shift) * 8);
if (n == 0) {
n = 1;
}
/* "n" elements for bitmap, plus one requested */
for (i = 0; i < (n + 1) / (8 * sizeof(uintptr_t)); i++) {
bitmap[i] = NGX_SLAB_BUSY;
}
m = ((uintptr_t) 1 << ((n + 1) % (8 * sizeof(uintptr_t)))) - 1;
bitmap[i] = m;
map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t));
for (i = i + 1; i < map; i++) {
bitmap[i] = 0;
}
page->slab = shift;
page->next = &slots[slot];
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;
slots[slot].next = page;
pool->stats[slot].total += (ngx_pagesize >> shift) - n;
p = ngx_slab_page_addr(pool, page) + (n << shift);
pool->stats[slot].used++;
goto done;
} else if (shift == ngx_slab_exact_shift) {
page->slab = 1;
page->next = &slots[slot];
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;
slots[slot].next = page;
pool->stats[slot].total += 8 * sizeof(uintptr_t);
p = ngx_slab_page_addr(pool, page);
pool->stats[slot].used++;
goto done;
} else { /* shift > ngx_slab_exact_shift */
page->slab = ((uintptr_t) 1 << NGX_SLAB_MAP_SHIFT) | shift;
page->next = &slots[slot];
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;
slots[slot].next = page;
pool->stats[slot].total += ngx_pagesize >> shift;
p = ngx_slab_page_addr(pool, page);
pool->stats[slot].used++;
goto done;
}
}
p = 0;
pool->stats[slot].fails++;
done:
//ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,"slab alloc: %p", (void *) p);
return (void *) p;
}
void *
ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size)
{
void *p;
ngx_shmtx_lock(&pool->mutex);
p = ngx_slab_calloc_locked(pool, size);
ngx_shmtx_unlock(&pool->mutex);
return p;
}
void *
ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size)
{
void *p;
p = ngx_slab_alloc_locked(pool, size);
if (p) {
ngx_memzero(p, size);
}
return p;
}
void
ngx_slab_free(ngx_slab_pool_t *pool, void *p)
{
ngx_shmtx_lock(&pool->mutex);
ngx_slab_free_locked(pool, p);
ngx_shmtx_unlock(&pool->mutex);
}
void
ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p)
{
size_t size;
uintptr_t slab, m, *bitmap;
ngx_uint_t i, n, type, slot, shift, map;
ngx_slab_page_t *slots, *page;
//ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p);
if ((u_char *) p < pool->start || (u_char *) p > pool->end) {
ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_free(): outside of pool");
goto fail;
}
n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;
page = &pool->pages[n];
slab = page->slab;
type = ngx_slab_page_type(page);
switch (type) {
case NGX_SLAB_SMALL:
shift = slab & NGX_SLAB_SHIFT_MASK;
size = (size_t) 1 << shift;
if ((uintptr_t) p & (size - 1)) {
goto wrong_chunk;
}
n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift;
m = (uintptr_t) 1 << (n % (8 * sizeof(uintptr_t)));
n /= 8 * sizeof(uintptr_t);
bitmap = (uintptr_t *)
((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1));
if (bitmap[n] & m) {
slot = shift - pool->min_shift;
if (page->next == NULL) {
slots = ngx_slab_slots(pool);
page->next = slots[slot].next;
slots[slot].next = page;
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;
page->next->prev = (uintptr_t) page | NGX_SLAB_SMALL;
}
bitmap[n] &= ~m;
n = (ngx_pagesize >> shift) / ((1 << shift) * 8);
if (n == 0) {
n = 1;
}
i = n / (8 * sizeof(uintptr_t));
m = ((uintptr_t) 1 << (n % (8 * sizeof(uintptr_t)))) - 1;
if (bitmap[i] & ~m) {
goto done;
}
map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t));
for (i = i + 1; i < map; i++) {
if (bitmap[i]) {
goto done;
}
}
ngx_slab_free_pages(pool, page, 1);
pool->stats[slot].total -= (ngx_pagesize >> shift) - n;
goto done;
}
goto chunk_already_free;
case NGX_SLAB_EXACT:
m = (uintptr_t) 1 <<
(((uintptr_t) p & (ngx_pagesize - 1)) >> ngx_slab_exact_shift);
size = ngx_slab_exact_size;
if ((uintptr_t) p & (size - 1)) {
goto wrong_chunk;
}
if (slab & m) {
slot = ngx_slab_exact_shift - pool->min_shift;
if (slab == NGX_SLAB_BUSY) {
slots = ngx_slab_slots(pool);
page->next = slots[slot].next;
slots[slot].next = page;
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;
page->next->prev = (uintptr_t) page | NGX_SLAB_EXACT;
}
page->slab &= ~m;
if (page->slab) {
goto done;
}
ngx_slab_free_pages(pool, page, 1);
pool->stats[slot].total -= 8 * sizeof(uintptr_t);
goto done;
}
goto chunk_already_free;
case NGX_SLAB_BIG:
shift = slab & NGX_SLAB_SHIFT_MASK;
size = (size_t) 1 << shift;
if ((uintptr_t) p & (size - 1)) {
goto wrong_chunk;
}
m = (uintptr_t) 1 << ((((uintptr_t) p & (ngx_pagesize - 1)) >> shift)
+ NGX_SLAB_MAP_SHIFT);
if (slab & m) {
slot = shift - pool->min_shift;
if (page->next == NULL) {
slots = ngx_slab_slots(pool);
page->next = slots[slot].next;
slots[slot].next = page;
page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;
page->next->prev = (uintptr_t) page | NGX_SLAB_BIG;
}
page->slab &= ~m;
if (page->slab & NGX_SLAB_MAP_MASK) {
goto done;
}
ngx_slab_free_pages(pool, page, 1);
pool->stats[slot].total -= ngx_pagesize >> shift;
goto done;
}
goto chunk_already_free;
case NGX_SLAB_PAGE:
if ((uintptr_t) p & (ngx_pagesize - 1)) {
goto wrong_chunk;
}
if (!(slab & NGX_SLAB_PAGE_START)) {
ngx_slab_error(pool, NGX_LOG_ALERT,"ngx_slab_free(): page is already free");
goto fail;
}
if (slab == NGX_SLAB_PAGE_BUSY) {
ngx_slab_error(pool, NGX_LOG_ALERT,"ngx_slab_free(): pointer to wrong page");
goto fail;
}
size = slab & ~NGX_SLAB_PAGE_START;
ngx_slab_free_pages(pool, page, size);
ngx_slab_junk(p, size << ngx_pagesize_shift);
return;
}
/* not reached */
return;
done:
pool->stats[slot].used--;
ngx_slab_junk(p, size);
return;
wrong_chunk:
ngx_slab_error(pool, NGX_LOG_ALERT,"ngx_slab_free(): pointer to wrong chunk");
goto fail;
chunk_already_free:
ngx_slab_error(pool, NGX_LOG_ALERT,"ngx_slab_free(): chunk is already free");
fail:
return;
}
static ngx_slab_page_t *
ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages)
{
ngx_slab_page_t *page, *p;
for (page = pool->free.next; page != &pool->free; page = page->next) {
if (page->slab >= pages) {
if (page->slab > pages) {
page[page->slab - 1].prev = (uintptr_t) &page[pages];
page[pages].slab = page->slab - pages;
page[pages].next = page->next;
page[pages].prev = page->prev;
p = (ngx_slab_page_t *) page->prev;
p->next = &page[pages];
page->next->prev = (uintptr_t) &page[pages];
} else {
p = (ngx_slab_page_t *) page->prev;
p->next = page->next;
page->next->prev = page->prev;
}
page->slab = pages | NGX_SLAB_PAGE_START;
page->next = NULL;
page->prev = NGX_SLAB_PAGE;
pool->pfree -= pages;
if (--pages == 0) {
return page;
}
for (p = page + 1; pages; pages--) {
p->slab = NGX_SLAB_PAGE_BUSY;
p->next = NULL;
p->prev = NGX_SLAB_PAGE;
p++;
}
return page;
}
}
if (pool->log_nomem) {
ngx_slab_error(pool, NGX_LOG_CRIT,"ngx_slab_alloc() failed: no memory");
}
return NULL;
}
static void
ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
ngx_uint_t pages)
{
ngx_slab_page_t *prev, *join;
pool->pfree += pages;
page->slab = pages--;
if (pages) {
ngx_memzero(&page[1], pages * sizeof(ngx_slab_page_t));
}
if (page->next) {
prev = ngx_slab_page_prev(page);
prev->next = page->next;
page->next->prev = page->prev;
}
join = page + page->slab;
if (join < pool->last) {
if (ngx_slab_page_type(join) == NGX_SLAB_PAGE) {
if (join->next != NULL) {
pages += join->slab;
page->slab += join->slab;
prev = ngx_slab_page_prev(join);
prev->next = join->next;
join->next->prev = join->prev;
join->slab = NGX_SLAB_PAGE_FREE;
join->next = NULL;
join->prev = NGX_SLAB_PAGE;
}
}
}
if (page > pool->pages) {
join = page - 1;
if (ngx_slab_page_type(join) == NGX_SLAB_PAGE) {
if (join->slab == NGX_SLAB_PAGE_FREE) {
join = ngx_slab_page_prev(join);
}
if (join->next != NULL) {
pages += join->slab;
join->slab += page->slab;
prev = ngx_slab_page_prev(join);
prev->next = join->next;
join->next->prev = join->prev;
page->slab = NGX_SLAB_PAGE_FREE;
page->next = NULL;
page->prev = NGX_SLAB_PAGE;
page = join;
}
}
}
if (pages) {
page[pages].prev = (uintptr_t) page;
}
page->prev = (uintptr_t) &pool->free;
page->next = pool->free.next;
page->next->prev = (uintptr_t) page;
pool->free.next = page;
}
static void
ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level, char *text)
{
hloge("%s%s", text, pool->log_ctx);
}
void ngx_slab_test()
{
uint32_t poolsize = 10000;
ngx_slab_pool_t *sp = ngx_slab_sizes_init(poolsize);
sp->addr = sp;
sp->end = sp->addr + poolsize;
sp->min_shift = 3;
void *d = ngx_slab_alloc(sp, 10);
ngx_slab_free(sp, d);
free(sp);
}

95
common/slab/ngx_slab.h Executable file
View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
* thread safe
*/
#ifndef _NGX_SLAB_H_INCLUDED_
#define _NGX_SLAB_H_INCLUDED_
#include <stdint.h>
#include "hmutex.h"
#define ngx_memzero(buf, n) (void) memset(buf, 0, n)
#define ngx_memset(buf, c, n) (void) memset(buf, c, n)
#define ngx_shmtx_t hmutex_t
#define ngx_shmtx_lock hmutex_lock
#define ngx_shmtx_unlock hmutex_unlock
typedef uint8_t u_char;
typedef intptr_t ngx_int_t;
typedef uintptr_t ngx_uint_t;
typedef intptr_t ngx_flag_t;
#define ngx_align_ptr(p, a) \
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
typedef struct ngx_slab_page_s ngx_slab_page_t;
struct ngx_slab_page_s {
uintptr_t slab;
ngx_slab_page_t *next;
uintptr_t prev;
};
typedef struct {
ngx_uint_t total;
ngx_uint_t used;
ngx_uint_t reqs;
ngx_uint_t fails;
} ngx_slab_stat_t;
typedef struct {
size_t min_size;
size_t min_shift;
ngx_slab_page_t *pages;
ngx_slab_page_t *last;
ngx_slab_page_t free;
ngx_slab_stat_t *stats;
ngx_uint_t pfree;
u_char *start;
u_char *end;
ngx_shmtx_t mutex;
u_char *log_ctx;
u_char zero;
unsigned log_nomem:1;
void *data;
void *addr;
} ngx_slab_pool_t;
void ngx_slab_test();
ngx_slab_pool_t *ngx_slab_sizes_init(uint32_t pool_size);
void ngx_slab_init(ngx_slab_pool_t *pool);
void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size);
void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size);
void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size);
void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size);
void ngx_slab_free(ngx_slab_pool_t *pool, void *p);
void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p);
#endif /* _NGX_SLAB_H_INCLUDED_ */

88
common/standard.c Executable file
View File

@@ -0,0 +1,88 @@
/*************************************************
1. 头文件说明
File name : app_main.c
Module :
Author : amir
Version : 0.1
Created on : 2022-02-11
Description : 代码语法规范
Modify History:
1. Date: Author: Modification:
*************************************************/
#include <stdint.h>
#include "hlog.h"
/*[0]超过512字节的内存考虑要用堆内存, 特别是1K及以上禁止用栈内存*/
/*2. 注释标准:头文件宏标准*/
#ifndef __MAIN_H__ /* 3. 双下线__ */
#define __MAIN_H__
#endif
#define MAX(a, b) ((a) > (b) ? (a) : (b)) /* 4. 变量用括号() */ /* 注释用 *号进行,避免用 // */
#define MIN(a, b) ({int32_t ret; ret = (a) > (b) ? (b) : (a); ret+2;}) /* 5. 定义变量得到其值GNU支持({}), 其它代替do{}while(0) */
#define MAX_PATH (256) /* 6. 宏用大写*/
typedef enum {
STD_OK,
STD_NG,
}std_e; /* 7. 结构体 _e */
typedef struct {
uint8_t num; /* 8. num of pipeline -- 变量简明注释,特别是重要的变量 */
std_e e_std;
}std_s; /* 9. 结构体 _s */
static int32_t s_num; /* 10. 静态变量用 s_xxx */
static int32_t g_num; /* 11. 全局变量用 g_xxx, 尽量少用公共变量 ,全局变量减少耦合 */
static int32_t k_num; /* 12. 常量用 k_xxx */
static int32_t *p_num; /* 13. 指针变量用 p_xxx */
#define OK 0 /* 14. success */
#define NG 1 /* fail */
int32_t standard(void) { /* 15. 函数 花括号*/
hloge("<< %s %d", __func__, MIN(1,5));
return OK; /* 16. TAB键为4个空格 */
}
/* 17. <---- 函数间用空格分段 */
int32_t standard2(std_s *p_std) {/* 18. 1. 对于结构体入参尽可能用指针2. 指针变量用 p_xxx, 3. 指针符号*靠近变量 */
int32_t k = 1; /* 19. 不允许将多个短句放一行 */
uint32_t i = 0; /* 20. =号对齐 */
char *p_str = NULL; 0; /* 21. 变量或指针要尽量初始化,除非明确操作 */
{
uint8_t cnt = 0; /* 22. 变量靠近第一次使用处 */
cnt = cnt+cnt+cnt+cnt+cnt+cnt+cnt+cnt+cnt+cnt+cnt+cnt+cnt
+cnt; /* 23. 操作符放在新行首 */
}
switch ( i ) { /* 24. switch/while/if/for/do 独占一行,需要加花括号, 加空格,突出关键字 */
case 1:
break;
case 2:
break;
default:
break;
}
i = i + 1; /* 25. 操作符前面加空格 */
i += 1; /* 26. 选号对齐 */
if ( i > k ) {/* 27. i不能小于k -- while/if/for 写注释,有助于维护人员 */
k = ( i + k ) / 10; /* 28. 用括号表明操作顺序 */
}
#ifdef MAX_PATH
{ /* 29. 宏花括号 */
hlogi("<< %s MAX_PATH:%d", __func__, MAX_PATH);
}
#endif
return OK; /* 30. 用宏或有意义的变量表达, 禁止使用magic num */
}

410
common/threadpool/threadpool.c Executable file
View File

@@ -0,0 +1,410 @@
/*
* =====================================================================================
* Copyright (c), 2013-2020, Jz.
* Filename: ringbuffer.h
* Author: linux kernel,
* Organization: jz
*
* =====================================================================================
*/
/*************************************************
File name : ringbuffer.h
Module : common
Author : amir
Created on : 2023-01-6
Description :
a ringbuffer to store data(copy)
Modify History:
1. Date: Author: Modification:
202407 罗启宏 free时packet重复释放
*************************************************/
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include "list.h"
#include "htime.h"
#include "hthread.h"
#include "hbase.h"
#include "hlog.h"
#include "hmutex.h"
#include "threadpool.h"
#define TAG "TAG_THREADPOOL"
#define POOL_DEGUG 0
enum{
TASKLIST_FREE = 0,//unuse queue
TASKLIST_BUSYING, //normal task queue, all threads can run
TASKLIST_MAX,
}TASKLIST_TYPE;
/**
* @struct threadpool_task
* @brief the work struct
*
* @var function Pointer to the function that will perform the task.
* @var argument Argument to be passed to the function.
*/
typedef struct {
struct list_head link;
thread_routine routine;
kpacket *packet;
} threadpool_task_s;
typedef struct {
uint8_t busying;
uint32_t max_exe_time;
uint32_t total_exe_time;
uint32_t total_exe_cnt;
uint32_t th_idx;
hthread_t th;
} thread_info_s;
struct threadpool_s{
kpacket ref;
hmutex_t mutex;
hsem_t sem;
thread_info_s *threads_info;
uint8_t exit;
uint8_t thread_count;
uint8_t cur_th_idx; /*当前的id*/
uint8_t max_thread_count;
uint8_t all_thread_busy_times;
struct list_head route_queue[TASKLIST_MAX];
};
#define is_tasklist_empty(_QUEUE) list_empty(pool->route_queue[_QUEUE].next)
HTHREAD_ROUTINE(threadpool_thread){
threadpool *pool = (threadpool *)userdata;
hmutex_lock(&(pool->mutex));
thread_info_s *this_info = &pool->threads_info[pool->cur_th_idx];
this_info->th_idx = pool->cur_th_idx;
pool->cur_th_idx++;
hmutex_unlock(&(pool->mutex));
hlogd("%s start:%p th_idx:%u", __func__, userdata, this_info->th_idx);
while(!pool->exit) {
threadpool_task_s *task = NULL;
hmutex_lock(&(pool->mutex));
if (!is_tasklist_empty(TASKLIST_BUSYING)){
task = list_entry(pool->route_queue[TASKLIST_BUSYING].next, threadpool_task_s, link);
list_del(&task->link);
}
if (!task){
if(!pool->exit){
#if POOL_DEGUG
hlogd("wait th_idx:%u normal:%u", this_info->th_idx, is_tasklist_empty(TASKLIST_BUSYING));
#endif
hmutex_unlock(&(pool->mutex));
hsem_wait(&(pool->sem));
//hlogd("th_idx:%u", this_info->th_idx);
}
}
else
{
/* Get to work */
kpacket *packet = task->packet;
uint64_t elasped = gettimeofday_ms();
#if POOL_DEGUG
hlogd("task->routine:%p", task->routine);
#endif
this_info->busying = 1;
hmutex_unlock(&(pool->mutex));
task->routine(packet);
hmutex_lock(&(pool->mutex));
this_info->busying = 0;
elasped = gettimeofday_ms() - elasped;
if (elasped > this_info->max_exe_time){
this_info->max_exe_time = elasped;
}
this_info->total_exe_cnt ++;
this_info->total_exe_time += elasped;
packet ? kpacket_dec(packet) : 0;
list_add(&task->link, &pool->route_queue[TASKLIST_FREE]);
hmutex_unlock(&(pool->mutex));
}
}
hmutex_lock(&(pool->mutex));
pool->thread_count--;
hmutex_unlock(&(pool->mutex));
hlogw("%s exit thread_id:%ld\n",__func__, hv_gettid());
return(NULL);
}
/**
* @function void *threadpool_thread(void *threadpool)
* @brief the worker thread
* @param threadpool the pool which own the thread
*/
static uint32_t threadpool_free(threadpool *pool)
{
if (!pool) {
return -1;
}
/* Did we manage to allocate ? */
if (pool->threads_info) {
/* Because we allocate pool->threads_info after initializing the
mutex and condition variable, we're sure they're
initialized. Let's mutex the mutex just in case. */
hmutex_lock(&(pool->mutex));
struct list_head *pos, *n;
uint32_t i;
for(i=0; i<TASKLIST_MAX; i++){
list_for_each_safe(pos, n, &pool->route_queue[i]){
threadpool_task_s* task = list_entry(pos, threadpool_task_s, link);
list_del(pos);
if (task->packet && i != TASKLIST_FREE){
kpacket_dec(task->packet);
}
hv_free(task);
}
}
hmutex_unlock(&(pool->mutex));
hmutex_destroy(&(pool->mutex));
hsem_destroy(&(pool->sem));
hv_free(pool->threads_info);
pool->threads_info = NULL;
}
hv_free(pool);
return 0;
}
threadpool *threadpool_create(uint32_t max_thread_cnt)
{
threadpool *pool;
max_thread_cnt = max_thread_cnt <= 0 || max_thread_cnt > MAX_THREADS?MAX_THREADS:max_thread_cnt;
if ((pool = (threadpool *)hv_calloc(1, sizeof(threadpool))) == NULL) {
goto err;
}
/* Initialize */
INIT_LIST_HEAD(&pool->route_queue[TASKLIST_BUSYING]);
INIT_LIST_HEAD(&pool->route_queue[TASKLIST_FREE]);
pool->max_thread_count = max_thread_cnt;
/* Allocate thread and task queue */
pool->threads_info = (thread_info_s *)calloc(1, sizeof(thread_info_s) * max_thread_cnt);
/* Initialize mutex and conditional variable first */
if ((hmutex_init(&pool->mutex) != 0) ||
(hsem_init(&pool->sem, 0) != 0) ||
(pool->threads_info == NULL)) {
goto err;
}
return pool;
err:
if (pool) {
threadpool_free(pool);
}
return NULL;
}
static uint32_t threadpool_free_thread_count_locked(threadpool *pool){
uint32_t i, count = 0;
for(i=0; i < pool->thread_count && i<pool->max_thread_count; i++){
thread_info_s *info = &pool->threads_info[i];
count += info->busying ? 0 : 1;
}
//hlogd("%s %u", __func__, count);
return count;
}
static uint32_t threadpool_add_internal(threadpool *pool, thread_routine routine, kpacket *packet){
uint32_t err = 0;
if (pool == NULL || routine == NULL)
{
hlogd("ERR pool = %p or routine=%p", pool, routine);
return EINVAL;
}
if (hmutex_lock(&(pool->mutex)) != 0)
{
hlogd("ERR hmutex_lock");
return EPERM;
}
do {
/* Are we shutting down ? */
if (pool->exit) {
err = EBADRQC;
break;
}
threadpool_task_s *task;
if (is_tasklist_empty(TASKLIST_FREE)){
task = (threadpool_task_s *)hv_malloc(sizeof(threadpool_task_s));
}
else
{
task = list_entry(pool->route_queue[TASKLIST_FREE].next, threadpool_task_s, link);
list_del(&task->link);
}
if (!task)
{
err = ENOMEM;
break;
}
task->routine = routine;
task->packet = packet;
(void)(packet ? kpacket_inc(packet) : 0);
//if block task then add to block_list otherwise normal ready_list
//static cnt; hlogd("cnt:%u",cnt++);
list_add_tail(&task->link,&(pool->route_queue[TASKLIST_BUSYING]));
if (threadpool_free_thread_count_locked(pool) == 0 && pool->thread_count < pool->max_thread_count)
{
pool->threads_info[pool->thread_count].th = hthread_create(threadpool_thread, pool);
pool->thread_count++;
}
else
{
pool->all_thread_busy_times++;
// hloge("%s hv_free_threads:%u, thread_count:%u, max_thread_count:%u",__func__, threadpool_free_thread_count_locked(pool), pool->thread_count, pool->max_thread_count);
}
if (hsem_post(&pool->sem) != 0) {
err = EPERM;
break;
}
} while(0);
if (hmutex_unlock(&pool->mutex) != 0)
{
err = EPERM;
}
return err;
}
uint32_t threadpool_add(threadpool *pool, thread_routine routine, kpacket *packet)
{
return threadpool_add_internal(pool, routine, packet);
}
uint32_t threadpool_del(threadpool *pool, thread_routine routine){
uint32_t err = 0;
if (routine == NULL || pool == NULL) {
hloge("%s err routine:%p(!NULL) spool:%p(!NULL)",__func__, routine, pool );
return EINVAL;
}
if (hmutex_lock(&(pool->mutex)) != 0) {
return EPERM;
}
struct list_head *pos, *n;
uint32_t i;
for(i=0; i<TASKLIST_MAX; i++){
list_for_each_safe(pos, n, &pool->route_queue[i]){
threadpool_task_s* task = list_entry(pos, threadpool_task_s, link);
if (task->routine == routine){
list_del(pos);
if (task->packet && i != TASKLIST_FREE){
kpacket_dec(task->packet);
}
hv_free(task);
break;
}
}
}
if (hmutex_unlock(&pool->mutex) != 0) {
err = EPERM;
}
return err;
}
uint32_t threadpool_destroy(threadpool *pool)
{
uint32_t i, thread_cnt, err = 0;
if (pool == NULL) {
return EINVAL;
}
if (hmutex_lock(&(pool->mutex)) != 0) {
return EPERM;
}
do {
/* Already shutting down */
if (pool->exit) {
err = EBADRQC;
break;
}
thread_cnt = pool->thread_count;
pool->exit = 1;
hmutex_unlock(&(pool->mutex));
/* then Wake up all worker threads */
for(i=0; i<thread_cnt; i++){
if ((hsem_post(&(pool->sem)) != 0)) {
err = EPERM;
thread_info_s *info = &pool->threads_info[i];
hloge("%s err hsem_post th_idx:%d %p", __func__, info->th_idx, info->th);
}
}
/* Join all worker thread */
//hloge("%s thread_cnt %u", __func__, thread_cnt);
for(i = 0; i < thread_cnt && err == 0; i++) {
uint64_t start_ms = gettimeofday_ms();
thread_info_s *info = &pool->threads_info[i];
if (hthread_join(info->th) != 0) {
err = ESRCH;
hloge("%s hthread_join th_idx:%d %p", __func__, info->th_idx, info->th);
}else {
hlogw("%s %u/%u hthread_join th_idx:%d %p elapsed:%ul ms", __func__, i+1, thread_cnt, info->th_idx, info->th, gettimeofday_ms() - start_ms);
}
}
} while(0);
/* Only if everything went well do we deallocate the pool */
if (!err) {
threadpool_free(pool);
}
hlogw("%s",__func__);
return err;
}
void threadpool_dump(threadpool *pool){
hmutex_lock(&(pool->mutex));
uint32_t i;
hlogd("%s start", __func__);
hlogd("hv_free_thread:%u busy_times:%u max_thread_count:%u thread_count:%u",threadpool_free_thread_count_locked(pool), pool->all_thread_busy_times, pool->max_thread_count, pool->thread_count);
for(i=0; i< pool->thread_count && i<pool->max_thread_count; i++){
thread_info_s *info = &pool->threads_info[i];
hlogd("thread_info_s:%02d busy:%d exe_cnt:%u max_exe_time:%u total_exe_time:%u", info->th_idx, info->busying, info->total_exe_cnt, info->max_exe_time, info->total_exe_time);
}
hlogd("%s end", __func__);
hmutex_unlock(&(pool->mutex));
}
static void *test_routine(void *param)
{
hloge("%s th_id:%ld", __func__, hv_gettid());
hv_msleep(10);
return NULL;
}
void threadpool_test(){
hlogw("%s start", __func__);
threadpool *tp = threadpool_create(5);
for (uint32_t i = 10; i>0; i--){
threadpool_add(tp, test_routine, NULL);
hv_msleep(1);
}
hv_sleep(1);
threadpool_destroy(tp);
hlogw("%s end", __func__);
}
#if 0
kpacket *packet = kpacket_new(EVENT_HAL_DAYNIGHT, sizeof(uint32_t));
*packet->box->payload = IRCUT_NIGHT;
threadpool_add(pool, timer_callback, packet, 1000);
kpacket_dec(packet);
#endif

65
common/threadpool/threadpool.h Executable file
View File

@@ -0,0 +1,65 @@
#ifndef _THREADPOOL_H_
#define _THREADPOOL_H_
#include "kpacket.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void *(*thread_routine)(void *param);
/**
* @file threadpool.h
* @brief Threadpool Header File
*/
/**
* Increase this constants at your own risk
* Large values might slow down your system
*/
#define MAX_THREADS 16
typedef struct threadpool_s threadpool;
/**
* @function threadpool_create
* @brief Creates a threadpool object.
* @param thread_count Number of worker threads.
* @param queue_size Size of the queue(routine) for threadpool.
* @return a newly created thread pool or NULL
*/
threadpool *threadpool_create(uint32_t max_thread_cnt);
/**
* @function threadpool_add
* @brief add a new task in the queue of a thread pool
* @param pool Thread pool to which add the task.
* @param function Pointer to the function that will perform the task.
* @param packet Packet to be passed to the function.
* @return 0 if all goes well, negative values in case of error (@see
* threadpool_error_t for codes).
*/
uint32_t threadpool_add(threadpool *pool, thread_routine routine, kpacket *packet);
//delete a routine
uint32_t threadpool_del(threadpool *pool, thread_routine routine);
/**
* @function threadpool_destroy
* @brief Stops and destroys a thread pool.
* @param pool Thread pool to destroy.
*
* Known values for flags are 0 (default) and threadpool_graceful in
* which case the thread pool doesn't accept any new tasks but
* processes all pending tasks before shutdown.
*/
uint32_t threadpool_destroy(threadpool *pool);
void threadpool_dump(threadpool *pool);
void threadpool_test();
#ifdef __cplusplus
}
#endif
#endif /* _THREADPOOL_H_ */

2
common/utils/iot_math.c Executable file
View File

@@ -0,0 +1,2 @@
#include "iot_math.h"

46
common/utils/iot_math.h Executable file
View File

@@ -0,0 +1,46 @@
#ifndef _IOTMATH_H_INCLUDED
#define _IOTMATH_H_INCLUDED 1
#include <stdint.h>
/* 2的n次方数 */
#define roundup_pow_of_two(n) \
(1UL << \
( \
( \
(n) & (1UL << 31) ? 31 : \
(n) & (1UL << 30) ? 30 : \
(n) & (1UL << 29) ? 29 : \
(n) & (1UL << 28) ? 28 : \
(n) & (1UL << 27) ? 27 : \
(n) & (1UL << 26) ? 26 : \
(n) & (1UL << 25) ? 25 : \
(n) & (1UL << 24) ? 24 : \
(n) & (1UL << 23) ? 23 : \
(n) & (1UL << 22) ? 22 : \
(n) & (1UL << 21) ? 21 : \
(n) & (1UL << 20) ? 20 : \
(n) & (1UL << 19) ? 19 : \
(n) & (1UL << 18) ? 18 : \
(n) & (1UL << 17) ? 17 : \
(n) & (1UL << 16) ? 16 : \
(n) & (1UL << 15) ? 15 : \
(n) & (1UL << 14) ? 14 : \
(n) & (1UL << 13) ? 13 : \
(n) & (1UL << 12) ? 12 : \
(n) & (1UL << 11) ? 11 : \
(n) & (1UL << 10) ? 10 : \
(n) & (1UL << 9) ? 9 : \
(n) & (1UL << 8) ? 8 : \
(n) & (1UL << 7) ? 7 : \
(n) & (1UL << 6) ? 6 : \
(n) & (1UL << 5) ? 5 : \
(n) & (1UL << 4) ? 4 : \
(n) & (1UL << 3) ? 3 : \
(n) & (1UL << 2) ? 2 : \
(n) & (1UL << 1) ? 1 : \
(n) & (1UL << 0) ? 0 : -1 \
) + 1 \
) \
)
#endif

29
common/utils/ratelimit.c Executable file
View File

@@ -0,0 +1,29 @@
/**********************************************************************************************
File name : ratelimit.h
Module : common
Author :
Copyright :
Version : 0.1
Created on : 2021-11-18
Creator : amir.liang
Description :
以一定的速率执行入参函数, ratelimit(func()); 每次call这个调用默认每5秒最多执行一次func()
Modify History:
1. Date: Author: Modification:
************************************************************************************************/
#include "ratelimit.h"
static void retalimit_delay(){
hv_msleep(500);
}
void retalimit_test()
{
uint64_t start = gettimeofday_ms();
LOG_TIME(retalimit_delay());
while(gettimeofday_ms() - start < 1000){
ratelimit(printf("%s test\n", __func__));
}
LOG_TIME("retalimit_delay()");
}

103
common/utils/ratelimit.h Executable file
View File

@@ -0,0 +1,103 @@
/**********************************************************************************************
File name : ratelimit.h
Module : common
Author :
Copyright :
Version : 0.1
Created on : 2021-11-18
Creator : amir.liang
Description :
以一定的速率执行入参函数, ratelimit(func()); 每次call这个调用默认每5秒最多执行一次func()
Modify History:
1. Date: Author: Modification:
************************************************************************************************/
#ifndef __RATELIMIT_H__
#define __RATELIMIT_H__
#include <stdint.h>
#include "htime.h"
/**
* 参考linux kernel的 printk_ratelimited
*
* 使用方法:
* 默认5秒只执行1次
* ratelimit(printf("test\n"));
* *
* 设置成10秒可以执行30次
* ratelimit2(10, 30, printf("test\n"));
*/
struct ratelimit_state {
//下面是运行时信息
uint32_t interval_ms;
uint32_t next_ms;
};
struct task_time_state
{
uint32_t task_start;
uint32_t task_print_time;
};
#define DEFAULT_RATELIMIT_INTERVAL 5
#define DEFAULT_RATELIMIT_BURST 1
//第2个版本你也可以指定多少秒可以打印多少次
//ratelimit2(10, 30, printf("test\n"));
#define ratelimit2(_sec, _times, _action) \
({ \
static struct ratelimit_state _rs = { \
_sec*1000/_times, 0 \
}; \
uint32_t _now = gettimeofday_ms();\
if (_now >= _rs.next_ms){ \
_rs.next_ms = _now + _rs.interval_ms; \
_action; \
} \
})
//默认允许5秒打印1次log
//ratelimit(printf("test\n"));
#define ratelimit(_action) ratelimit2(DEFAULT_RATELIMIT_INTERVAL, 1, _action)
//尝试times直到action结果等于ifequ每次延时delayms
//do_retry2(action(), 10 100 0); 尝试10次action结果等于0时即退出每次延时100ms
#define do_retry2(_action, _times, _delayms, _ifequ_break)\
({ \
int32_t _t = _times;\
while(_t-->0){\
if (_ifequ_break)\
break;\
ratelimit2(1, 5, printf("waiting %dms:%s\n", _delayms, #_action));\
usleep(_delayms*1000);\
}\
})
//默认延时100ms, action结果等于0时退出
//do_retry(action(), 10); 尝试10次直到action结果等于0时即退出每次延时100ms
#define do_retry(_action, _times) do_retry2(_action, _times, 100, ==0)
#define LOG_TIME2(_start_ts, _action) ({\
uint64_t pre_ts = _start_ts == -1 ? gettimeofday_ms() : _start_ts;\
_action;\
printf("%lu %s take:%llums\n", pre_ts, #_action, gettimeofday_ms() - pre_ts);\
})
/*
* 计算某个函数或操作所消耗的时间
* _action, 可以是一个函数如: retalimit_delay()
* _action, 可以是一个字符串: "imin" 用于时间打印记录
*/
#define LOG_TIME(_action) LOG_TIME2(-1, _action)
void retalimit_test();
#endif //__RATELIMIT_H__

38
common/utils/util.c Executable file
View File

@@ -0,0 +1,38 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "hlog.h"
#include "util.h"
const char *get_filename(char *path)
{
CHECK_NULL_RETURN("path", path);
char *s1 = strrchr(path, '/');
char *s2 = strrchr(path, '\\');
if (s1 && s2) {
path = (s1 > s2) ? s1 + 1 : s2 + 1;
}
else if (s1)
path = s1 + 1;
else if (s2)
path = s2 + 1;
return path;
}
uint8_t file_exist(const char* path)
{
return !access(path, F_OK);
}
uint8_t isIP(const char*ip){
int32_t a,b,c,d;
char str[128];
return sscanf(ip,"%d.%d.%d.%d",&a,&b,&c,&d) == 4 || sscanf(ip,"%[^:]|%[^:]|%[^:]|%[^:]|%[^:]|%[^:]|%s",str,str,str,str,str,str,str) == 7;
}

94
common/utils/util.h Executable file
View File

@@ -0,0 +1,94 @@
/*************************************************************************
File name : util.h
Module : common
Author :
Copyright :
Version : 0.1
Created on : 2022-08-18
Creator : amir.liang
Description :
utils
Modify History:
1. Date: Author: Modification:
***************************************************************************/
#ifndef __UTIL_H__
#define __UTIL_H__
#include <stdint.h>
#ifndef OK
#define OK (uint8_t)(0)
#endif
#ifndef NG
#define NG (uint8_t)(1)
#endif
#ifndef MAX_PATH
#define MAX_PATH (256)
#endif
#ifndef MIN
#define MIN(x,y) (((x)<(y))?(x):(y))
#endif
#ifndef MAX
#define MAX(x,y) (((x)>(y))?(x):(y))
#endif
#define SET_BITS(value, bits) ((value) | (bits))
#define CLEAR_BITS(value, bits) ((value) & ~(bits))
#define CHECK_BITS(value, bits) ((value) & (bits))
#define TOGGLE_BITS(value, bits) ((value) ^ (bits))
// note: 'a' must be align 2
#define ROUNDUP(x, a) (((x) + (a)-1) & ~((a)-1)) // ALIGN(x, a)
#define CHECK_SAME(a, b) ({\
if ( a != b ){\
hloge("%s [%d]!=[%d], fail.", __func__, a, b); \
}; a==b;})
#define CHECK_SAME_RETURN(a, b) ({if (!CHECK_SAME(a, b) ){ return NG;}})
#define CHECK_NULL(who, val) ({if(!val){hloge("%s %s is null param", __func__, who);}; val;})
#define CHECK_NULL_RETURN(who, val) if (!CHECK_NULL(who, val)){return NULL;}
#define CHECK_LESS_RETURN(who, val) if(who<val){hloge("%s %d<%d", __func__, who, val); return NG;}
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
#endif
#define DECLAR_UT_CMD(FUNC, ARRAY, CMD, USAGE) \
{FUNC, ARRAY, ARRAY_SIZE(ARRAY), CMD, USAGE}
typedef struct unittest_st unittest_cmd;
typedef struct unittest_st
{
int32_t (*exec_func)(int32_t argc, char **argv); /* 如果不为NULL 即为终函数 */
unittest_cmd *next_cmd;
uint16_t next_cmd_cnt;
char *cmd_name;
char *cmd_help; /* 如果exec_func=NULL 即 一个'cmd_name'提示help*/
} unittest_cmd;
const char *get_filename(char *path);
uint8_t file_exist(const char* path);
uint8_t isIP(const char*ip);
#endif

2
common/workqueue/config.mk Executable file
View File

@@ -0,0 +1,2 @@
CORE_SRCDIRS += $(COM_DIR)/workqueue
FUSION_HEADERS += $(COM_DIR)/workqueue/*.h

67
common/workqueue/workqueue.c Executable file
View File

@@ -0,0 +1,67 @@
/*************************************************
File name : workqueue.h
Module :
Author : amir
Version : 0.1
Created on : 2022-02-07
Description :
Data structure and function definitions required by the socket interface
Modify History:
1. Date: Author: Modification:
*************************************************/
#include "threadpool.h"
#include "workqueue.h"
#include "hlog.h"
workqueue *workqueue_init(uint32_t max_cnt){
workqueue *wq = threadpool_create(max_cnt);
assert(wq);
return wq;
}
void workqueue_deinit(workqueue *wq){
if (wq){
threadpool_dump(wq);
threadpool_destroy(wq);
}
}
uint32_t workqueue_add(workqueue *wq, thread_routine routine, kpacket *packet){
return threadpool_add(wq, routine, packet );
}
static void *workqueue_test_handler(void *param){
kpacket *packet = (kpacket *)param;
hlogi("%s V:%u", __func__, *((int32_t *) packet->tlv.V));
return NULL;
};
void workqueue_test()
{
hlogi("%s start", __func__);
workqueue *wq = workqueue_init(5);
uint32_t i;
for(i=0; i<1000000;i++){
kpacket *packet = kpacket(1, 10);
hlogi("%s i:%u packet:%p", __func__, i, packet);
if (!packet){
hloge("%s i:%u packet:%p", __func__, i, packet);
hv_usleep(1000);
continue;
}
*((int32_t *) packet->tlv.V) = i;
workqueue_add(wq, workqueue_test_handler, packet);
kpacket_dec(packet);
}
workqueue_deinit(wq);
hlogi("%s stop", __func__);
}
void workqueue_dump(workqueue *wq)
{
threadpool_dump(wq);
}

47
common/workqueue/workqueue.h Executable file
View File

@@ -0,0 +1,47 @@
#ifndef __PAL_THREADPOOL_H__
#define __PAL_THREADPOOL_H__
#include <stdint.h>
#include "list.h"
#include "threadpool.h"
typedef threadpool workqueue;
/** workqueue_init
* [in] max_cnt, thread/task max count if need
//
void workqueue_deinit(workqueue *wq);
*/
workqueue *workqueue_init(uint32_t max_cnt);
/** workqueue_deinit
* no need to deinit commomly
*/
void workqueue_deinit(workqueue *wq);
// add a work to workqueue
// entry as callback
/**
* @brief Add a work to workqueue.
*
* @param [in] wq, workqueue instance.
* @param [in] entry, as callback func.
* @param [in] packet, param to entry.
* @param [in] type, urge level.
* @param [in] delayms, run after ms.
* @retval 0 Mutex lock create successfully.
* @retval ZFAILED Mutex lock create failed.
*
* @see os_mutex_delete
*/
uint32_t workqueue_add(workqueue *wq, thread_routine routine, kpacket *packet);
void workqueue_test();
void workqueue_dump();
#endif /* __PAL_THREADPOOL_H__ */

169
common/xbuf/xbuf.c Executable file
View File

@@ -0,0 +1,169 @@
#include "xbuf.h"
#include "errno.h"
#include "hlog.h"
#define TAG "TAG_XBUF"
uint32_t xbuf_init(xbuf_handler *hdlr)
{
iobuffer_init(&hdlr->read_io);
return OK;
}
uint32_t xbuf_deinit(xbuf_handler *hdlr)
{
iobuffer_deinit(&hdlr->read_io);
return OK;
}
uint32_t xbuf_put(xbuf_handler *hdlr, const char *data, const uint32_t sz)
{
if ( OK == iobuffer_appendData(&hdlr->read_io, data, sz) )
{
return xbuf_flush(hdlr);
}
return NG;
}
uint32_t xbuf_flush(xbuf_handler *hdlr)
{
kpacket *packet = (kpacket*)hdlr->read_io.iodata;
//hlogd("xbuf_flush len:%d magic:%x %d %d",packet->tlv.L, packet->tlv.magic,hdlr->read_io.size,sizeof(kpacket));
while ( hdlr->read_io.size >= sizeof(kpacket) + packet->tlv.L ) /* 粘包 或 包不齐处理 */
{
if ( packet->tlv.magic == OS_PACKET_MAGIC && kpacket_calc_checksum(packet) == packet->tlv.checksum ){
{ /* 如果 注册了type 处理 */
for ( uint16_t i=0; i< hdlr->ev_list_sz; i++ ){
//hlogd("xbuf_flush len:%d magic:%x",packet->tlv.T, hdlr->ev_list[i].event);
if ( hdlr->ev_list[i].event == packet->tlv.T ){
hdlr->ev_list[i].on_event(packet);
break;
}
}
}
{ /* 增加未注册type的, packet 处理*/
if ( hdlr->on_packet )
{
hdlr->on_packet(packet);
}
}
}else{
hloge("invalid %s magic:0x%x, calc_checksum:%x %x, V:%s", __func__, packet->tlv.magic, kpacket_calc_checksum(packet), packet->tlv.checksum,packet->tlv.V);
}
/* 删除packet占用的内存后面的数据将前移到0位置 */
iobuffer_erase(&hdlr->read_io, 0, sizeof(kpacket) + packet->tlv.L);
}
return OK;
}
/************************************ for tester ************************************/
/* 应用层四步
**
** 一, 声明枚举指令 和 回调函数
** 二, 填写 packet_event 的 ev_list
** 三, 通过xbuf_init注册到xbuf
** 四, 收数xbuf_put到xbuf, 自动回调
**/
/* 第一步 */
enum{
CMD_SYNC = 0x0001, /* 握手指令 */
};
static uint32_t on_sync(const kpacket *packet){
hlogw("%s magic:0x%x, type:%x, extend:%u, len:%u, payload:%s", __func__, packet->tlv.magic, packet->tlv.T, packet->offset, packet->tlv.L, packet->tlv.V);
return OK;
}
static packet_event s_ev_list[]={
{CMD_SYNC, on_sync},
};
/* 第二步 */
static xbuf_handler handler = {
.ev_list = s_ev_list,
.ev_list_sz = sizeof(s_ev_list)/sizeof(s_ev_list[0]),
};
/* 第三和四步 */
static uint32_t kpacket_recv(char *data, uint32_t max_sz);
void xbuf_test()
{
xbuf_init(&handler);
{
/* 用iobuffer */
for ( uint32_t i=0; i<10; i++ )
{
if ( iobuffer_freesize(&handler.read_io) < 1024 ) /* 如果预期接收的数据不小于1024大小也可是256/512字节点 那么扩容一下, 随协议来定*/
{
iobuffer_reserve(&handler.read_io, 1024 + handler.read_io.size); /* 小于1024了申请多些内存 */
}
/*第一种: 直接读到xbuf的iobuffer, 减少一次内存拷贝 */
uint32_t read_cnt = kpacket_recv(handler.read_io.iodata + handler.read_io.size, iobuffer_freesize(&handler.read_io));
if ( read_cnt > 0 )
{
handler.read_io.size += read_cnt;
kpacket *packet = (kpacket*)handler.read_io.iodata;
hlogd("xbuf_test read_cnt:%u %s",read_cnt, packet->tlv.V);
xbuf_flush(&handler); /*将自动回调对应的on_type*/
}
//hlogd("xbuf_test i:%u",i);
}
hlogd("xbuf_test end");
}
xbuf_deinit(&handler);
}
/* 串口, rndis 等的接收*/
static uint32_t kpacket_recv(char *data, uint32_t max_sz)
{
/*******这段为模拟发送端发送的数据 ,即接收*******/
static uint32_t i;
char str[128]; /* 没必要memset 或 ={0}, sprintf 会补 0 */
sprintf(str, "{\"sync\":\"i m :%u\"}", i++);
uint32_t size = strlen(str) + 1; /*+1 for '\0'*/
kpacket *packet = kpacket(CMD_SYNC, size);
kpacket_put_string(packet, str);
kpacket_checksum(packet); /* 生成 crc16 */
hlogd("%s magic:0x%x, calc_checksum:%x %x, V:%s", __func__, packet->tlv.magic, kpacket_calc_checksum(packet), packet->tlv.checksum, packet->tlv.V);
#if 0
send(packet, sizeof(kpacket)+packet->tlv.L); /* 发给接收端数据 */
#endif
/*********************end***********************/
/******* 这段为接收端数据拷贝到目标中data, 如iobuffer.iodata *******/
#if 0
recv_cnt = recv(data, max_sz); /* 发给接收端数据 */
#else
int32_t recv_cnt = sizeof(kpacket) + packet->tlv.L;
memcpy(data, packet, recv_cnt);
#endif
kpacket_dec(packet);/* 释放kpacket */
return recv_cnt;
}
/************************************end************************************/

84
common/xbuf/xbuf.h Executable file
View File

@@ -0,0 +1,84 @@
/*************************************************
File name : xbuf.h
Module :
Author : amir
Version : 0.1
Created on : 2024-04-27
Description : buf for protocol transmission
协议间传输
Modify History:
1. Date: Author: Modification:
*************************************************/
#ifndef __XBUF__
#define __XBUF__
#include <stdint.h>
#include "kpacket.h"
#include "iobuffer.h"
typedef struct{
uint16_t event;
uint32_t (*on_event)(const kpacket *packet);
}packet_event;
typedef struct{
/**
* @brief 当接收完整一包kpacket, 触发回调
*
* @param [in] box, box的地址.
*
*
*/
void (*on_packet)(const kpacket *packet);
packet_event *ev_list;
uint16_t ev_list_sz;
/* private data*/
iobuffer read_io;
/* 高阶应用
* 1. iobuffer_iobuffer_reserve(&read_io, 4096); // 设置iobuffer的缓冲大小
* 2. recv(read_io.iodata, read_io.capacity - read_io.size); xbuf_flush(); // 直接将数据读到iobuffer里,并尝试触发回调
**/
}xbuf_handler;
uint32_t xbuf_init(xbuf_handler *hdlr);
uint32_t xbuf_deinit(xbuf_handler *hdlr);
/**
* @brief 入数据处理, 满足包条件时触发on_packet回调
*
* @param [in] hdlr, 外部保存的xbuf_handler.
* @param [in] data, 入数.
* @param [in] sz, 入数长度.
* @note 成长返回OK, 返回NG内存不足--查一下read_io的capacity和size.
*
*/
uint32_t xbuf_put(xbuf_handler *hdlr, const char *data, const uint32_t sz);
/**
* @brief 尝试主动触发回调
*
* @param [in] hdlr, 外部保存的xbuf_handler.
* @note 成长返回OK, 返回NG内存不足--查一下read_io的capacity和size.
*
*/
uint32_t xbuf_flush(xbuf_handler *hdlr);
void xbuf_test();
#endif /* __XBUF__ */