code hierarchy refactoring
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* allocator.cpp
|
||||
*
|
||||
* Created on: Jan 28, 2020
|
||||
* Author: nnosov
|
||||
*/
|
||||
|
||||
#include "../src/utils/allocator.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void heap_free(pst_allocator* alloc, void* buff)
|
||||
{
|
||||
pthread_mutex_lock(&alloc->lock);
|
||||
alloc->size -= malloc_usable_size(buff);
|
||||
pthread_mutex_unlock(&alloc->lock);
|
||||
free(buff);
|
||||
}
|
||||
|
||||
void* heap_alloc(pst_allocator* alloc, uint32_t size)
|
||||
{
|
||||
void* buff = malloc(size);
|
||||
pthread_mutex_lock(&alloc->lock);
|
||||
alloc->size += malloc_usable_size(buff);
|
||||
pthread_mutex_unlock(&alloc->lock);
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
void* heap_realloc(pst_allocator* alloc, void* buff, uint32_t new_size)
|
||||
{
|
||||
pthread_mutex_lock(&alloc->lock);
|
||||
alloc->size -= malloc_usable_size(buff);
|
||||
void* new_buff = realloc(buff, new_size);
|
||||
alloc->size += malloc_usable_size(new_buff);
|
||||
pthread_mutex_unlock(&alloc->lock);
|
||||
|
||||
return new_buff;
|
||||
}
|
||||
|
||||
void pst_alloc_init(pst_allocator* alloc)
|
||||
{
|
||||
alloc->type = ALLOC_HEAP;
|
||||
alloc->base = NULL;
|
||||
alloc->size = 0;
|
||||
|
||||
alloc->alloc = heap_alloc;
|
||||
alloc->free = heap_free;
|
||||
alloc->realloc = heap_realloc;
|
||||
|
||||
pthread_mutex_init(&alloc->lock, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void pst_alloc_init_custom(pst_allocator* alloc, void* buff, uint32_t size)
|
||||
{
|
||||
// TBD to implement custom allocator
|
||||
pst_alloc_init(alloc);
|
||||
return;
|
||||
}
|
||||
|
||||
void pst_alloc_fini(pst_allocator* alloc)
|
||||
{
|
||||
if(alloc->type == ALLOC_HEAP || alloc->type == ALLOC_CUSTOM) {
|
||||
alloc->type = ALLOC_NONE;
|
||||
alloc->base = NULL;
|
||||
alloc->size = 0;
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&alloc->lock);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* allocator.h
|
||||
*
|
||||
* Created on: Jan 28, 2020
|
||||
* Author: nnosov
|
||||
*/
|
||||
|
||||
#ifndef PST_ALLOCATOR_H_
|
||||
#define PST_ALLOCATOR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// concatenation
|
||||
#define CAT(a, ...) CAT2(a, __VA_ARGS__)
|
||||
#define CAT2(a, ...) a ## __VA_ARGS__
|
||||
|
||||
// declaration with initialization and parameters of initialization
|
||||
#define pst_decl(TYPE, NAME, ...) \
|
||||
TYPE NAME; CAT2(TYPE, _init) (&NAME, __VA_ARGS__);
|
||||
|
||||
// declaration with initialization
|
||||
#define pst_decl0(TYPE, NAME) \
|
||||
TYPE NAME; CAT2(TYPE, _init) (&NAME);
|
||||
|
||||
// allocation with initialization
|
||||
#define pst_new(TYPE, NAME, ...) \
|
||||
TYPE* NAME; NAME = CAT2(TYPE, _new) (__VA_ARGS__);
|
||||
|
||||
// de-initialization and deletion if was previously allocated
|
||||
#define pst_fini(TYPE, NAME) \
|
||||
CAT2(TYPE, _fini) (NAME);
|
||||
|
||||
typedef enum {
|
||||
ALLOC_NONE = 0, // not initialized
|
||||
ALLOC_HEAP = 1, // use libc memory allocator
|
||||
ALLOC_CUSTOM = 2 // use custom allocator in predefined range of memory
|
||||
} pst_alloc_type;
|
||||
|
||||
typedef struct pst_allocator {
|
||||
// methods
|
||||
void* (*alloc)(pst_allocator* alloc, uint32_t size);
|
||||
void (*free)(pst_allocator* alloc, void* buff);
|
||||
void* (*realloc)(pst_allocator* alloc, void* buff, uint32_t new_size);
|
||||
|
||||
// fields
|
||||
int type;
|
||||
void* base;
|
||||
uint32_t size;
|
||||
pthread_mutex_t lock;
|
||||
|
||||
} pst_allocator;
|
||||
|
||||
void pst_alloc_init(pst_allocator* alloc);
|
||||
void pst_alloc_init_custom(pst_allocator* alloc, void* buff, uint32_t size);
|
||||
void pst_alloc_fini(pst_allocator* alloc);
|
||||
|
||||
#endif /* PST_ALLOCATOR_H_ */
|
||||
@@ -0,0 +1,328 @@
|
||||
/* =============================================================================
|
||||
* CDL (Configuration Definition Language) validator $Revision: 1.4 $
|
||||
* (C)2004-2007 Nikolay Nosov. All rights reserved.
|
||||
*
|
||||
* File: $RCSfile: hash_multimap.c,v $
|
||||
* Purpose: Hash Multimap implementation
|
||||
* Written by: Nikolay Nosov
|
||||
* Last modified: $Date: 2008/06/21 12:15:53 $ by $Author: nnosov $.
|
||||
*
|
||||
* For more information please visit
|
||||
* http://nsoft.volgocity.ru/cdl or
|
||||
* http://cdl.sourceforge.net
|
||||
* ===========================================================================*/
|
||||
#include "../src/utils/hash_multimap.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Default hash function
|
||||
@param key hash key
|
||||
@param size hash key size in bytes
|
||||
@return hash value, depends of the hash key
|
||||
*/
|
||||
static unsigned int default_hash_fn(const void *key, int size)
|
||||
{
|
||||
register int i, j;
|
||||
unsigned int cs = 0;
|
||||
unsigned int ps = 0;
|
||||
|
||||
if(key)
|
||||
{
|
||||
for(i = 0, j = 0; i < size; i++, j++)
|
||||
{
|
||||
ps |= ((unsigned int)((const char*)key)[i]) << (j * 8);
|
||||
if(j == 3 || j == (size - 1))
|
||||
{
|
||||
cs ^= ps;
|
||||
ps = 0;
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
static int default_compare_fn(const void *key1, const void *key2, const int size)
|
||||
{
|
||||
return !memcmp(key1, key2, size);
|
||||
}
|
||||
|
||||
/** Initialize hash node. Must be called before first usage of the node.
|
||||
|
||||
@param node pointer to the hash node descriptor
|
||||
*/
|
||||
void hash_node_init(struct hash_node *node)
|
||||
{
|
||||
node->key = NULL;
|
||||
node->key_size = 0;
|
||||
list_node_init(&node->node);
|
||||
}
|
||||
|
||||
/** Cleanup hash node
|
||||
|
||||
@param node pointer to the hash node descriptor
|
||||
*/
|
||||
void hash_node_cleanup(struct hash_node *node)
|
||||
{
|
||||
if(node->key) free(node->key);
|
||||
list_node_init(&node->node);
|
||||
node->key = NULL;
|
||||
node->key_size = 0;
|
||||
}
|
||||
|
||||
/** Initialize hash table
|
||||
|
||||
@param map pointer to the hash table descriptor
|
||||
@param hash_shift size of the hash table in bits. Should be greater than
|
||||
HASH_MIN_SHIFT and less than HASH_MAX_SHIFT. In case of less than HASH_MIN_SHIFT,
|
||||
will be followed by HASH_MIN_SHIFT, in case of greater HASH_MAX_SHIFT will be
|
||||
followed by HASH_MAX_SHIFT
|
||||
@param hf pointer to the user defined hash function. If NULL, then default hash
|
||||
function will be used
|
||||
@param cf pointer to the user defined compare function. if NULL, then the default
|
||||
compare function will be used
|
||||
*/
|
||||
int hash_head_init(struct hash_head *map, unsigned int hash_shift, _hash_fn hf, _compare_fn cf)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(map)
|
||||
{
|
||||
if(hash_shift <= HASH_MIN_SHIFT) {
|
||||
map->hash_shift = HASH_MIN_SHIFT;
|
||||
} else if(hash_shift >= HASH_MAX_SHIFT) {
|
||||
map->hash_shift = HASH_MAX_SHIFT;
|
||||
} else {
|
||||
map->hash_shift = hash_shift;
|
||||
}
|
||||
|
||||
map->hash_size = 1UL << map->hash_shift;
|
||||
map->hash_mask = (map->hash_size - 1);
|
||||
|
||||
map->bucket = (struct list_head *)malloc(sizeof(struct list_head) * map->hash_size);
|
||||
if(map->bucket)
|
||||
{
|
||||
for(i = 0; i < map->hash_size; i++)
|
||||
{
|
||||
list_head_init(map->bucket + i);
|
||||
}
|
||||
|
||||
if(hf) {
|
||||
map->hash_fn = hf;
|
||||
} else {
|
||||
map->hash_fn = default_hash_fn;
|
||||
}
|
||||
|
||||
if(cf) {
|
||||
map->compare_fn = cf;
|
||||
} else {
|
||||
map->compare_fn = default_compare_fn;
|
||||
}
|
||||
}
|
||||
else
|
||||
return ENOMEM;
|
||||
}
|
||||
else
|
||||
return ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Cleanup hash table descriptor
|
||||
|
||||
@param map pointer to the hash table descriptor
|
||||
*/
|
||||
void hash_head_cleanup(struct hash_head *map)
|
||||
{
|
||||
struct list_node *p, *n;
|
||||
struct hash_node *node;
|
||||
int i;
|
||||
|
||||
if(map)
|
||||
{
|
||||
if(map->bucket)
|
||||
{
|
||||
for(i = 0; i < map->hash_size; i++)
|
||||
{
|
||||
list_for_each_safe(p, n, map->bucket + i)
|
||||
{
|
||||
node = list_entry(p, struct hash_node, node);
|
||||
hash_node_cleanup(node);
|
||||
}
|
||||
}
|
||||
free(map->bucket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Find first node which key is equal to the key represented
|
||||
|
||||
@param map pointer to the hash table descriptor
|
||||
@param key pointer to the hash key
|
||||
@param key_size size of the hash key
|
||||
@return pointer to the key found, or NULL in case of hash table have not nodes
|
||||
with the key equals to the key represented
|
||||
*/
|
||||
struct hash_node* hash_find(struct hash_head *map, const void *key, int key_size)
|
||||
{
|
||||
struct list_head *list;
|
||||
struct list_node *n;
|
||||
struct hash_node *node;
|
||||
|
||||
list = map->bucket + (map->hash_fn(key, key_size) & map->hash_mask);
|
||||
list_for_each(n, list)
|
||||
{
|
||||
node = list_entry(n, struct hash_node, node);
|
||||
if(key_size == node->key_size)
|
||||
{
|
||||
if(map->compare_fn(key, node->key, key_size)) return node;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Find next node, which key is equal to the key represented
|
||||
|
||||
@param hn1 pointer to the previous node found.
|
||||
@return pointer to the next node with the same key, or NULL in case of the current
|
||||
node is the last node with appropriate key
|
||||
*/
|
||||
struct hash_node* hash_find_next(struct hash_head *map, struct hash_node *hn1)
|
||||
{
|
||||
struct list_node *n = &hn1->node;
|
||||
struct hash_node *hn2;
|
||||
|
||||
|
||||
while((n = list_next(n)) != NULL)
|
||||
{
|
||||
hn2 = list_entry(n, struct hash_node, node);
|
||||
if(hn1->key_size == hn2->key_size)
|
||||
{
|
||||
if(map->compare_fn(hn1->key, hn2->key, hn2->key_size)) return hn2;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Add node to the hash table
|
||||
|
||||
@param map pointer to the hash table
|
||||
@param node pointer to the node, which will be added to the table
|
||||
@param key pointer to the hash key
|
||||
@param key_size size of the hash key
|
||||
|
||||
@return zero in case of success, ENOMEM in case of error
|
||||
*/
|
||||
int hash_add(struct hash_head *map, struct hash_node *node, const void *key, int key_size)
|
||||
{
|
||||
node->key = (char*)malloc(key_size);
|
||||
if(node->key)
|
||||
{
|
||||
memcpy(node->key, key, key_size);
|
||||
node->key_size = key_size;
|
||||
list_add_bottom(map->bucket + (map->hash_fn(key, key_size) & map->hash_mask), &node->node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/** Remove node from the hash table
|
||||
|
||||
@param node pointer to the node descriptor
|
||||
*/
|
||||
void hash_del(struct hash_node *node)
|
||||
{
|
||||
list_del_init(&node->node);
|
||||
hash_node_cleanup(node);
|
||||
}
|
||||
|
||||
/** Initialize iterator for usage. Must be called before first iterator usage.
|
||||
|
||||
@param map pointer to the hash table descriptor
|
||||
@param iter pointer to the iterator descriptor
|
||||
*/
|
||||
void hash_iterator_init(struct hash_head *map, struct hash_iterator *iter)
|
||||
{
|
||||
iter->map = map;
|
||||
iter->map_idx = 0;
|
||||
iter->current = NULL;
|
||||
}
|
||||
|
||||
/** Move iterator to the first node in the table, and return pointer to the node
|
||||
|
||||
@param iter pointer to the iterator descriptor
|
||||
@return pointer to the first node in the table, or NULL in case of error
|
||||
*/
|
||||
struct hash_node * hash_node_first(struct hash_iterator *iter)
|
||||
{
|
||||
iter->current = list_first(iter->map->bucket);
|
||||
iter->map_idx = 0;
|
||||
|
||||
if (iter->current)
|
||||
{
|
||||
return list_entry(iter->current, struct hash_node, node);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Move iterator to the next node in the table and return pointer to the node
|
||||
|
||||
@param iter pointer to the iterator descriptor
|
||||
@return pointer to the next node in the table, or NULL in case of error
|
||||
*/
|
||||
struct hash_node * hash_node_next(struct hash_iterator *iter)
|
||||
{
|
||||
if(iter->map_idx >= iter->map->hash_size) return NULL;
|
||||
|
||||
if(iter->current) {
|
||||
iter->current = list_next(iter->current);
|
||||
}
|
||||
if(iter->current) {
|
||||
return list_entry(iter->current, struct hash_node, node);
|
||||
}
|
||||
|
||||
while(iter->map_idx < iter->map->hash_size) {
|
||||
iter->current = list_first(iter->map->bucket + iter->map_idx);
|
||||
iter->map_idx++;
|
||||
if(iter->current) {
|
||||
return list_entry(iter->current, struct hash_node, node);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Remove current node, pointed by iterator, and move iterator to the next node
|
||||
|
||||
@param iter pointer to the iterator descriptor
|
||||
*/
|
||||
void hash_node_del(struct hash_iterator *iter)
|
||||
{
|
||||
struct list_node *tmp;
|
||||
|
||||
tmp = iter->current;
|
||||
hash_node_next(iter);
|
||||
list_del_init(tmp);
|
||||
}
|
||||
|
||||
/** Return total count of elements in the hash table
|
||||
|
||||
@param head pointer to the hash table descriptor
|
||||
*/
|
||||
int hash_count(struct hash_head *head)
|
||||
{
|
||||
int i;
|
||||
int count = 0;
|
||||
|
||||
for(i = 0; i < head->hash_size; i++) count += list_count(head->bucket + i);
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#ifndef HASH_MULTIMAP_H
|
||||
#define HASH_MULTIMAP_H
|
||||
|
||||
#include "../src/utils/list_head.h"
|
||||
|
||||
#define HASH_MIN_SHIFT (8)
|
||||
#define HASH_MAX_SHIFT (15)
|
||||
|
||||
#define hash_entry(ptr, type, member) container_of(ptr, type, member)
|
||||
|
||||
/** Hash multimap node descriptor
|
||||
|
||||
@param key hash key value
|
||||
@param key_size hash key size in bytes
|
||||
@param node uplink to hash multimap table
|
||||
*/
|
||||
struct hash_node
|
||||
{
|
||||
char *key;
|
||||
int key_size;
|
||||
struct list_node node;
|
||||
};
|
||||
|
||||
/** Hash function prototype
|
||||
|
||||
@param key hash key value
|
||||
@param key_size hash key size in bytes
|
||||
@return hash value
|
||||
*/
|
||||
typedef unsigned int (* _hash_fn)(const void *key, int key_size);
|
||||
|
||||
/** Compare function prototype
|
||||
*
|
||||
* @param key1 pointer to the first key for comparison
|
||||
* @param key2 pointer to the second key for comparison
|
||||
* @param size size of compared part of the keys in bytes
|
||||
*
|
||||
* @return zero if keys equals each other, othervize 1
|
||||
*/
|
||||
typedef int (*_compare_fn)(const void *key1, const void *key2, int size);
|
||||
|
||||
/** Hash multimap table descriptor
|
||||
|
||||
@param hash_shift size of hash table as power of 2
|
||||
@param hash_size size of the hash table
|
||||
@param hash_mask mask for the hash value
|
||||
@param bucket pointer to the array of linked lists. in other words, pointer to
|
||||
hash multimap table
|
||||
@param count count of the nodes in the hash table
|
||||
*/
|
||||
struct hash_head
|
||||
{
|
||||
unsigned char hash_shift;
|
||||
unsigned short hash_size;
|
||||
unsigned int hash_mask;
|
||||
struct list_head *bucket;
|
||||
//int count;
|
||||
|
||||
_hash_fn hash_fn;
|
||||
_compare_fn compare_fn;
|
||||
};
|
||||
|
||||
/** Hash table iterator
|
||||
|
||||
@param map pointer to the hash table descriptor, used for iteration
|
||||
@param current pointer to the current list node (bucket[map_idx])
|
||||
@param map_idx current bucket index
|
||||
*/
|
||||
struct hash_iterator
|
||||
{
|
||||
struct hash_head *map; // pointer to the hash map header
|
||||
struct list_node *current; // pointer to current list node in the bucket[map_idx] list
|
||||
unsigned int map_idx; // index of current list in the hash map bucket
|
||||
};
|
||||
|
||||
void hash_node_init(struct hash_node *node);
|
||||
void hash_node_cleanup(struct hash_node *node);
|
||||
|
||||
int hash_head_init(struct hash_head *map, unsigned int hash_shift = HASH_MIN_SHIFT, _hash_fn hf = 0, _compare_fn cf = 0);
|
||||
void hash_head_cleanup(struct hash_head *map);
|
||||
|
||||
struct hash_node* hash_find(struct hash_head *map, const void *key, int key_size);
|
||||
struct hash_node* hash_find_next(struct hash_head *map, struct hash_node *node);
|
||||
|
||||
int hash_add(struct hash_head *map, struct hash_node *node, const void *key, int key_size);
|
||||
void hash_del(struct hash_node *node);
|
||||
|
||||
void hash_iterator_init(struct hash_head *map, struct hash_iterator *iter);
|
||||
struct hash_node * hash_node_first(struct hash_iterator *iter);
|
||||
struct hash_node * hash_node_next(struct hash_iterator *iter);
|
||||
void hash_node_del(struct hash_iterator *iter);
|
||||
int hash_count(struct hash_head *head);
|
||||
|
||||
#endif // HASH_MULTIMAP_H
|
||||
@@ -0,0 +1,338 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2006, Nikolay Nosov
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __LIST_HEAD_H__
|
||||
#define __LIST_HEAD_H__
|
||||
|
||||
/**
|
||||
Double linked list for user space implementation
|
||||
*/
|
||||
|
||||
#include <stddef.h> /* for NULL declaration */
|
||||
|
||||
/** Get offset of a member
|
||||
@param TYPE the type of the struct
|
||||
@param MEMBER the name of the member, which offset to be computed
|
||||
*/
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
/** Casts a member of a structure out to the containing structure
|
||||
@param ptr the pointer to the member.
|
||||
@param type the type of the container struct this is embedded in
|
||||
@param member the name of the member within the struct.
|
||||
*/
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type, member) );})
|
||||
|
||||
/** Get the struct for this entry
|
||||
@param ptr the &struct list_head pointer.
|
||||
@param type the type of the struct this is embedded in.
|
||||
@param member the name of the list_struct within the struct
|
||||
*/
|
||||
|
||||
#define list_entry(ptr, type, member) container_of(ptr, type, member)
|
||||
|
||||
/** Iterate over a list
|
||||
@param pos the &struct list_head to use as a loop counter.
|
||||
@param head the head for your list.
|
||||
*/
|
||||
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->first; pos; \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(tpos, pos, head, member) \
|
||||
for (pos = (head)->first; \
|
||||
pos && ({ tpos = list_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = pos->next)
|
||||
|
||||
|
||||
/** Iterate over list of given type safe against removal of list entry
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct list_node to use as a loop cursor.
|
||||
* @n: another &struct list_node to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_node within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(tpos, pos, n, head, member) \
|
||||
for (pos = (head)->first; \
|
||||
pos && ({ n = pos->next; 1; }) && \
|
||||
({ tpos = list_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = n)
|
||||
|
||||
|
||||
/** Iterate over a list backwards
|
||||
@param pos the &struct list_head to use as a loop counter.
|
||||
@param head the head for your list.
|
||||
*/
|
||||
|
||||
#define list_for_each_prev(pos, head) \
|
||||
for (pos = (head)->last; pos; \
|
||||
pos = pos->prev)
|
||||
|
||||
|
||||
/** Iterate over a list safe against removal of list entry
|
||||
@param pos the &struct list_head to use as a loop counter.
|
||||
@param n another &struct list_head to use as temporary storage
|
||||
@param head the head for your list.
|
||||
*/
|
||||
|
||||
#if !defined(list_for_each_safe)
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
|
||||
pos = n)
|
||||
#endif
|
||||
|
||||
/* to compiler be happy */
|
||||
|
||||
struct list_head;
|
||||
|
||||
/** Node of the list
|
||||
@param next next node in the list
|
||||
@param prev previous node in the list
|
||||
@param head head of the list
|
||||
*/
|
||||
|
||||
typedef struct list_node
|
||||
{
|
||||
struct list_node *next, *prev;
|
||||
struct list_head *head;
|
||||
} list_node;
|
||||
|
||||
|
||||
|
||||
/** Head of the list
|
||||
@param first first node in the list
|
||||
@param last last node in the list
|
||||
@param count cont of the nodes
|
||||
*/
|
||||
|
||||
typedef struct list_head
|
||||
{
|
||||
struct list_node *first, *last;
|
||||
int count;
|
||||
} list_head;
|
||||
|
||||
/**
|
||||
Compile time initialization of the head struct
|
||||
*/
|
||||
|
||||
#define LIST_HEAD_INIT { .first = NULL, .last = NULL, .count = 0 }
|
||||
|
||||
/**
|
||||
Compile time initialization of the node struct
|
||||
*/
|
||||
|
||||
#define LIST_NODE_INIT { .prev = NULL, .next = NULL, .head = NULL }
|
||||
|
||||
/** Runtime initialization of the head struct
|
||||
(should be applied before first using of the list)
|
||||
@param node head, which to be initialized.
|
||||
*/
|
||||
|
||||
static inline void list_head_init(struct list_head *head)
|
||||
{
|
||||
head->first = head->last = NULL;
|
||||
head->count = 0;
|
||||
}
|
||||
|
||||
|
||||
/** Runtime initialization of the node struct
|
||||
(should be applied before first using of the node)
|
||||
@param node node, which to be initialized.
|
||||
*/
|
||||
|
||||
static inline void list_node_init(struct list_node *node)
|
||||
{
|
||||
node->next = node->prev = NULL;
|
||||
node->head = NULL;
|
||||
}
|
||||
|
||||
/** Add node to begin of the list
|
||||
@param head the head of the list
|
||||
@param node node of the list, which to be added
|
||||
*/
|
||||
|
||||
static inline void list_add_head(struct list_head *head, struct list_node *node)
|
||||
{
|
||||
struct list_node *pfirst = head->first;
|
||||
head->first = node;
|
||||
node->next = pfirst;
|
||||
node->prev = NULL;
|
||||
node->head = head;
|
||||
|
||||
if(pfirst) pfirst->prev = node;
|
||||
else head->last = node;
|
||||
|
||||
head->count++;
|
||||
}
|
||||
|
||||
/** Add node to the end of the list
|
||||
@param head the head of the list;
|
||||
@param node node of the list, which to be added
|
||||
*/
|
||||
|
||||
static inline void list_add_bottom(struct list_head *head, struct list_node *node)
|
||||
{
|
||||
struct list_node *plast = head->last;
|
||||
|
||||
head->last = node;
|
||||
node->next = NULL;
|
||||
node->prev = plast;
|
||||
node->head = head;
|
||||
|
||||
if(plast) plast->next = node;
|
||||
else head->first = node;
|
||||
|
||||
head->count++;
|
||||
}
|
||||
|
||||
/** Add node in the list after given 'base' node
|
||||
@param base the base node, after that node will be added
|
||||
@param node node of the list, which to be added
|
||||
*/
|
||||
|
||||
static inline void list_add_after(struct list_node *base, struct list_node *node)
|
||||
{
|
||||
struct list_node *pnext = base->next;
|
||||
|
||||
base->next = node;
|
||||
node->next = pnext;
|
||||
node->prev = base;
|
||||
node->head = base->head;
|
||||
|
||||
if(pnext) pnext->prev = node;
|
||||
else base->head->last = node;
|
||||
|
||||
base->head->count++;
|
||||
}
|
||||
|
||||
/** Adds node in the list before given 'base' node
|
||||
@param base the base node, before that node will be added
|
||||
@param node node of the list, which to be added
|
||||
*/
|
||||
|
||||
static inline void list_add_before(struct list_node *base, struct list_node *node)
|
||||
{
|
||||
struct list_node *pprev = base->prev;
|
||||
|
||||
base->prev = node;
|
||||
node->next = base;
|
||||
node->prev = pprev;
|
||||
node->head = base->head;
|
||||
|
||||
if(pprev) pprev->next = node;
|
||||
else base->head->first = node;
|
||||
base->head->count++;
|
||||
}
|
||||
|
||||
/** Remove node from the list
|
||||
@param node the node, which to be removed
|
||||
*/
|
||||
|
||||
static inline void list_del(struct list_node *node)
|
||||
{
|
||||
if(node->head)
|
||||
{
|
||||
if(node->prev) node->prev->next = node->next;
|
||||
else node->head->first = node->next;
|
||||
if(node->next) node->next->prev = node->prev;
|
||||
else node->head->last = node->prev;
|
||||
node->head->count--;
|
||||
}
|
||||
|
||||
node->prev = node->next = NULL;
|
||||
node->head = NULL;
|
||||
}
|
||||
|
||||
static inline void list_del_init(struct list_node *node)
|
||||
{
|
||||
list_del(node);
|
||||
list_node_init(node);
|
||||
}
|
||||
|
||||
/** Count of the nodes in the list
|
||||
@param head the head of the list
|
||||
@return count of the nodes in the list
|
||||
*/
|
||||
|
||||
static inline int list_count(struct list_head *head)
|
||||
{
|
||||
return head->count;
|
||||
}
|
||||
|
||||
/** First element of the list
|
||||
@param head the head of the list
|
||||
@return pointer to first element of the list
|
||||
*/
|
||||
|
||||
static inline struct list_node* list_first(struct list_head *head)
|
||||
{
|
||||
return head->first;
|
||||
}
|
||||
|
||||
/** Last element of the list
|
||||
@param head the head of the list
|
||||
@return pointer to last element of the list
|
||||
*/
|
||||
|
||||
static inline struct list_node* list_last(struct list_head *head)
|
||||
{
|
||||
return head->last;
|
||||
}
|
||||
|
||||
/** Next element of the list
|
||||
@param head current element of the list
|
||||
@return pointer to next element relatively of current
|
||||
*/
|
||||
|
||||
static inline struct list_node* list_next(struct list_node *node)
|
||||
{
|
||||
return node->next;
|
||||
}
|
||||
|
||||
/** Previous element of the list
|
||||
@param head current element of the list
|
||||
@return pointer to previous element relatively of current
|
||||
*/
|
||||
|
||||
static inline struct list_node* list_prev(struct list_node *node)
|
||||
{
|
||||
return node->prev;
|
||||
}
|
||||
|
||||
#endif // __LIST_HEAD_H__
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
#include "../../src/utils/log.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char * const severity_map[] = {
|
||||
" [DEBUG] : ",
|
||||
" [INFO] : ",
|
||||
" [WARNING]: ",
|
||||
" [ERROR] : "
|
||||
};
|
||||
|
||||
void format_string(pst_log* log, const char* fmt, va_list args)
|
||||
{
|
||||
log->mStringLen += vsnprintf(log->mString + log->mStringLen, log->mStringSize - log->mStringLen, fmt, args);
|
||||
}
|
||||
|
||||
void format_prefix(pst_log* log, SC_LogSeverity severity)
|
||||
{
|
||||
time_t rawTime;
|
||||
struct tm * timeinfo;
|
||||
time(&rawTime);
|
||||
timeinfo = gmtime(&rawTime);
|
||||
|
||||
log->mStringLen += strftime(log->mString, sizeof(log->mString), "%d-%m-%Y %H:%M:%S", timeinfo);
|
||||
strncpy(log->mString + log->mStringLen, severity_map[(int)severity], strlen(severity_map[(int)severity]));
|
||||
log->mStringLen += strlen(severity_map[(int)severity]);
|
||||
}
|
||||
|
||||
void format_postfix(pst_log* log)
|
||||
{
|
||||
if((log->mStringLen + 2) < log->mStringSize) {
|
||||
log->mString[log->mStringLen++] = '\n';
|
||||
log->mString[log->mStringLen++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//variable argument number logging
|
||||
void log(pst_log* log, SC_LogSeverity severity, const char* fmt, ...)
|
||||
{
|
||||
if (severity < log->mCurrentSeverity)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&log->mLock);
|
||||
|
||||
if(!log->is_opened(log)) {
|
||||
log->open(log);
|
||||
}
|
||||
|
||||
log->mStringLen = 0;
|
||||
format_prefix(log, severity);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
format_string(log, fmt, args);
|
||||
va_end(args);
|
||||
format_postfix(log);
|
||||
log->send_message(log, severity);
|
||||
|
||||
pthread_mutex_unlock(&log->mLock);
|
||||
}
|
||||
|
||||
void log_init_base(pst_log* plog, const char* source)
|
||||
{
|
||||
// methods
|
||||
plog->log = log;
|
||||
|
||||
// fields
|
||||
plog->mpSource = 0;
|
||||
if(source) {
|
||||
plog->mpSource = strdup(source);
|
||||
}
|
||||
plog->mString[0] = 0;
|
||||
plog->mStringSize = sizeof(plog->mString);
|
||||
plog->mStringLen = 0;
|
||||
plog->mCurrentSeverity = SEVERITY_DEBUG;
|
||||
pthread_mutex_init(&plog->mLock, NULL);
|
||||
plog->child = 0;
|
||||
}
|
||||
|
||||
void pst_log_fini(pst_log* log)
|
||||
{
|
||||
pthread_mutex_destroy(&log->mLock);
|
||||
log->close(log);
|
||||
if(log->mpSource) {
|
||||
free(log->mpSource);
|
||||
log->mpSource = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Console logger implementation
|
||||
//
|
||||
#define RED "\e[0;31m"
|
||||
#define GREEN "\e[0;32m"
|
||||
#define YELLOW "\e[1;33m"
|
||||
#define NC "\e[0m" // No Color
|
||||
|
||||
//actually sends message to the source
|
||||
void send_msg_console(pst_log* log, SC_LogSeverity severity)
|
||||
{
|
||||
const char* color = NC;
|
||||
switch(severity) {
|
||||
case SEVERITY_DEBUG:
|
||||
color = NC;
|
||||
break;
|
||||
case SEVERITY_ERROR:
|
||||
color = RED;
|
||||
break;
|
||||
case SEVERITY_INFO:
|
||||
color = GREEN;
|
||||
break;
|
||||
case SEVERITY_WARNING:
|
||||
color = YELLOW;
|
||||
break;
|
||||
default:
|
||||
color = NC;
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s%s%s", color, log->mString, NC);
|
||||
}
|
||||
|
||||
void close_console(pst_log* log) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
bool open_console(pst_log* log) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_opened_console(pst_log* log) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void pst_log_init_console(pst_log* log)
|
||||
{
|
||||
log_init_base(log, NULL);
|
||||
log->close = close_console;
|
||||
log->open = open_console;
|
||||
log->is_opened = is_opened_console;
|
||||
log->send_message = send_msg_console;
|
||||
}
|
||||
|
||||
//
|
||||
// Log to file
|
||||
//
|
||||
|
||||
typedef struct _file_spec {
|
||||
FILE* fd;
|
||||
uint64_t max_bytes;
|
||||
uint64_t num_bytes;
|
||||
char* dir;
|
||||
char* fname;
|
||||
} file_spec;
|
||||
|
||||
//open file for writing
|
||||
bool open_file(pst_log* log)
|
||||
{
|
||||
file_spec* fsp = (file_spec*)log->child;
|
||||
if(!fsp) {
|
||||
fprintf(stderr, "Wrong initialization of File-based logger\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!fsp->fd) {
|
||||
// extract log and path names
|
||||
uint32_t namelen = strlen(log->mpSource);
|
||||
if(namelen) {
|
||||
const char* ptr = strrchr(log->mpSource, '/');
|
||||
uint32_t pathlen = 0;
|
||||
if(ptr) {
|
||||
pathlen = ptr - log->mpSource + 1;
|
||||
namelen -= pathlen + 1;
|
||||
}
|
||||
|
||||
fsp->dir = strndup(log->mpSource, pathlen);
|
||||
fsp->fname = strndup(log->mpSource + pathlen, namelen);
|
||||
|
||||
//open the file finally
|
||||
fsp->fd = fopen(log->mpSource, "a+");
|
||||
}
|
||||
}
|
||||
|
||||
return (fsp->fd != 0);
|
||||
}
|
||||
|
||||
void close_file(pst_log* log)
|
||||
{
|
||||
file_spec* fsp = (file_spec*)log->child;
|
||||
if(!fsp) {
|
||||
fprintf(stderr, "Wrong initialization of File-based logger while close\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(fsp->fd) {
|
||||
fclose(fsp->fd);
|
||||
}
|
||||
|
||||
fsp->fd = 0;
|
||||
fsp->max_bytes = 0;
|
||||
}
|
||||
|
||||
bool is_file_opened(pst_log* log)
|
||||
{
|
||||
file_spec* fsp = (file_spec*)log->child;
|
||||
if(!fsp) {
|
||||
fprintf(stderr, "Wrong initialization of File-based logger while check open\n");
|
||||
return false;
|
||||
}
|
||||
return (fsp->fd != 0);
|
||||
}
|
||||
|
||||
void send_msg_file(pst_log* log, SC_LogSeverity severity)
|
||||
{
|
||||
file_spec* fsp = (file_spec*)log->child;
|
||||
if(!fsp) {
|
||||
fprintf(stderr, "Wrong initialization of File-based logger while check send message\n");
|
||||
return;
|
||||
}
|
||||
if(fsp->fd && fsp->num_bytes < fsp->max_bytes) {
|
||||
if(fputs(log->mString, fsp->fd) >= 0) {
|
||||
fflush(fsp->fd);
|
||||
fsp->num_bytes += log->mStringLen;
|
||||
} else {
|
||||
fclose(fsp->fd);
|
||||
fsp->fd = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pst_log_init_file(pst_log* log, const char* path, uint64_t max_bytes)
|
||||
{
|
||||
log_init_base(log, path);
|
||||
file_spec* fsp = (file_spec*)malloc(sizeof(file_spec));
|
||||
fsp->fd = 0;
|
||||
fsp->max_bytes = max_bytes;
|
||||
fsp->num_bytes = 0;
|
||||
log->child = fsp;
|
||||
|
||||
log->close = close_file;
|
||||
log->open = open_file;
|
||||
log->is_opened = is_file_opened;
|
||||
log->send_message = send_msg_file;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef PST_LOG_H_
|
||||
#define PST_LOG_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <limits.h>
|
||||
|
||||
// Log message severity
|
||||
enum SC_LogSeverity {
|
||||
SEVERITY_DEBUG = 0,
|
||||
SEVERITY_INFO,
|
||||
SEVERITY_WARNING,
|
||||
SEVERITY_ERROR,
|
||||
//----------------
|
||||
SEVERITY_MAX
|
||||
};
|
||||
|
||||
#define LOG_BUFF_SIZE (1024*1024)
|
||||
|
||||
typedef struct __pst_log pst_log;
|
||||
|
||||
typedef struct __pst_log {
|
||||
// methods
|
||||
void (*close) (pst_log* log);
|
||||
bool (*open) (pst_log* log);
|
||||
bool (*is_opened) (pst_log* log);
|
||||
void (*log) (pst_log* log, SC_LogSeverity severity, const char* fmt, ...);
|
||||
void (*send_message) (pst_log* log, SC_LogSeverity severity);
|
||||
|
||||
// fields
|
||||
char* mpSource; // source for store log messages (file, IP:port or something else)
|
||||
|
||||
char mString[LOG_BUFF_SIZE]; // formatted string to be printed
|
||||
uint32_t mStringSize; // size of the 'mString' buffer
|
||||
uint32_t mStringLen; // length of the formatted string
|
||||
|
||||
SC_LogSeverity mCurrentSeverity; // maximum severity value to be logged
|
||||
pthread_mutex_t mLock;
|
||||
|
||||
void* child;
|
||||
} pst_log;
|
||||
|
||||
void pst_log_init_console(pst_log* log);
|
||||
void pst_log_init_file(pst_log* log, const char* path, uint64_t max_bytes = 64 * 1024 * 1024/* 64Mb */);
|
||||
void pst_log_fini(pst_log* log);
|
||||
|
||||
#endif /* PST_LOG_H_ */
|
||||
Reference in New Issue
Block a user