Merge branch 'dev'
This commit is contained in:
@@ -42,6 +42,12 @@ AddOption('--coverage',
|
|||||||
help='Build with coverage (gcov) support'
|
help='Build with coverage (gcov) support'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AddOption('--with-assertions',
|
||||||
|
dest='assertions',
|
||||||
|
action='store_true',
|
||||||
|
help='Build with assertions enabled (Default for a debug build)'
|
||||||
|
)
|
||||||
|
|
||||||
AddOption('--stack-protection',
|
AddOption('--stack-protection',
|
||||||
dest = 'stack_protection',
|
dest = 'stack_protection',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@@ -51,6 +57,7 @@ AddOption('--stack-protection',
|
|||||||
|
|
||||||
|
|
||||||
build_type = GetOption('build_type')
|
build_type = GetOption('build_type')
|
||||||
|
assertions = GetOption('assertions')
|
||||||
test_xml = GetOption('test_xml')
|
test_xml = GetOption('test_xml')
|
||||||
prefix = GetOption('prefix')
|
prefix = GetOption('prefix')
|
||||||
if not (build_type in ['debug', 'release']):
|
if not (build_type in ['debug', 'release']):
|
||||||
@@ -81,6 +88,7 @@ env.Append(CPPPATH = ['#include'])
|
|||||||
if build_type == 'release':
|
if build_type == 'release':
|
||||||
env.Append(CFLAGS = ['-O2'])
|
env.Append(CFLAGS = ['-O2'])
|
||||||
|
|
||||||
|
if not assertions:
|
||||||
#this will turn off assert()
|
#this will turn off assert()
|
||||||
env.Append(CPPDEFINES = ['NDEBUG'])
|
env.Append(CPPDEFINES = ['NDEBUG'])
|
||||||
|
|
||||||
|
|||||||
+2
-10
@@ -1,5 +1,5 @@
|
|||||||
#ifndef BITEVEC_H_
|
#ifndef UC_BITEVEC_H_
|
||||||
#define BITEVEC_H_
|
#define UC_BITEVEC_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -65,14 +65,6 @@ void uc_bv_set_all(struct UCBitVec *v);
|
|||||||
* */
|
* */
|
||||||
void uc_bv_set_bits_from_array(struct UCBitVec *v,char *array,size_t array_len);
|
void uc_bv_set_bits_from_array(struct UCBitVec *v,char *array,size_t array_len);
|
||||||
|
|
||||||
// The _s ("secure") versions does boundary checking and assert() if they
|
|
||||||
// try to access a bit out of bounds.
|
|
||||||
|
|
||||||
void uc_bv_set_bit_s(struct UCBitVec *v,int b);
|
|
||||||
|
|
||||||
void uc_bv_clear_bit_s(struct UCBitVec *v,int b);
|
|
||||||
|
|
||||||
int uc_bv_get_bit_s(const struct UCBitVec *v,int b);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_BUFFER_H_
|
#ifndef UC_BUFFER_H_
|
||||||
#define UCORE_BUFFER_H_
|
#define uc_BUFFER_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef dbuf_H_
|
#ifndef UC_DBUF_H_
|
||||||
#define dbuf_H_
|
#define UC_DBUF_H_
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef FD_UTILS_H_
|
#ifndef UC_FD_UTILS_H_
|
||||||
#define FD_UTILS_H_
|
#define UC_FD_UTILS_H_
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_HASH_H_
|
#ifndef UC_HASH_H_
|
||||||
#define UCORE_HASH_H_
|
#define UC_HASH_H_
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_HEAPSORT_H_
|
#ifndef UC_HEAPSORT_H_
|
||||||
#define UCORE_HEAPSORT_H_
|
#define UC_HEAPSORT_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
#ifndef UC_HTABLE_H_
|
||||||
|
#define UC_HTABLE_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/** Building block for hash table.
|
||||||
|
* The hash table is stored using a chained list of buckets.
|
||||||
|
* Nodes with different hash value can be stored in the same bucket.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* The hash table manages only the hash value, not the equality
|
||||||
|
* between nodes.
|
||||||
|
*
|
||||||
|
* It's up to the user to check for duplicate values
|
||||||
|
* before adding nodes if dublicates are not desired.
|
||||||
|
*
|
||||||
|
* Finding a node must be done in a user specific way,
|
||||||
|
* normally by iterating over all nodes with the desidred
|
||||||
|
* hash, and deciding in some other way whether it is the desidred
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Node the hashtable tracks.
|
||||||
|
* Will normally be embedded inside another struct
|
||||||
|
*/
|
||||||
|
struct UHNode {
|
||||||
|
//cached value of the hash
|
||||||
|
size_t hash;
|
||||||
|
//pointer to next in same bucket
|
||||||
|
struct UHNode *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hash table struct
|
||||||
|
*/
|
||||||
|
struct UHTable {
|
||||||
|
size_t cnt_elements;
|
||||||
|
size_t cnt_buckets;
|
||||||
|
struct UHNode **buckets;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a hash table.
|
||||||
|
* @param table hash table to initialize
|
||||||
|
* @param buckets number of buckets
|
||||||
|
* @return 0 on success, errno if malloc fails or buckets == 0
|
||||||
|
*/
|
||||||
|
int uc_htable_init(struct UHTable *table, size_t buckets);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free resources of the hash table.
|
||||||
|
* @param table hash table to free (does not free @table itself
|
||||||
|
*/
|
||||||
|
void uc_htable_destroy(struct UHTable *table);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param table
|
||||||
|
* @param hash find the bucket from this hash value
|
||||||
|
* @return the bucket number for the given hash
|
||||||
|
*/
|
||||||
|
static inline size_t uc_htable_bucket(const struct UHTable *table, size_t hash)
|
||||||
|
{
|
||||||
|
return hash % table->cnt_buckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first bucket node for the given hash.
|
||||||
|
* The returned node might not have the same hash, since different
|
||||||
|
* nodes can share the same bucket.
|
||||||
|
*
|
||||||
|
* @param table table
|
||||||
|
* @param hash hash
|
||||||
|
*/
|
||||||
|
static inline struct UHNode *uc_htable_first_bucket(const struct UHTable *table, size_t hash)
|
||||||
|
{
|
||||||
|
size_t bucket = uc_htable_bucket(table, hash);
|
||||||
|
|
||||||
|
return table->buckets[bucket];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next node in the bucket.
|
||||||
|
* @return next node or NULL
|
||||||
|
*/
|
||||||
|
static inline struct UHNode *uc_htable_next_bucket(const struct UHNode *node)
|
||||||
|
{
|
||||||
|
return node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first node that have the given hash
|
||||||
|
* @param table table
|
||||||
|
* @param hash hash
|
||||||
|
* @return first node with the given hash or NULL
|
||||||
|
*/
|
||||||
|
struct UHNode *uc_htable_first_hash(const struct UHTable *table, size_t hash);
|
||||||
|
|
||||||
|
|
||||||
|
//internal helper
|
||||||
|
struct UHNode *uc_htable_next_hash_hlp(struct UHNode *next, size_t hash);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next node with the same hash
|
||||||
|
* @param node previous node
|
||||||
|
* @return next node with the same hash as node or NULL
|
||||||
|
*/
|
||||||
|
static inline struct UHNode *uc_htable_next_hash(const struct UHNode *node)
|
||||||
|
{
|
||||||
|
return uc_htable_next_hash_hlp(node->next, node->hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//internal helper
|
||||||
|
struct UHNode *uc_htable_iter_hlp(struct UHTable *table, size_t bucket);
|
||||||
|
|
||||||
|
/** Get the first node in the hash table
|
||||||
|
*
|
||||||
|
* @param table table
|
||||||
|
* @return first node or NULL
|
||||||
|
*/
|
||||||
|
static inline struct UHNode *uc_htable_first(struct UHTable *table)
|
||||||
|
{
|
||||||
|
return uc_htable_iter_hlp(table, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the next node in the hash table
|
||||||
|
*
|
||||||
|
* @param table table
|
||||||
|
* @param node previous node
|
||||||
|
* @return first node or NULL
|
||||||
|
*/
|
||||||
|
struct UHNode *uc_htable_next(struct UHTable *table, struct UHNode *node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap 2 hash tables.
|
||||||
|
*
|
||||||
|
* @param a first table
|
||||||
|
* @param b second table
|
||||||
|
*/
|
||||||
|
void uc_htable_swap(struct UHTable *a, struct UHTable *b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over all nodes in a bucket.
|
||||||
|
* The table must not be changed while iterating.
|
||||||
|
*
|
||||||
|
* @param table the struct UHTable*
|
||||||
|
* @param node_iter struct UHNode* for the current node being iterated
|
||||||
|
* @param hash size_t hash for the bucket to iterate
|
||||||
|
*/
|
||||||
|
#define UC_HTABLE_FOREACH_BUCKET(table, node_iter, hash)\
|
||||||
|
for ((node_iter) = uc_htable_first_bucket((table), (hash));\
|
||||||
|
(node_iter) != NULL;\
|
||||||
|
(node_iter) = uc_htable_next_bucket((node_iter)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over all nodes that has the given hash.
|
||||||
|
* The table must not be changed while iterating.
|
||||||
|
* Normally the user would check in a user specific way
|
||||||
|
* if the node_iter is equal to the node one wants to find.
|
||||||
|
*
|
||||||
|
* @param table the struct UHTable*
|
||||||
|
* @param node_iter struct UHNode* for the current node being iterated
|
||||||
|
* @param hash size_t hash for the node(s) to iterate over
|
||||||
|
*/
|
||||||
|
#define UC_HTABLE_FOREACH_HASH(table, node_iter, hash)\
|
||||||
|
for ((node_iter) = uc_htable_first_hash((table), (hash));\
|
||||||
|
(node_iter) != NULL;\
|
||||||
|
(node_iter) = uc_htable_next_hash((node_iter)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Safe" variant of UC_HTABLE_FOREACH_HASH, the iterated node
|
||||||
|
* (or any previously iterated nodes) can be freed while iterating
|
||||||
|
*
|
||||||
|
* @param table the struct UHTable*
|
||||||
|
* @param node_iter struct UHNode* for the current node being iterated
|
||||||
|
* @param next_iter struct UHNode* for the next node, required by the
|
||||||
|
* iteration, next_iter must not be altered while iterating.
|
||||||
|
* @param hash size_t hash for the node(s) to iterate over
|
||||||
|
*/
|
||||||
|
#define UC_HTABLE_FOREACH_HASH_SAFE(table, node_iter, next_iter, hash)\
|
||||||
|
for ((node_iter) = uc_htable_first_hash((table), (hash));\
|
||||||
|
(node_iter) != NULL && (((next_iter) = (node_iter->next)), 1);\
|
||||||
|
(node_iter) = (next))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over all nodes in a table
|
||||||
|
* The table must not be changed while iterating.
|
||||||
|
*
|
||||||
|
* @param table the struct UHTable*
|
||||||
|
* @param node_iter struct UHNode* for the current node being iterated
|
||||||
|
*/
|
||||||
|
#define UC_HTABLE_FOREACH(table, node_iter)\
|
||||||
|
for ((node_iter) = uc_htable_first((table));\
|
||||||
|
(node_iter) != NULL;\
|
||||||
|
(node_iter) = uc_htable_next((table), (node_iter)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Safe" variant of UC_HTABLE_FOREACH, the iterated node
|
||||||
|
* (or any previously iterated nodes) can be freed while iterating
|
||||||
|
*
|
||||||
|
* @param table the struct UHTable*
|
||||||
|
* @param node_iter struct UHNode* for the current node being iterated
|
||||||
|
* @param next_iter struct UHNode* for the next node, required by the
|
||||||
|
* iteration, next_iter must not be altered while iterating.
|
||||||
|
*/
|
||||||
|
#define UC_HTABLE_FOREACH_SAFE(table, node_iter, next_iter)\
|
||||||
|
for ((node_iter) = uc_htable_first((table));\
|
||||||
|
(node_iter) != NULL &&\
|
||||||
|
((next_iter) = uc_htable_next((table), (node_iter)), 1);\
|
||||||
|
(node_iter) = (next))
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given node pointer exists in the hash table
|
||||||
|
*
|
||||||
|
* @param table table
|
||||||
|
* @param node node to check for
|
||||||
|
* @return 0 if the node does not exist in table non-0 if it does
|
||||||
|
*/
|
||||||
|
int uc_htable_has_node(struct UHTable *table, struct UHNode *node);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return 0 if table is empty non-0 if it contains any nodes
|
||||||
|
*/
|
||||||
|
static inline int uc_htable_isempty(const struct UHTable *table)
|
||||||
|
{
|
||||||
|
return table->cnt_elements == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get number of elements in the hash table.
|
||||||
|
*
|
||||||
|
* @rparam table table
|
||||||
|
* @return number of elements
|
||||||
|
*/
|
||||||
|
static inline size_t uc_htable_count(const struct UHTable *table)
|
||||||
|
{
|
||||||
|
return table->cnt_elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Clears all nodes from the hash table, making it empty.
|
||||||
|
* No memory is released.
|
||||||
|
* @param table table to clear
|
||||||
|
*/
|
||||||
|
void uc_htable_clear(struct UHTable *table);
|
||||||
|
|
||||||
|
/** Insert a new node.
|
||||||
|
* The new node pointer must exist as long as it is part of the
|
||||||
|
* hash table. The hash table does not check for duplicates in any way.
|
||||||
|
*
|
||||||
|
* @param table table to insert into
|
||||||
|
* @param node new node to insert.
|
||||||
|
* @param hash hash value of the new node
|
||||||
|
*/
|
||||||
|
void uc_htable_insert(struct UHTable *table, struct UHNode *node, size_t hash);
|
||||||
|
|
||||||
|
/** Remove a node.
|
||||||
|
* If the node pointer is not part of the table,
|
||||||
|
* no action is taken
|
||||||
|
*
|
||||||
|
* @param table table to remove from.
|
||||||
|
* @param node node to remove.
|
||||||
|
*/
|
||||||
|
void uc_htable_remove(struct UHTable *table, struct UHNode *node);
|
||||||
|
|
||||||
|
/** Resize the hash table. This changes the number of buckets, and re-inserts
|
||||||
|
* all nodes.
|
||||||
|
*
|
||||||
|
* @param table table to resize
|
||||||
|
* @param buckets new number of buckets, must be > 0
|
||||||
|
* @return 0 on success, errno if malloc fails or buckets == 0
|
||||||
|
*/
|
||||||
|
int uc_htable_resize(struct UHTable *table, size_t buckets);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef IO_MUX_H_
|
#ifndef UC_IO_MUX_H_
|
||||||
#define IO_MUX_H_
|
#define UC_IO_MUX_H_
|
||||||
|
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
/** @addtogroup IOMux
|
/** @addtogroup IOMux
|
||||||
|
|||||||
+12
-9
@@ -1,5 +1,6 @@
|
|||||||
#ifndef UCORE_LOGGING_H_
|
#ifndef UC_LOGGING_H_
|
||||||
#define UCORE_LOGGING_H_
|
#define UC_LOGGING_H_
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
/** Logging functions.
|
/** Logging functions.
|
||||||
* All logging functions except uc_log_init are thread safe,
|
* All logging functions except uc_log_init are thread safe,
|
||||||
@@ -268,14 +269,16 @@ int uc_log_reopen_files(void);
|
|||||||
void uc_log_init(struct uc_log_modules *user_modules);
|
void uc_log_init(struct uc_log_modules *user_modules);
|
||||||
|
|
||||||
void uc_logf(int log_level, int module, int raw,
|
void uc_logf(int log_level, int module, int raw,
|
||||||
const char *file, int line, const char *fmt, ...)
|
const char *location, const char *fmt, ...)
|
||||||
__attribute__((format(printf, 6, 7)));
|
__attribute__((format(printf, 5, 6)));
|
||||||
|
|
||||||
#ifdef DEBUG
|
// only compile in UC_DEBUG log calls in debug mode, but allow the user
|
||||||
|
// to override that by defining UC_DEBUG_ALWAYS
|
||||||
|
#if defined(DEBUG) || defined(UC_DEBUG_ALWAYS)
|
||||||
# define UC_DEBUGF(mod, fmt, ...)\
|
# define UC_DEBUGF(mod, fmt, ...)\
|
||||||
uc_logf(UC_LL_DEBUG, mod,0 , __FILE__, __LINE__, fmt, ## __VA_ARGS__)
|
uc_logf(UC_LL_DEBUG, mod,0 , UC_SRC_LOCATION, fmt, ## __VA_ARGS__)
|
||||||
# define UC_DEBUGFR(mod, fmt, ...)\
|
# define UC_DEBUGFR(mod, fmt, ...)\
|
||||||
uc_logf(UC_LL_DEBUG, mod,1 , __FILE__, __LINE__, fmt, ## __VA_ARGS__)
|
uc_logf(UC_LL_DEBUG, mod,1 , UC_SRC_LOCATION, fmt, ## __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
# define UC_DEBUGF(mod, fmt, ...)
|
# define UC_DEBUGF(mod, fmt, ...)
|
||||||
# define UC_DEBUGFR(mod, fmt, ...)
|
# define UC_DEBUGFR(mod, fmt, ...)
|
||||||
@@ -292,14 +295,14 @@ void uc_logf(int log_level, int module, int raw,
|
|||||||
* @param ... printf style arguments
|
* @param ... printf style arguments
|
||||||
*/
|
*/
|
||||||
#define UC_LOGF(lvl, mod, fmt, ...) \
|
#define UC_LOGF(lvl, mod, fmt, ...) \
|
||||||
uc_logf(lvl, mod, 0, __FILE__, __LINE__, fmt, ## __VA_ARGS__)
|
uc_logf(lvl, mod, 0, UC_SRC_LOCATION, fmt, ## __VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
/** Raw logging ,Like UC_LOGF, but only prints the supplied
|
/** Raw logging ,Like UC_LOGF, but only prints the supplied
|
||||||
* data, not timestamp, log level etc.
|
* data, not timestamp, log level etc.
|
||||||
*/
|
*/
|
||||||
#define UC_LOGFR(lvl, mod, fmt, ...) \
|
#define UC_LOGFR(lvl, mod, fmt, ...) \
|
||||||
uc_logf(lvl, mod, 1, __FILE__, __LINE__, fmt, ## __VA_ARGS__)
|
uc_logf(lvl, mod, 1, UC_SRC_LOCATION, fmt, ## __VA_ARGS__)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_MATH_H_
|
#ifndef UC_MATH_H_
|
||||||
#define UCORE_MATH_H_
|
#define UC_MATH_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ struct MBuf {
|
|||||||
/**Arbitary pointer user can associate with the mbuf*/
|
/**Arbitary pointer user can associate with the mbuf*/
|
||||||
void *cookie;
|
void *cookie;
|
||||||
|
|
||||||
|
/*UC_MBUF_FLAGS. The upper 16 bits can be used by the application */
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
/** Total no of bytes from bufstart*/
|
/** Total no of bytes from bufstart*/
|
||||||
uint32_t allocated;
|
uint32_t allocated;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_MERSENNE_TWISTER_H
|
#ifndef UC_MERSENNE_TWISTER_H
|
||||||
#define UCORE_MERSENNE_TWISTER_H
|
#define UC_MERSENNE_TWISTER_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_PACK_H_
|
#ifndef UC_PACK_H_
|
||||||
#define UCORE_PACK_H_
|
#define UC_PACK_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#ifndef UC_RATE_LIMIT_H_
|
||||||
|
#define UC_RATE_LIMIT_H_
|
||||||
|
|
||||||
|
/** This is a rate limiter, based on the token bucket principle.
|
||||||
|
* We have X amount of tickets(=our rate) per Y amount of time,
|
||||||
|
*
|
||||||
|
* The allowed tickets increases with X per Y amount of time.
|
||||||
|
*
|
||||||
|
* Bursts will be allowed up till the number of tickets initially
|
||||||
|
* specified.
|
||||||
|
* e.g. if we are limited to 50 tickets * per 2 second, 50 tickets
|
||||||
|
* can be immedietely handed out in the
|
||||||
|
* first second. At the 2. second, 25 more tickets become available
|
||||||
|
* handed out, at the 3. second 25 more, and so on.
|
||||||
|
* (So this is throttleed, so no more than the initial tickets, 50 in
|
||||||
|
* this case, can be handed out in any given period)
|
||||||
|
*
|
||||||
|
* Another example is if we rate 1000 tickets per 60 seconds,
|
||||||
|
* 1000 tickets can be handed out the 1. second, 16/17 more the
|
||||||
|
* next second, 16/17 more the 3. second and so on.
|
||||||
|
*
|
||||||
|
* Specify how many tickes we have available per period of time.
|
||||||
|
* when work is performed, call uc_ratelimit_cllow() with the current
|
||||||
|
* time.
|
||||||
|
* The unit of time passed to uc_ratelimit_allow must be the same as
|
||||||
|
* for uc_ratelimit_init.
|
||||||
|
*
|
||||||
|
* Example for rate limiting accepting connections:
|
||||||
|
* struct RateLimit r;
|
||||||
|
* //Limit to 20 per 1 second, which also limits us to max 20
|
||||||
|
* per second. (1 second since we will pass in time that have 1 second resolution)
|
||||||
|
* 40 per 2 second would even out to the same rate, but allow a burst of 40
|
||||||
|
* (if there's 40 tickets available)
|
||||||
|
*
|
||||||
|
* uc_ratelimit_init(&r,20, 1, time(NULL));
|
||||||
|
*
|
||||||
|
* NOTE. (period + 1) * tickets must not exceed the range of the RateLimit.funds
|
||||||
|
*
|
||||||
|
* for (;;) {
|
||||||
|
* int fd = accept(..);
|
||||||
|
* if (uc_ratelimit_allow(&r, time(NULL)) {
|
||||||
|
* //handle new connection
|
||||||
|
* } else {
|
||||||
|
* //exceeded limit
|
||||||
|
* close(fd);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
struct RateLimit {
|
||||||
|
//how many tickets we want
|
||||||
|
long tickets;
|
||||||
|
//per this period of time
|
||||||
|
long period;
|
||||||
|
|
||||||
|
//internal fields:
|
||||||
|
|
||||||
|
//money we have to "buy" tickets
|
||||||
|
long funds;
|
||||||
|
//time of the previos period
|
||||||
|
long last_ts;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Static initializer for a struct RateLimit
|
||||||
|
*
|
||||||
|
* @param tickets number of tickets (bucket depth)
|
||||||
|
* @param period per this period
|
||||||
|
*/
|
||||||
|
#define UC_RATELIMIT_INITIALIZER(tickets)\
|
||||||
|
{ tickets, period, 0, -period}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a struct RateLimit, which can hand out @tickets per @period
|
||||||
|
* the perioid must be in the same units as the current_ts
|
||||||
|
*
|
||||||
|
* NOTE. 2 * (period + 1) * tickets must not exceed the range of the RateLimit.funds
|
||||||
|
*
|
||||||
|
* @param r RateLimit to initialize
|
||||||
|
* @param tickets number of tickets (bucket depth)
|
||||||
|
* @param period per this period
|
||||||
|
*/
|
||||||
|
void uc_ratelimit_init(struct RateLimit *r, long tickets, long period);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset a RateLimit, filling up the tickets again.
|
||||||
|
*
|
||||||
|
* @param r RateLimit to reset
|
||||||
|
* @param current ts, if non-zero, re-sets the last_ts to the current_ts
|
||||||
|
*/
|
||||||
|
void uc_ratelimit_reset(struct RateLimit *r, long current_ts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we have 1 ticket available, and can therefore allow
|
||||||
|
* the work. Removes 1 ticket if we can, and replenishes the tickets
|
||||||
|
* based on the elapsed time since last time the function was called.
|
||||||
|
*
|
||||||
|
* @param r the RateLimit
|
||||||
|
* @param current_ts the current timestamp. Used to calculate the
|
||||||
|
* replenisment of tichets since the previous check.
|
||||||
|
* @return 1 if we can allow, 0 if we don't.
|
||||||
|
*/
|
||||||
|
int uc_ratelimit_allow(struct RateLimit *r, long current_ts);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef RBTREE_H_
|
#ifndef UC_RBTREE_H_
|
||||||
#define RBTREE_H_
|
#define UC_RBTREE_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_READ_FILE_H_
|
#ifndef UC_READ_FILE_H_
|
||||||
#define UCORE_READ_FILE_H_y
|
#define UC_READ_FILE_H_y
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef SALLOC_H_
|
#ifndef UC_SALLOC_H_
|
||||||
#define SALLOC_H_
|
#define UC_SALLOC_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#ifndef UC_SATMATH_H_
|
||||||
|
#define UC_SATMATH_H_
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/** Implementation of saturated operation on uintxx_t.
|
/** Implementation of saturated operation on uintxx_t.
|
||||||
@@ -79,3 +81,4 @@ static inline uint64_t uc_sat_multu64(uint64_t a, uint64_t b)
|
|||||||
return UC_SAT_MULT(a, b, uint64_t, UINT64_MAX);
|
return UC_SAT_MULT(a, b, uint64_t, UINT64_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
#ifndef SEQ_H_
|
#ifndef UC_SEQ_H_
|
||||||
#define SEQ_H_
|
#define UC_SEQ_H_
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Check if a is less than b, taking care of wrap arounds
|
// Check if a is less than b, taking care of wrap arounds
|
||||||
|
|||||||
+39
-4
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_STRING_H_
|
#ifndef UC_STRING_H_
|
||||||
#define UCORE_STRING_H_
|
#define UC_STRING_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -17,16 +17,48 @@ uc_hex_decode(const char *in, size_t maxlen,uint8_t *out);
|
|||||||
char*
|
char*
|
||||||
uc_hex_encode_delim(const uint8_t *in, size_t inlen, char *out, int outlen, char *delim);
|
uc_hex_encode_delim(const uint8_t *in, size_t inlen, char *out, int outlen, char *delim);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the string to lowercase, calls tolower() on each char.
|
||||||
|
* @param s string to lowercase
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
uc_str_tolower(char *s);
|
uc_str_tolower(char *s);
|
||||||
|
/**
|
||||||
|
* Convert the string to uppercase, calls toupper() on each char.
|
||||||
|
* @param s string to uppercase
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
uc_str_toupper(char *s);
|
uc_str_toupper(char *s);
|
||||||
|
|
||||||
|
/** Macro to calculate the number of bytes required to BCD encode
|
||||||
|
* the number of ascii digits
|
||||||
|
*/
|
||||||
#define UC_BCD_LEN(ascii_len) ((ascii_len) / 2 + ((ascii_len) % 2))
|
#define UC_BCD_LEN(ascii_len) ((ascii_len) / 2 + ((ascii_len) % 2))
|
||||||
#define UC_ASCII_LEN(bcd_len) ((bcd_len) * 2 + 1)
|
|
||||||
|
|
||||||
|
/** Macro to calculate the number of bytes required to ASCII encode
|
||||||
|
* the number of BCD digits
|
||||||
|
*/
|
||||||
|
#define UC_ASCII_LEN(bcd_len) ((bcd_len) * 2)
|
||||||
|
|
||||||
|
/** Convert the ascii digits to BCD. Digits not in 0..9 are skipped.
|
||||||
|
*
|
||||||
|
* @param ascii string to BCD encode.
|
||||||
|
* @param bcdout resulting BCD data. Must be at least UC_BCD_LEN(strlen(asciii)) big
|
||||||
|
* @param filler filler byte(not the ascii digit) to write in the last BCD nibble
|
||||||
|
* if the number of ASCII digits is odd. This would usually be 0x0 or 0xf.
|
||||||
|
* @return the number of bytes written to bcdout
|
||||||
|
*/
|
||||||
size_t
|
size_t
|
||||||
uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler);
|
uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler);
|
||||||
|
|
||||||
|
/** Convert the BCD digits to ascii.
|
||||||
|
* The resulting ascii string is 0 terminated.
|
||||||
|
*
|
||||||
|
* @param bcd Buffer with BCD data to convert to ascii
|
||||||
|
* @param bcdlen number of bytes in @bcd to convert
|
||||||
|
* @param asciiout buffer to place ASCII in, must be UC_ASCII_LEN(bcdlen)+1 big
|
||||||
|
* @return the number of characters written to bcdout (this will always be UC_ASCII_LEN(bcdlen)
|
||||||
|
*/
|
||||||
size_t
|
size_t
|
||||||
uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout);
|
uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout);
|
||||||
|
|
||||||
@@ -39,10 +71,13 @@ uc_sprintbll(char *result, unsigned long long value);
|
|||||||
char*
|
char*
|
||||||
uc_sprintbs(char *result, unsigned short value);
|
uc_sprintbs(char *result, unsigned short value);
|
||||||
|
|
||||||
|
/** Like http://swtch.com/plan9port/man/man3/getfields.html
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
getfields(char *str, char **args, int max, int mflag, const char *set);
|
getfields(char *str, char **args, int max, int mflag, const char *set);
|
||||||
|
|
||||||
//ocnvert bytes to a human representable test, (i.e. 12kB, 160 MB 1.78 GB etc.
|
//Converts bytes to a human representable test, (i.e. 12kB, 160 MB 1.78 GB etc.)
|
||||||
|
//Conversion is done in decimal (base 10 ,1 kB == 1000 bytes)
|
||||||
///result should be at least of size 12,
|
///result should be at least of size 12,
|
||||||
///returns the result argument
|
///returns the result argument
|
||||||
char *
|
char *
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#ifndef UC_STRVEC_H_
|
#ifndef UC_STRVEC_H_
|
||||||
#define UC_STRVEC_H_
|
#define UC_STRVEC_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_SUPERVISOR_H_
|
#ifndef UC_SUPERVISOR_H_
|
||||||
#define UCORE_SUPERVISOR_H_
|
#define UC_SUPERVISOR_H_
|
||||||
|
|
||||||
/** Supervises this process - restart if it dies.
|
/** Supervises this process - restart if it dies.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef _THREADQUEUE_H_
|
#ifndef UC_THREADQUEUE_H_
|
||||||
#define _THREADQUEUE_H_ 1
|
#define UC_THREADQUEUE_H_
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ struct uc_threadmsg{
|
|||||||
/**
|
/**
|
||||||
* Callback function for the walk and destroy functions.
|
* Callback function for the walk and destroy functions.
|
||||||
*/
|
*/
|
||||||
typedef void (*uc_thread_queue_walk_func) (struct uc_threadmsg *msg);
|
typedef void (*uc_thread_queue_walk_func) (struct uc_threadmsg *msg, void *cookie);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,23 +240,40 @@ long uc_thread_queue_length( struct uc_threadqueue *queue );
|
|||||||
* @param queue Pointer to the queue that should be cleaned
|
* @param queue Pointer to the queue that should be cleaned
|
||||||
* @param free_func pointer to function that will be called for each item.
|
* @param free_func pointer to function that will be called for each item.
|
||||||
* The function must not in anyway interact with the queue.
|
* The function must not in anyway interact with the queue.
|
||||||
|
* @param cookie pointer passed back to the uc_thread_queue_walk_func
|
||||||
* @return 0 on success EINVAL if queue is NULL EBUSY if someone is holding any locks on the queue
|
* @return 0 on success EINVAL if queue is NULL EBUSY if someone is holding any locks on the queue
|
||||||
*/
|
*/
|
||||||
int uc_thread_queue_destroy(struct uc_threadqueue *queue, uc_thread_queue_walk_func free_func);
|
int uc_thread_queue_destroy(struct uc_threadqueue *queue, uc_thread_queue_walk_func free_func, void *cookie);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walk the elements of the queue, intended for debugging
|
* Walk the elements of the queue, intended for debugging
|
||||||
*
|
*
|
||||||
* The supplied function will be called for each item in the queue, internal queue
|
* The supplied function will be called for each item in the queue, internal queue
|
||||||
* locks are held while the function is called, so the supplied function must not
|
* locks are held while the function is called, so the supplied function must not
|
||||||
* interact with the queue, else deadlock occors.
|
* interact with the queue, else deadlock occurs.
|
||||||
*
|
*
|
||||||
* @param queue Pointer to the queue to walk
|
* @param queue Pointer to the queue to walk
|
||||||
* @param free_func pointer to function that will be called for each item.
|
* @param free_func pointer to function that will be called for each item.
|
||||||
|
* @param cookie pointer passed back to the uc_thread_queue_walk_func
|
||||||
* The function must not in anyway interact with the queue.
|
* The function must not in anyway interact with the queue.
|
||||||
* @return 0 on success
|
* @return 0 on success
|
||||||
*/
|
*/
|
||||||
int uc_thread_queue_walk(struct uc_threadqueue *queue, uc_thread_queue_walk_func walk_func);
|
int uc_thread_queue_walk(struct uc_threadqueue *queue, uc_thread_queue_walk_func walk_func, void *cookie);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the queue.
|
||||||
|
* The free_func unless NULL, will be called for each element
|
||||||
|
* locks are held while the function is called, so the supplied function must not
|
||||||
|
* interact with the queue, else deadlock occurs.
|
||||||
|
*
|
||||||
|
* @param queue Pointer to the queue to clear
|
||||||
|
* @param free_func pointer to function that will be called for each item, intended to e.g. release memory
|
||||||
|
* @param cookie pointer passed back to the uc_thread_queue_walk_func
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
int uc_thread_queue_clear(struct uc_threadqueue *queue, uc_thread_queue_walk_func free_func, void *cookie);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}*/
|
* @}*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_TIMERS_H_
|
#ifndef UC_TIMERS_H_
|
||||||
#define UCORE_TIMERS_H_
|
#define UC_TIMERS_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|||||||
+31
-18
@@ -1,23 +1,16 @@
|
|||||||
#ifndef UCORE_UTILS_H_
|
#ifndef UC_UTILS_H_
|
||||||
#define UCORE_UTILS_H_
|
#define UC_UTILS_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "backtrace.h"
|
||||||
|
|
||||||
//Gnerate a compiler error if the compile time
|
//Gnerate a compiler error if the compile time
|
||||||
//constant expression fails
|
//constant expression fails
|
||||||
#define UC_STATIC_ASSERT(expr) \
|
#define UC_STATIC_ASSERT(expr) \
|
||||||
do { \
|
enum { assert_static__ = 1/(expr) };
|
||||||
enum { assert_static__ = 1/(expr) }; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
#define TRACEF(fmt, ...)\
|
|
||||||
do { \
|
|
||||||
fprintf(stdout, "%s:%d (%s)\t" fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);\
|
|
||||||
fflush(stdout);\
|
|
||||||
} while(0)
|
|
||||||
#else
|
|
||||||
#define TRACEF(fmt, ...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//MAX of a and b
|
//MAX of a and b
|
||||||
#define UC_MAX(a,b) \
|
#define UC_MAX(a,b) \
|
||||||
@@ -78,22 +71,42 @@ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \
|
|||||||
#define UC_STRINGIFY(x) UC_STRINGIFY_HLP(x)
|
#define UC_STRINGIFY(x) UC_STRINGIFY_HLP(x)
|
||||||
#define UC_STRINGIFY_HLP(x) #x
|
#define UC_STRINGIFY_HLP(x) #x
|
||||||
|
|
||||||
|
/** Macro that expands to a string for the current file:line
|
||||||
|
*/
|
||||||
|
#define UC_SRC_LOCATION __FILE__ ":" UC_STRINGIFY(__LINE__)
|
||||||
/**
|
/**
|
||||||
* assert() that is not affected by NDEBUG define
|
* assert() that is not affected by NDEBUG define
|
||||||
*/
|
*/
|
||||||
#define UC_ASSERT(expr) do {\
|
#define UC_ASSERT(expr)\
|
||||||
|
do {\
|
||||||
if (!(expr) ) {\
|
if (!(expr) ) {\
|
||||||
fprintf(stderr,\
|
fprintf(stderr,\
|
||||||
"UC_ASSERT failed '%s' %s:%d\n", UC_STRINGIFY(expr), __FILE__, __LINE__);\
|
"UC_ASSERT failed '%s' %s\n", UC_STRINGIFY(expr), UC_SRC_LOCATION);\
|
||||||
uc_backtrace_fd(3);\
|
uc_backtrace_fd(2);\
|
||||||
abort();\
|
abort();\
|
||||||
|
}\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define TRACEF(fmt, ...)\
|
||||||
|
do { \
|
||||||
|
fprintf(stdout, "%s (%s)\t" fmt, UC_SRC_LOCATION, __FUNCTION__, ##__VA_ARGS__);\
|
||||||
|
fflush(stdout);\
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define TRACEF(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Macro for asserting code that should not be reached,
|
* Macro for asserting code that should not be reached,
|
||||||
* terminates the program if executed
|
* terminates the program if executed
|
||||||
*/
|
*/
|
||||||
#define UC_NOT_REACED() abort()
|
#define UC_NOT_REACED()\
|
||||||
|
do {\
|
||||||
|
fprintf(stderr, "UC_NOT_REACED at %s\n", UC_SRC_LOCATION);\
|
||||||
|
uc_backtrace_fd(2);\
|
||||||
|
abort();\
|
||||||
|
while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Round up X / y
|
* Round up X / y
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef UCORE_VERSION_H_
|
#ifndef UC_VERSION_H_
|
||||||
#define UCORE_VERSION_H_
|
#define UC_VERSION_H_
|
||||||
/**
|
/**
|
||||||
* @mainpage
|
* @mainpage
|
||||||
* @htmlonly
|
* @htmlonly
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ void uc_bv_free(struct UCBitVec *v)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void uc_bv_clr_bit(struct UCBitVec *v,int b)
|
void uc_bv_clr_bit(struct UCBitVec *v,int b)
|
||||||
{
|
{
|
||||||
v->vec[bit_index(b)] &= ~(1UL << (bit_offset(b)));
|
v->vec[bit_index(b)] &= ~(1UL << (bit_offset(b)));
|
||||||
@@ -64,40 +63,6 @@ void uc_bv_set_bit(struct UCBitVec *v,int b)
|
|||||||
v->vec[bit_index(b)] |= 1UL << (bit_offset(b));
|
v->vec[bit_index(b)] |= 1UL << (bit_offset(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
void uc_bv_set_bit_s(struct UCBitVec *v,int b)
|
|
||||||
{
|
|
||||||
size_t idx = (size_t)bit_index(b);
|
|
||||||
assert(b >= 0);
|
|
||||||
assert(v->vec_len > (size_t)idx);
|
|
||||||
|
|
||||||
if (likely(idx < v->vec_len))
|
|
||||||
v->vec[idx] |= 1UL << (bit_offset(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
void uc_bv_clear_bit_s(struct UCBitVec *v,int b)
|
|
||||||
{
|
|
||||||
size_t idx = (size_t)bit_index(b);
|
|
||||||
|
|
||||||
assert(b >= 0);
|
|
||||||
assert(v->vec_len > (size_t)idx);
|
|
||||||
|
|
||||||
if (likely(idx < v->vec_len))
|
|
||||||
v->vec[idx] &= ~(1UL << (bit_offset(b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
int uc_bv_get_bit_s(const struct UCBitVec *v,int b)
|
|
||||||
{
|
|
||||||
size_t idx = (size_t)bit_index(b);
|
|
||||||
|
|
||||||
assert(b >= 0);
|
|
||||||
assert(v->vec_len > (size_t)idx);
|
|
||||||
|
|
||||||
if (likely(idx < v->vec_len))
|
|
||||||
return !!(v->vec[idx] & (1UL << bit_offset(b)));
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uc_bv_set_bits_from_array(struct UCBitVec *v,char *array,size_t array_len)
|
void uc_bv_set_bits_from_array(struct UCBitVec *v,char *array,size_t array_len)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|||||||
+173
@@ -0,0 +1,173 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ucore/htable.h"
|
||||||
|
|
||||||
|
int uc_htable_init(struct UHTable *table, size_t buckets)
|
||||||
|
{
|
||||||
|
if (buckets == 0) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->buckets = calloc(buckets, sizeof *table->buckets);
|
||||||
|
if (table->buckets == NULL) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->cnt_buckets = buckets;
|
||||||
|
table->cnt_elements = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_htable_destroy(struct UHTable *table)
|
||||||
|
{
|
||||||
|
free(table->buckets);
|
||||||
|
table->buckets = NULL;
|
||||||
|
table->cnt_elements = table->cnt_buckets = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UHNode *uc_htable_first_hash(const struct UHTable *table, size_t hash)
|
||||||
|
{
|
||||||
|
size_t bucket = uc_htable_bucket(table, hash);
|
||||||
|
struct UHNode *it = table->buckets[bucket];
|
||||||
|
|
||||||
|
while (it && it->hash != hash) {
|
||||||
|
it = it->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
//given a node, find the next one in the chain with the given hash
|
||||||
|
struct UHNode *uc_htable_next_hash_hlp(struct UHNode *next, size_t hash)
|
||||||
|
{
|
||||||
|
while (next && next->hash != hash) {
|
||||||
|
next = next->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
//find a node, starting at bucket
|
||||||
|
struct UHNode *uc_htable_iter_hlp(struct UHTable *table, size_t bucket)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
struct UHNode *found = NULL;
|
||||||
|
|
||||||
|
//search through buckets until a node is found
|
||||||
|
for (i = bucket; i < table->cnt_buckets; i++) {
|
||||||
|
found = uc_htable_first_bucket(table, i);
|
||||||
|
if (found != NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UHNode *uc_htable_next(struct UHTable *table, struct UHNode *node)
|
||||||
|
{
|
||||||
|
struct UHNode *found;
|
||||||
|
|
||||||
|
found = uc_htable_next_bucket(node);
|
||||||
|
if (found == NULL) {
|
||||||
|
size_t current_bucket = uc_htable_bucket(table, node->hash);
|
||||||
|
found = uc_htable_iter_hlp(table, current_bucket + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_htable_swap(struct UHTable *a, struct UHTable *b)
|
||||||
|
{
|
||||||
|
struct UHTable tmp;
|
||||||
|
|
||||||
|
tmp = *a;
|
||||||
|
*a = *b;
|
||||||
|
*b = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_htable_has_node(struct UHTable *table, struct UHNode *node)
|
||||||
|
{
|
||||||
|
struct UHNode *iter;
|
||||||
|
|
||||||
|
UC_HTABLE_FOREACH_BUCKET(table, iter, node->hash) {
|
||||||
|
if (node == iter) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_htable_clear(struct UHTable *table)
|
||||||
|
{
|
||||||
|
memset(table->buckets, 0 , sizeof *table->buckets * table->cnt_buckets);
|
||||||
|
table->cnt_elements = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_htable_insert(struct UHTable *table, struct UHNode *node, size_t hash)
|
||||||
|
{
|
||||||
|
size_t bucket = uc_htable_bucket(table, hash);
|
||||||
|
|
||||||
|
node->next = table->buckets[bucket];
|
||||||
|
table->buckets[bucket] = node;
|
||||||
|
node->hash = hash;
|
||||||
|
|
||||||
|
table->cnt_elements++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_htable_remove(struct UHTable *table, struct UHNode *node)
|
||||||
|
{
|
||||||
|
struct UHNode **it = &table->buckets[uc_htable_bucket(table, node->hash)];
|
||||||
|
|
||||||
|
while (*it) {
|
||||||
|
|
||||||
|
if (*it == node) {
|
||||||
|
*it = (*it)->next;
|
||||||
|
table->cnt_elements--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
it = &(*it)->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_htable_resize(struct UHTable *table, size_t buckets)
|
||||||
|
{
|
||||||
|
struct UHTable tmp_table;
|
||||||
|
int rc;
|
||||||
|
size_t h;
|
||||||
|
|
||||||
|
if (buckets == 0) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//create new temp table
|
||||||
|
rc = uc_htable_init(&tmp_table, buckets);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//move all the nodes to the new temp table
|
||||||
|
for (h = 0; h < table->cnt_buckets; h++) {
|
||||||
|
struct UHNode *next;
|
||||||
|
struct UHNode *node;
|
||||||
|
|
||||||
|
for (node = uc_htable_first_bucket(table, h);
|
||||||
|
node != NULL;
|
||||||
|
node = next) {
|
||||||
|
next = node->next;
|
||||||
|
uc_htable_insert(&tmp_table, node, node->hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//replace the existing table with the resized temp table
|
||||||
|
uc_htable_swap(&tmp_table, table);
|
||||||
|
uc_htable_destroy(&tmp_table);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+7
-9
@@ -42,8 +42,7 @@ struct uc_log_args {
|
|||||||
struct uc_log_destination *dest;
|
struct uc_log_destination *dest;
|
||||||
const struct uc_log_module *module;
|
const struct uc_log_module *module;
|
||||||
int log_level;
|
int log_level;
|
||||||
const char *file;
|
const char *location;
|
||||||
int line;
|
|
||||||
int raw;
|
int raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -415,9 +414,9 @@ static inline void uc_vlog_file(const struct uc_log_args *args, const char *fmt,
|
|||||||
time_buf[sizeof time_buf -1] = 0;
|
time_buf[sizeof time_buf -1] = 0;
|
||||||
|
|
||||||
if (dest->log_location) {
|
if (dest->log_location) {
|
||||||
fprintf(dest->type.file.file, "[%-7s] %s %s:%d [%s] : ",
|
fprintf(dest->type.file.file, "[%-7s] %s %s [%s] : ",
|
||||||
uc_ll_2_str(args->log_level), time_buf, args->file,
|
uc_ll_2_str(args->log_level), time_buf,
|
||||||
args->line, args->module->short_name);
|
args->location, args->module->short_name);
|
||||||
} else {
|
} else {
|
||||||
fprintf(dest->type.file.file, "[%-7s] %s [%s]: ",
|
fprintf(dest->type.file.file, "[%-7s] %s [%s]: ",
|
||||||
uc_ll_2_str(args->log_level), time_buf, args->module->short_name);
|
uc_ll_2_str(args->log_level), time_buf, args->module->short_name);
|
||||||
@@ -446,7 +445,7 @@ static inline void uc_vlog_syslog(const struct uc_log_args *args, const char *fm
|
|||||||
|
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
if (dest->log_location) {
|
if (dest->log_location) {
|
||||||
rc = snprintf(buf, sizeof buf, "%s:%d ", args->file, args->line);
|
rc = snprintf(buf, sizeof buf, "%s ", args->location);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto log;
|
goto log;
|
||||||
offset += rc;
|
offset += rc;
|
||||||
@@ -543,7 +542,7 @@ void uc_log_destination_set_mask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void uc_logf(int log_level, int module, int raw,
|
void uc_logf(int log_level, int module, int raw,
|
||||||
const char *file, int line, const char *fmt, ...)
|
const char *location, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
struct uc_log_destination *dest;
|
struct uc_log_destination *dest;
|
||||||
@@ -581,8 +580,7 @@ void uc_logf(int log_level, int module, int raw,
|
|||||||
.dest = dest,
|
.dest = dest,
|
||||||
.module = log_module,
|
.module = log_module,
|
||||||
.log_level = log_level,
|
.log_level = log_level,
|
||||||
.file = file,
|
.location = location,
|
||||||
.line = line,
|
|
||||||
.raw = raw
|
.raw = raw
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include "ucore/rate_limit.h"
|
||||||
|
|
||||||
|
void uc_ratelimit_init(struct RateLimit *r, long tickets, long period)
|
||||||
|
{
|
||||||
|
r->tickets = tickets;
|
||||||
|
|
||||||
|
r->period = period;
|
||||||
|
r->funds = 0; //we fill it on first _allow call
|
||||||
|
r->last_ts = -period; //-period ensures the first tick can start
|
||||||
|
//at >= 0 and still refill the bicket
|
||||||
|
|
||||||
|
assert(tickets > 0);
|
||||||
|
assert(r->period > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_ratelimit_reset(struct RateLimit *r, long current_ts)
|
||||||
|
{
|
||||||
|
r->funds = r->period * r->tickets;
|
||||||
|
|
||||||
|
if (current_ts) {
|
||||||
|
r->last_ts = current_ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_ratelimit_allow(struct RateLimit *r, long current_ts)
|
||||||
|
{
|
||||||
|
int allowed;
|
||||||
|
long diff_period;
|
||||||
|
|
||||||
|
if (r->funds >= r->period) {
|
||||||
|
//we have enough
|
||||||
|
r->funds -= r->period;
|
||||||
|
allowed = 1;
|
||||||
|
} else { //refill
|
||||||
|
//Find elapsed time
|
||||||
|
diff_period = current_ts - r->last_ts;
|
||||||
|
|
||||||
|
if (diff_period > r->period + 1) {
|
||||||
|
//help prevent overflow when calculating available_tickets below
|
||||||
|
diff_period = r->period + 1;
|
||||||
|
} else if (diff_period < 0) {
|
||||||
|
//time went backwards, skip this round
|
||||||
|
diff_period = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Calculate the cost of tickets that became available
|
||||||
|
r->funds += diff_period * r->tickets;
|
||||||
|
|
||||||
|
|
||||||
|
//throttle handing out tickets
|
||||||
|
if (r->funds > r->period * r->tickets) {
|
||||||
|
r->funds = r->period * r->tickets;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If we have enough to buy atleast one ticket, we can allow
|
||||||
|
if (r->funds >= r->period) {
|
||||||
|
r->funds -= r->period;
|
||||||
|
allowed = 1;
|
||||||
|
} else {
|
||||||
|
//not enough to buy a ticket
|
||||||
|
allowed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//save this period.
|
||||||
|
r->last_ts = current_ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return allowed;
|
||||||
|
}
|
||||||
|
|
||||||
+46
-6
@@ -199,19 +199,21 @@ int uc_thread_queue_tryget(struct uc_threadqueue *queue,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void uc_thread_queue_walk_unlocked(struct uc_threadqueue *queue,
|
static void uc_thread_queue_walk_unlocked(struct uc_threadqueue *queue,
|
||||||
uc_thread_queue_walk_func walk_func)
|
uc_thread_queue_walk_func walk_func,
|
||||||
|
void *cookie)
|
||||||
{
|
{
|
||||||
struct uc_threadmsg *p;
|
struct uc_threadmsg *p;
|
||||||
struct uc_threadmsg *next;
|
struct uc_threadmsg *next;
|
||||||
|
|
||||||
for(p = queue->first; p; p = next) {
|
for(p = queue->first; p; p = next) {
|
||||||
next = p->next;
|
next = p->next;
|
||||||
walk_func(p);
|
walk_func(p, cookie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int uc_thread_queue_walk(struct uc_threadqueue *queue,
|
int uc_thread_queue_walk(struct uc_threadqueue *queue,
|
||||||
uc_thread_queue_walk_func walk_func)
|
uc_thread_queue_walk_func walk_func,
|
||||||
|
void *cookie)
|
||||||
{
|
{
|
||||||
if (queue == NULL || !walk_func) {
|
if (queue == NULL || !walk_func) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
@@ -219,7 +221,7 @@ int uc_thread_queue_walk(struct uc_threadqueue *queue,
|
|||||||
|
|
||||||
pthread_mutex_lock(&queue->mutex);
|
pthread_mutex_lock(&queue->mutex);
|
||||||
|
|
||||||
uc_thread_queue_walk_unlocked(queue, walk_func);
|
uc_thread_queue_walk_unlocked(queue, walk_func, cookie);
|
||||||
|
|
||||||
pthread_mutex_unlock(&queue->mutex);
|
pthread_mutex_unlock(&queue->mutex);
|
||||||
|
|
||||||
@@ -227,7 +229,8 @@ int uc_thread_queue_walk(struct uc_threadqueue *queue,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int uc_thread_queue_destroy(struct uc_threadqueue *queue,
|
int uc_thread_queue_destroy(struct uc_threadqueue *queue,
|
||||||
uc_thread_queue_walk_func free_func)
|
uc_thread_queue_walk_func free_func,
|
||||||
|
void *cookie)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -250,7 +253,7 @@ int uc_thread_queue_destroy(struct uc_threadqueue *queue,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (free_func) {
|
if (free_func) {
|
||||||
uc_thread_queue_walk_unlocked(queue, free_func);
|
uc_thread_queue_walk_unlocked(queue, free_func, cookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&queue->mutex);
|
pthread_mutex_unlock(&queue->mutex);
|
||||||
@@ -276,3 +279,40 @@ long uc_thread_queue_length(struct uc_threadqueue *queue)
|
|||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int uc_thread_queue_clear(struct uc_threadqueue *queue,
|
||||||
|
uc_thread_queue_walk_func free_func,
|
||||||
|
void *cookie)
|
||||||
|
{
|
||||||
|
if (queue == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&queue->mutex);
|
||||||
|
|
||||||
|
//Let the caller free the data
|
||||||
|
if (free_func != NULL) {
|
||||||
|
uc_thread_queue_walk_unlocked(queue, free_func, cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
//reset the elements
|
||||||
|
queue->first = NULL;
|
||||||
|
queue->num_elements = 0;
|
||||||
|
queue->last = &queue->first;
|
||||||
|
|
||||||
|
//notify writes, there should be space now
|
||||||
|
if (queue->num_write_waiters == 1) {
|
||||||
|
//if there's just one thread waiting to push elements
|
||||||
|
//use _cond_signal. _cond_broadcast can be more expensive (os dependent)
|
||||||
|
pthread_cond_signal(&queue->write_cond);
|
||||||
|
} else if (queue->num_write_waiters > 1) {
|
||||||
|
//signall all threads that there's items available.
|
||||||
|
pthread_cond_broadcast(&queue->write_cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&queue->mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ void uc_timers_remove(struct UCTimers *timers, struct UCTimer *timer)
|
|||||||
timer->ready_entry.tqe_prev = (struct UCTimer **)105;
|
timer->ready_entry.tqe_prev = (struct UCTimer **)105;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
assert(timer->state == UC_TIMER_ACTIVE ||
|
||||||
|
timer->state == UC_TIMER_PENDING);
|
||||||
|
|
||||||
uc_rb_remove(&timers->timer_tree, &timer->rb_node); //remove it, safe for the
|
uc_rb_remove(&timers->timer_tree, &timer->rb_node); //remove it, safe for the
|
||||||
//callback to re_add it
|
//callback to re_add it
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "ucore/rate_limit.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct RateLimit r;
|
||||||
|
time_t start = time(NULL);
|
||||||
|
|
||||||
|
uc_ratelimit_init(&r, 30, 2);
|
||||||
|
|
||||||
|
for(i = 0; i < 120; i++) {
|
||||||
|
int k;
|
||||||
|
long allowed = 0;
|
||||||
|
sleep(1);
|
||||||
|
time_t now = time(NULL);
|
||||||
|
for (k = 0; k < 5000; k++)
|
||||||
|
allowed += uc_ratelimit_allow(&r, now);
|
||||||
|
printf("%3ld of 500 can pass i=%3d, time = %3ld\n", allowed,i , (long)(now - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ START_TEST (test_2bcd_2_filler)
|
|||||||
fail_if(len != 2, "len is %zu", len);
|
fail_if(len != 2, "len is %zu", len);
|
||||||
fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]);
|
fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]);
|
||||||
fail_if(bcd[1] != 0xf3,"was 0x%x",bcd[1]);
|
fail_if(bcd[1] != 0xf3,"was 0x%x",bcd[1]);
|
||||||
|
fail_if(UC_BCD_LEN(strlen(ascii)) != len);
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_2bcd_3_filler)
|
START_TEST (test_2bcd_3_filler)
|
||||||
@@ -98,6 +99,7 @@ START_TEST (test_2hex_1)
|
|||||||
fail_if(ascii[2] != '3',"2 was %c",ascii[2]);
|
fail_if(ascii[2] != '3',"2 was %c",ascii[2]);
|
||||||
fail_if(ascii[3] != '4',"3 was %c",ascii[3]);
|
fail_if(ascii[3] != '4',"3 was %c",ascii[3]);
|
||||||
fail_if(ascii[4] != 0, "4 was %c",ascii[4]);
|
fail_if(ascii[4] != 0, "4 was %c",ascii[4]);
|
||||||
|
fail_if(UC_ASCII_LEN(sizeof bcd) != len);
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_2hex_2)
|
START_TEST (test_2hex_2)
|
||||||
|
|||||||
@@ -0,0 +1,379 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ucore/htable.h>
|
||||||
|
#include <ucore/utils.h>
|
||||||
|
|
||||||
|
struct MyString {
|
||||||
|
char str[32];
|
||||||
|
struct UHNode node;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t hash_str(const char *str)
|
||||||
|
{
|
||||||
|
size_t hash = 31;
|
||||||
|
while (*str) {
|
||||||
|
hash *= *str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bad_hash(const char *str)
|
||||||
|
{
|
||||||
|
return str[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyString *my_find(struct UHTable *table, const char *str, size_t hash)
|
||||||
|
{
|
||||||
|
struct UHNode *it;
|
||||||
|
|
||||||
|
UC_HTABLE_FOREACH_HASH(table, it, hash) {
|
||||||
|
struct MyString *my_str = UC_CONTAINER_OF(it, struct MyString, node);
|
||||||
|
if (strcmp(my_str->str, str) == 0) {
|
||||||
|
return my_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_htable1)
|
||||||
|
struct MyString str[5] = {
|
||||||
|
{"One", {0,NULL}},
|
||||||
|
{"Two", {0,NULL}},
|
||||||
|
{"Three",{0,NULL}},
|
||||||
|
{"Four", {0,NULL}},
|
||||||
|
{"Five", {0,NULL}}
|
||||||
|
};
|
||||||
|
struct UHTable table;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
uc_htable_init(&table, 3);
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
uc_htable_insert(&table, &str[i].node, hash_str(str[i].str));
|
||||||
|
}
|
||||||
|
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 5);
|
||||||
|
|
||||||
|
fail_if(my_find(&table, "One", hash_str("One")) != &str[0]);
|
||||||
|
fail_if(my_find(&table, "Two", hash_str("Two")) != &str[1]);
|
||||||
|
fail_if(my_find(&table, "Three",hash_str("Three")) != &str[2]);
|
||||||
|
fail_if(my_find(&table, "Four", hash_str("Four")) != &str[3]);
|
||||||
|
fail_if(my_find(&table, "Five", hash_str("Five")) != &str[4]);
|
||||||
|
fail_if(my_find(&table, "NotHere", hash_str("NotHere")) != NULL);
|
||||||
|
|
||||||
|
uc_htable_destroy(&table);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_htable_hash_collision)
|
||||||
|
//same as test1 but with a bad hash to force equal hash
|
||||||
|
struct MyString str[5] = {
|
||||||
|
{"...", {0,NULL}},
|
||||||
|
{"", {0,NULL}},
|
||||||
|
{".", {0,NULL}},
|
||||||
|
{"..", {0,NULL}},
|
||||||
|
{"....", {0,NULL}}
|
||||||
|
};
|
||||||
|
struct UHTable table;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
uc_htable_init(&table, 1);
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
uc_htable_insert(&table, &str[i].node, bad_hash(str[i].str));
|
||||||
|
}
|
||||||
|
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 5);
|
||||||
|
|
||||||
|
fail_if(my_find(&table, "....", bad_hash("....")) != &str[4]);
|
||||||
|
fail_if(my_find(&table, ".", bad_hash(".")) != &str[2]);
|
||||||
|
fail_if(my_find(&table, "", bad_hash("")) != &str[1]);
|
||||||
|
fail_if(my_find(&table, "..", bad_hash("..")) != &str[3]);
|
||||||
|
fail_if(my_find(&table, "...", bad_hash("...")) != &str[0]);
|
||||||
|
|
||||||
|
uc_htable_destroy(&table);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_htable_resize)
|
||||||
|
struct MyString str[5] = {
|
||||||
|
{"One", {0,NULL}},
|
||||||
|
{"Two", {0,NULL}},
|
||||||
|
{"Three",{0,NULL}},
|
||||||
|
{"Four", {0,NULL}},
|
||||||
|
{"Five", {0,NULL}}
|
||||||
|
};
|
||||||
|
struct UHTable table;
|
||||||
|
int i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_htable_init(&table, 3);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
uc_htable_insert(&table, &str[i].node, hash_str(str[i].str));
|
||||||
|
}
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 5);
|
||||||
|
|
||||||
|
rc = uc_htable_resize(&table, 1024);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 5);
|
||||||
|
|
||||||
|
fail_if(my_find(&table, "One", hash_str("One")) != &str[0]);
|
||||||
|
fail_if(my_find(&table, "Two", hash_str("Two")) != &str[1]);
|
||||||
|
fail_if(my_find(&table, "Three",hash_str("Three")) != &str[2]);
|
||||||
|
fail_if(my_find(&table, "Four", hash_str("Four")) != &str[3]);
|
||||||
|
fail_if(my_find(&table, "Five", hash_str("Five")) != &str[4]);
|
||||||
|
|
||||||
|
uc_htable_destroy(&table);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_htable_fail_init_resize)
|
||||||
|
int rc;
|
||||||
|
struct UHTable table;
|
||||||
|
rc = uc_htable_init(&table, 0);
|
||||||
|
ck_assert_int_ne(rc, 0);
|
||||||
|
|
||||||
|
rc = uc_htable_init(&table, 1);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
rc = uc_htable_resize(&table, 0);
|
||||||
|
ck_assert_int_ne(rc, 0);
|
||||||
|
|
||||||
|
uc_htable_destroy(&table);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_htable_has_node)
|
||||||
|
struct MyString str1 = {"One", {0,NULL}};
|
||||||
|
struct MyString str2 = {"Two", {0,NULL}};
|
||||||
|
|
||||||
|
struct UHTable table;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_htable_init(&table, 3);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
uc_htable_insert(&table, &str1.node, hash_str(str1.str));
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 1);
|
||||||
|
|
||||||
|
rc = uc_htable_has_node(&table, &str1.node);
|
||||||
|
ck_assert_int_ne(rc, 0);
|
||||||
|
|
||||||
|
rc = uc_htable_has_node(&table, &str2.node);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
uc_htable_destroy(&table);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_htable_remove)
|
||||||
|
struct MyString str1 = {"One", {0,NULL}};
|
||||||
|
struct MyString str2 = {"One", {0,NULL}};
|
||||||
|
struct MyString str3 = {"Other", {0,NULL}};
|
||||||
|
|
||||||
|
struct UHTable table;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_htable_init(&table, 1);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
uc_htable_insert(&table, &str1.node, hash_str(str1.str));
|
||||||
|
uc_htable_insert(&table, &str2.node, hash_str(str2.str));
|
||||||
|
uc_htable_insert(&table, &str3.node, hash_str(str3.str));
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 3);
|
||||||
|
|
||||||
|
uc_htable_remove(&table, &str2.node);
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 2);
|
||||||
|
|
||||||
|
//this one should still be here
|
||||||
|
fail_if(my_find(&table, "One", hash_str("One")) != &str1);
|
||||||
|
//
|
||||||
|
//thisone should be gone
|
||||||
|
rc = uc_htable_has_node(&table, &str2.node);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
|
||||||
|
uc_htable_remove(&table, &str1.node);
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 1);
|
||||||
|
|
||||||
|
//now this one should be gone
|
||||||
|
rc = uc_htable_has_node(&table, &str1.node);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
//double removal should be ok
|
||||||
|
uc_htable_remove(&table, &str1.node);
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 1);
|
||||||
|
|
||||||
|
//this one should still be here
|
||||||
|
fail_if(my_find(&table, "Other", hash_str("Other")) != &str3);
|
||||||
|
|
||||||
|
uc_htable_destroy(&table);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_htable_remove_foreach)
|
||||||
|
struct MyString str1 = {"One", {0,NULL}};
|
||||||
|
struct MyString str2 = {"One", {0,NULL}};
|
||||||
|
struct MyString str3 = {"Other", {0,NULL}};
|
||||||
|
|
||||||
|
struct UHTable table;
|
||||||
|
struct UHNode *it;
|
||||||
|
struct UHNode *next;
|
||||||
|
int rc;
|
||||||
|
int removed = 0;
|
||||||
|
|
||||||
|
rc = uc_htable_init(&table, 1);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
uc_htable_insert(&table, &str1.node, hash_str(str1.str));
|
||||||
|
uc_htable_insert(&table, &str2.node, hash_str(str2.str));
|
||||||
|
uc_htable_insert(&table, &str3.node, hash_str(str3.str));
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 3);
|
||||||
|
|
||||||
|
fail_if(my_find(&table, "One", hash_str("One")) == NULL);
|
||||||
|
|
||||||
|
UC_HTABLE_FOREACH_HASH_SAFE(&table, it, next, hash_str("One")) {
|
||||||
|
uc_htable_remove(&table, it);
|
||||||
|
memset(it, 0xff, sizeof *it);
|
||||||
|
removed++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ck_assert_int_eq(removed, 2);
|
||||||
|
|
||||||
|
fail_if(my_find(&table, "One", hash_str("One")) != NULL);
|
||||||
|
fail_if(my_find(&table, "Other", hash_str("Other")) != &str3);
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 1);
|
||||||
|
|
||||||
|
uc_htable_destroy(&table);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_htable_clear)
|
||||||
|
struct MyString str1 = {"One", {0,NULL}};
|
||||||
|
|
||||||
|
struct UHTable table;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_htable_init(&table, 100);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
uc_htable_insert(&table, &str1.node, hash_str(str1.str));
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 1);
|
||||||
|
|
||||||
|
fail_if(my_find(&table, "One", hash_str("One")) != &str1);
|
||||||
|
|
||||||
|
uc_htable_clear(&table);
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 0);
|
||||||
|
fail_if(my_find(&table, "One", hash_str("One")) != NULL);
|
||||||
|
|
||||||
|
uc_htable_destroy(&table);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_htable_foreach)
|
||||||
|
struct MyString str1 = {"One", {0,NULL}};
|
||||||
|
struct MyString str2 = {"One", {0,NULL}};
|
||||||
|
struct MyString str3 = {"Other",{0,NULL}};
|
||||||
|
|
||||||
|
struct UHTable table;
|
||||||
|
struct UHNode *it;
|
||||||
|
int rc;
|
||||||
|
int found1 = 0;
|
||||||
|
int found2 = 0;
|
||||||
|
int found3 = 0;
|
||||||
|
|
||||||
|
rc = uc_htable_init(&table, 1000);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
uc_htable_insert(&table, &str1.node, hash_str(str1.str));
|
||||||
|
uc_htable_insert(&table, &str2.node, hash_str(str2.str));
|
||||||
|
uc_htable_insert(&table, &str3.node, hash_str(str3.str));
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 3);
|
||||||
|
|
||||||
|
UC_HTABLE_FOREACH(&table, it) {
|
||||||
|
struct MyString *my_str = UC_CONTAINER_OF(it, struct MyString, node);
|
||||||
|
if (my_str == &str1) {
|
||||||
|
found1++;
|
||||||
|
}
|
||||||
|
if (my_str == &str2) {
|
||||||
|
found2++;
|
||||||
|
}
|
||||||
|
if (my_str == &str3) {
|
||||||
|
found3++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ck_assert_int_eq(found1, 1);
|
||||||
|
ck_assert_int_eq(found2, 1);
|
||||||
|
ck_assert_int_eq(found3, 1);
|
||||||
|
|
||||||
|
|
||||||
|
uc_htable_destroy(&table);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_htable_foreach_safe)
|
||||||
|
struct MyString str1 = {"One", {0,NULL}};
|
||||||
|
struct MyString str2 = {"One", {0,NULL}};
|
||||||
|
struct MyString str3 = {"Other",{0,NULL}};
|
||||||
|
|
||||||
|
struct UHTable table;
|
||||||
|
struct UHNode *it;
|
||||||
|
struct UHNode *next;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_htable_init(&table, 1000);
|
||||||
|
ck_assert_int_eq(rc, 0);
|
||||||
|
|
||||||
|
uc_htable_insert(&table, &str1.node, hash_str(str1.str));
|
||||||
|
uc_htable_insert(&table, &str2.node, hash_str(str2.str));
|
||||||
|
uc_htable_insert(&table, &str3.node, hash_str(str3.str));
|
||||||
|
|
||||||
|
fail_if(my_find(&table, "Other", hash_str("Other")) != &str3);
|
||||||
|
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 3);
|
||||||
|
|
||||||
|
UC_HTABLE_FOREACH_SAFE(&table, it, next) {
|
||||||
|
uc_htable_remove(&table, it);
|
||||||
|
memset(it, 0xff, sizeof *it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_if(my_find(&table, "One", hash_str("One")) != NULL);
|
||||||
|
fail_if(my_find(&table, "Other", hash_str("Other")) != NULL);
|
||||||
|
|
||||||
|
ck_assert_int_eq(uc_htable_count(&table), 0);
|
||||||
|
|
||||||
|
uc_htable_destroy(&table);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite *htable_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("htable");
|
||||||
|
TCase *tc = tcase_create("htable tests");
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_htable1);
|
||||||
|
tcase_add_test(tc, test_htable_hash_collision);
|
||||||
|
tcase_add_test(tc, test_htable_resize);
|
||||||
|
tcase_add_test(tc, test_htable_fail_init_resize);
|
||||||
|
tcase_add_test(tc, test_htable_has_node);
|
||||||
|
tcase_add_test(tc, test_htable_remove);
|
||||||
|
tcase_add_test(tc, test_htable_remove_foreach);
|
||||||
|
tcase_add_test(tc, test_htable_clear);
|
||||||
|
tcase_add_test(tc, test_htable_foreach);
|
||||||
|
tcase_add_test(tc, test_htable_foreach_safe);
|
||||||
|
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include <ucore/rate_limit.h>
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_ratelimit_1)
|
||||||
|
struct RateLimit r;
|
||||||
|
long now = 10;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
uc_ratelimit_init(&r, 30, 2);
|
||||||
|
for (i = 0; i < 30; i++) {
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now), "i = %d", i);
|
||||||
|
}
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_ratelimit_2)
|
||||||
|
struct RateLimit r;
|
||||||
|
long now = 10;
|
||||||
|
|
||||||
|
uc_ratelimit_init(&r, 1, 1);
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
now += 1;
|
||||||
|
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_ratelimit_3)
|
||||||
|
struct RateLimit r;
|
||||||
|
long now = 10;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
uc_ratelimit_init(&r, 10, 5);
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
}
|
||||||
|
|
||||||
|
now += 1;
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
now += 1;
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
}
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
now += 1;
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
}
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_ratelimit_4)
|
||||||
|
struct RateLimit r;
|
||||||
|
long now = 10;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
uc_ratelimit_init(&r, 10, 5);
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
uc_ratelimit_reset(&r, now);
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
}
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_ratelimit_5)
|
||||||
|
struct RateLimit r;
|
||||||
|
long now = 1400000000;
|
||||||
|
|
||||||
|
uc_ratelimit_init(&r, 1, 10);
|
||||||
|
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
now += 5;
|
||||||
|
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
now += 5;
|
||||||
|
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
now += 200;
|
||||||
|
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_ratelimit_time_backward)
|
||||||
|
struct RateLimit r;
|
||||||
|
long now = 1400000000;
|
||||||
|
|
||||||
|
uc_ratelimit_init(&r, 1, 10);
|
||||||
|
|
||||||
|
fail_if(!uc_ratelimit_allow(&r, now));
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
now -= 5;
|
||||||
|
|
||||||
|
fail_if(uc_ratelimit_allow(&r, now));
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
Suite *ratelimit_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("ratelimit");
|
||||||
|
TCase *tc = tcase_create("ratelimit tests");
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_ratelimit_1);
|
||||||
|
tcase_add_test(tc, test_ratelimit_2);
|
||||||
|
tcase_add_test(tc, test_ratelimit_3);
|
||||||
|
tcase_add_test(tc, test_ratelimit_4);
|
||||||
|
tcase_add_test(tc, test_ratelimit_5);
|
||||||
|
tcase_add_test(tc, test_ratelimit_time_backward);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -24,6 +24,8 @@ extern Suite *human_bytesz_suite(void);
|
|||||||
extern Suite *dbuf_suite(void);
|
extern Suite *dbuf_suite(void);
|
||||||
extern Suite *sprintb_suite(void);
|
extern Suite *sprintb_suite(void);
|
||||||
extern Suite *strv_suite(void);
|
extern Suite *strv_suite(void);
|
||||||
|
extern Suite *ratelimit_suite(void);
|
||||||
|
extern Suite *htable_suite(void);
|
||||||
|
|
||||||
static suite_func suites[] = {
|
static suite_func suites[] = {
|
||||||
bitvec_suite,
|
bitvec_suite,
|
||||||
@@ -42,6 +44,8 @@ static suite_func suites[] = {
|
|||||||
dbuf_suite,
|
dbuf_suite,
|
||||||
sprintb_suite,
|
sprintb_suite,
|
||||||
strv_suite,
|
strv_suite,
|
||||||
|
ratelimit_suite,
|
||||||
|
htable_suite,
|
||||||
clock_suite,
|
clock_suite,
|
||||||
threadqueue_suite
|
threadqueue_suite
|
||||||
};
|
};
|
||||||
@@ -58,6 +62,8 @@ main (int argc, char *argv[])
|
|||||||
if (xml_output)
|
if (xml_output)
|
||||||
srunner_set_xml(sr, "result.xml");
|
srunner_set_xml(sr, "result.xml");
|
||||||
|
|
||||||
|
srunner_set_fork_status(sr, CK_FORK_GETENV);
|
||||||
|
|
||||||
|
|
||||||
for(i = 0; i < sizeof suites/sizeof suites[0]; i++) {
|
for(i = 0; i < sizeof suites/sizeof suites[0]; i++) {
|
||||||
srunner_add_suite(sr, suites[i]());
|
srunner_add_suite(sr, suites[i]());
|
||||||
|
|||||||
+68
-10
@@ -50,17 +50,44 @@ START_TEST (test_thread_queue_one_thread)
|
|||||||
fail_if(my_msg->a != i);
|
fail_if(my_msg->a != i);
|
||||||
free(my_msg);
|
free(my_msg);
|
||||||
}
|
}
|
||||||
fail_if(uc_thread_queue_destroy(&queue, NULL) != 0);
|
fail_if(uc_thread_queue_destroy(&queue, NULL, NULL) != 0);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_thread_queue_priority_msg)
|
||||||
|
|
||||||
|
struct uc_threadqueue queue;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
struct uc_threadmsg msg[3];
|
||||||
|
memset(&msg, 0, sizeof msg);
|
||||||
|
|
||||||
|
fail_if(uc_thread_queue_init(&queue, 3) != 0);
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
msg[i].msgtype = -1; //negative == add at head
|
||||||
|
fail_if(uc_thread_queue_add(&queue, &msg[i]) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 2; i >= 0; i--) {
|
||||||
|
struct uc_threadmsg *my_msg;
|
||||||
|
fail_if(uc_thread_queue_get(&queue, &my_msg) != 0);
|
||||||
|
|
||||||
|
fail_if(my_msg != &msg[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_if(uc_thread_queue_destroy(&queue, NULL, NULL) != 0);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//pretty ugly..
|
//pretty ugly..
|
||||||
static int test_thread_queue_walk_global;
|
static int test_thread_queue_walk_global;
|
||||||
static void test_thread_queue_walk_func(struct uc_threadmsg *msg)
|
static void test_thread_queue_walk_func(struct uc_threadmsg *msg, void *cookie)
|
||||||
{
|
{
|
||||||
|
(void)cookie;
|
||||||
struct thr_msg *my_msg = (struct thr_msg *)msg;
|
struct thr_msg *my_msg = (struct thr_msg *)msg;
|
||||||
fail_if(my_msg->a != test_thread_queue_walk_global);
|
fail_if(my_msg->a != test_thread_queue_walk_global);
|
||||||
test_thread_queue_walk_global++;
|
test_thread_queue_walk_global++;
|
||||||
@@ -82,7 +109,7 @@ START_TEST (test_thread_queue_walk)
|
|||||||
|
|
||||||
test_thread_queue_walk_global = 0;
|
test_thread_queue_walk_global = 0;
|
||||||
|
|
||||||
uc_thread_queue_walk(&queue, test_thread_queue_walk_func);
|
uc_thread_queue_walk(&queue, test_thread_queue_walk_func, NULL);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
@@ -125,7 +152,7 @@ START_TEST (test_thread_queue_reader_writer)
|
|||||||
|
|
||||||
pthread_join(tid, NULL);
|
pthread_join(tid, NULL);
|
||||||
|
|
||||||
fail_if(uc_thread_queue_destroy(&queue, NULL) != 0);
|
fail_if(uc_thread_queue_destroy(&queue, NULL, NULL) != 0);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
@@ -216,7 +243,7 @@ START_TEST (test_thread_queue_timeout1)
|
|||||||
fail_if(uc_thread_queue_init(&queue, 100) != 0);
|
fail_if(uc_thread_queue_init(&queue, 100) != 0);
|
||||||
|
|
||||||
fail_if(uc_thread_queue_tryget(&queue, &timeout, &msg) != ETIMEDOUT);
|
fail_if(uc_thread_queue_tryget(&queue, &timeout, &msg) != ETIMEDOUT);
|
||||||
uc_thread_queue_destroy(&queue, NULL);
|
uc_thread_queue_destroy(&queue, NULL, NULL);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
@@ -251,7 +278,7 @@ START_TEST (test_thread_queue_timeout2)
|
|||||||
|
|
||||||
pthread_join(tid1, NULL);
|
pthread_join(tid1, NULL);
|
||||||
|
|
||||||
uc_thread_queue_destroy(&queue, NULL);
|
uc_thread_queue_destroy(&queue, NULL, NULL);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
@@ -270,7 +297,7 @@ START_TEST (test_thread_queue_tryadd_timeout_0_0)
|
|||||||
|
|
||||||
fail_if(uc_thread_queue_tryadd(&queue, &timeout, &msg[2].msg) != ETIMEDOUT);
|
fail_if(uc_thread_queue_tryadd(&queue, &timeout, &msg[2].msg) != ETIMEDOUT);
|
||||||
|
|
||||||
fail_if(uc_thread_queue_destroy(&queue, NULL) != 0);
|
fail_if(uc_thread_queue_destroy(&queue, NULL, NULL) != 0);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
@@ -289,7 +316,7 @@ START_TEST (test_thread_queue_tryadd_timeout_0_100)
|
|||||||
|
|
||||||
fail_if(uc_thread_queue_tryadd(&queue, &timeout, &msg[2].msg) != ETIMEDOUT);
|
fail_if(uc_thread_queue_tryadd(&queue, &timeout, &msg[2].msg) != ETIMEDOUT);
|
||||||
|
|
||||||
fail_if(uc_thread_queue_destroy(&queue, NULL) != 0);
|
fail_if(uc_thread_queue_destroy(&queue, NULL, NULL) != 0);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
@@ -308,7 +335,36 @@ START_TEST (test_thread_queue_tryadd_no_timeout_0_100)
|
|||||||
|
|
||||||
fail_if(uc_thread_queue_tryadd(&queue, &timeout, &msg[2].msg) != 0);
|
fail_if(uc_thread_queue_tryadd(&queue, &timeout, &msg[2].msg) != 0);
|
||||||
|
|
||||||
fail_if(uc_thread_queue_destroy(&queue, NULL) != 0);
|
fail_if(uc_thread_queue_destroy(&queue, NULL, NULL) != 0);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
void clear_cb(struct uc_threadmsg *msg, void *cookie)
|
||||||
|
{
|
||||||
|
int *i = cookie;
|
||||||
|
(void)msg;
|
||||||
|
++*i;
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST (test_thread_queue_clear)
|
||||||
|
|
||||||
|
struct uc_threadqueue queue;
|
||||||
|
int i;
|
||||||
|
struct thr_msg msg[3];
|
||||||
|
memset(msg, 0, sizeof msg);
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
fail_if(uc_thread_queue_init(&queue, 3) != 0);
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
fail_if(uc_thread_queue_add(&queue, &msg[i].msg) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_if(uc_thread_queue_length(&queue) != 3);
|
||||||
|
fail_if(uc_thread_queue_clear(&queue, clear_cb, &cnt));
|
||||||
|
ck_assert_int_eq(cnt , 3);
|
||||||
|
fail_if(uc_thread_queue_length(&queue) != 0);
|
||||||
|
|
||||||
|
fail_if(uc_thread_queue_destroy(&queue, NULL, NULL) != 0);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
@@ -320,6 +376,7 @@ Suite *threadqueue_suite(void)
|
|||||||
|
|
||||||
tcase_add_test(tc1, test_thread_queue_length);
|
tcase_add_test(tc1, test_thread_queue_length);
|
||||||
tcase_add_test(tc1, test_thread_queue_one_thread);
|
tcase_add_test(tc1, test_thread_queue_one_thread);
|
||||||
|
tcase_add_test(tc1, test_thread_queue_priority_msg);
|
||||||
tcase_add_test(tc1, test_thread_queue_walk);
|
tcase_add_test(tc1, test_thread_queue_walk);
|
||||||
tcase_add_test(tc1, test_thread_queue_reader_writer);
|
tcase_add_test(tc1, test_thread_queue_reader_writer);
|
||||||
tcase_add_test(tc1, test_thread_queue_reader_writer_len_1);
|
tcase_add_test(tc1, test_thread_queue_reader_writer_len_1);
|
||||||
@@ -330,6 +387,7 @@ Suite *threadqueue_suite(void)
|
|||||||
tcase_add_test(tc1, test_thread_queue_tryadd_timeout_0_0);
|
tcase_add_test(tc1, test_thread_queue_tryadd_timeout_0_0);
|
||||||
tcase_add_test(tc1, test_thread_queue_tryadd_timeout_0_100);
|
tcase_add_test(tc1, test_thread_queue_tryadd_timeout_0_100);
|
||||||
tcase_add_test(tc1, test_thread_queue_tryadd_no_timeout_0_100);
|
tcase_add_test(tc1, test_thread_queue_tryadd_no_timeout_0_100);
|
||||||
|
tcase_add_test(tc1, test_thread_queue_clear);
|
||||||
|
|
||||||
//lets start with this:
|
//lets start with this:
|
||||||
tcase_set_timeout(tc1, 15);
|
tcase_set_timeout(tc1, 15);
|
||||||
|
|||||||
Reference in New Issue
Block a user