initial commit
This commit is contained in:
25
common/config.mk
Executable file
25
common/config.mk
Executable 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
154
common/iobuffer/iobuffer.c
Executable 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
42
common/iobuffer/iobuffer.h
Executable 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
224
common/jsonpacket/json_packet.c
Executable 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
77
common/jsonpacket/json_packet.h
Executable 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
171
common/kpacket.c
Executable 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
184
common/kpacket.h
Executable 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
116
common/ringbuffer/av_ringbuffer.c
Executable 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
113
common/ringbuffer/av_ringbuffer.h
Executable 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
320
common/ringbuffer/ringbuffer.c
Executable 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
94
common/ringbuffer/ringbuffer.h
Executable 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
837
common/slab/ngx_slab.c
Executable 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
95
common/slab/ngx_slab.h
Executable 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
88
common/standard.c
Executable 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
410
common/threadpool/threadpool.c
Executable 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
65
common/threadpool/threadpool.h
Executable 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
2
common/utils/iot_math.c
Executable file
@@ -0,0 +1,2 @@
|
||||
#include "iot_math.h"
|
||||
|
||||
46
common/utils/iot_math.h
Executable file
46
common/utils/iot_math.h
Executable 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
29
common/utils/ratelimit.c
Executable 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
103
common/utils/ratelimit.h
Executable 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
38
common/utils/util.c
Executable 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
94
common/utils/util.h
Executable 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
2
common/workqueue/config.mk
Executable file
@@ -0,0 +1,2 @@
|
||||
CORE_SRCDIRS += $(COM_DIR)/workqueue
|
||||
FUSION_HEADERS += $(COM_DIR)/workqueue/*.h
|
||||
67
common/workqueue/workqueue.c
Executable file
67
common/workqueue/workqueue.c
Executable 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
47
common/workqueue/workqueue.h
Executable 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
169
common/xbuf/xbuf.c
Executable 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
84
common/xbuf/xbuf.h
Executable 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__ */
|
||||
|
||||
Reference in New Issue
Block a user