Merge branch 'dev'

This commit is contained in:
Nils O. Selåsdal
2013-10-27 13:33:56 +01:00
39 changed files with 1474 additions and 146 deletions
+8
View File
@@ -42,6 +42,12 @@ AddOption('--coverage',
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',
dest = 'stack_protection',
action='store_true',
@@ -51,6 +57,7 @@ AddOption('--stack-protection',
build_type = GetOption('build_type')
assertions = GetOption('assertions')
test_xml = GetOption('test_xml')
prefix = GetOption('prefix')
if not (build_type in ['debug', 'release']):
@@ -81,6 +88,7 @@ env.Append(CPPPATH = ['#include'])
if build_type == 'release':
env.Append(CFLAGS = ['-O2'])
if not assertions:
#this will turn off assert()
env.Append(CPPDEFINES = ['NDEBUG'])
+2 -10
View File
@@ -1,5 +1,5 @@
#ifndef BITEVEC_H_
#define BITEVEC_H_
#ifndef UC_BITEVEC_H_
#define UC_BITEVEC_H_
#ifdef __cplusplus
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);
// 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
}
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_BUFFER_H_
#define UCORE_BUFFER_H_
#ifndef UC_BUFFER_H_
#define uc_BUFFER_H_
#include <stddef.h>
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef dbuf_H_
#define dbuf_H_
#ifndef UC_DBUF_H_
#define UC_DBUF_H_
#include <stdlib.h>
#ifdef __cplusplus
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef FD_UTILS_H_
#define FD_UTILS_H_
#ifndef UC_FD_UTILS_H_
#define UC_FD_UTILS_H_
#ifdef __cplusplus
extern "C" {
#endif
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_HASH_H_
#define UCORE_HASH_H_
#ifndef UC_HASH_H_
#define UC_HASH_H_
#include <stddef.h>
#include <stdint.h>
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_HEAPSORT_H_
#define UCORE_HEAPSORT_H_
#ifndef UC_HEAPSORT_H_
#define UC_HEAPSORT_H_
#include <stddef.h>
+279
View File
@@ -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
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef IO_MUX_H_
#define IO_MUX_H_
#ifndef UC_IO_MUX_H_
#define UC_IO_MUX_H_
#include "timers.h"
/** @addtogroup IOMux
+12 -9
View File
@@ -1,5 +1,6 @@
#ifndef UCORE_LOGGING_H_
#define UCORE_LOGGING_H_
#ifndef UC_LOGGING_H_
#define UC_LOGGING_H_
#include "utils.h"
/** Logging functions.
* 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_logf(int log_level, int module, int raw,
const char *file, int line, const char *fmt, ...)
__attribute__((format(printf, 6, 7)));
const char *location, const char *fmt, ...)
__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, ...)\
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, ...)\
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
# define UC_DEBUGF(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
*/
#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
* data, not timestamp, log level etc.
*/
#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
}
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_MATH_H_
#define UCORE_MATH_H_
#ifndef UC_MATH_H_
#define UC_MATH_H_
#include <stdint.h>
+1
View File
@@ -30,6 +30,7 @@ struct MBuf {
/**Arbitary pointer user can associate with the mbuf*/
void *cookie;
/*UC_MBUF_FLAGS. The upper 16 bits can be used by the application */
uint32_t flags;
/** Total no of bytes from bufstart*/
uint32_t allocated;
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_MERSENNE_TWISTER_H
#define UCORE_MERSENNE_TWISTER_H
#ifndef UC_MERSENNE_TWISTER_H
#define UC_MERSENNE_TWISTER_H
#ifdef __cplusplus
extern "C" {
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_PACK_H_
#define UCORE_PACK_H_
#ifndef UC_PACK_H_
#define UC_PACK_H_
#include <stdint.h>
#ifdef __GNUC__
+106
View File
@@ -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
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef RBTREE_H_
#define RBTREE_H_
#ifndef UC_RBTREE_H_
#define UC_RBTREE_H_
#ifdef __cplusplus
extern "C" {
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_READ_FILE_H_
#define UCORE_READ_FILE_H_y
#ifndef UC_READ_FILE_H_
#define UC_READ_FILE_H_y
#include <stddef.h>
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef SALLOC_H_
#define SALLOC_H_
#ifndef UC_SALLOC_H_
#define UC_SALLOC_H_
#include <stddef.h>
+3
View File
@@ -1,3 +1,5 @@
#ifndef UC_SATMATH_H_
#define UC_SATMATH_H_
#include <stdint.h>
/** 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);
}
#endif
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef SEQ_H_
#define SEQ_H_
#ifndef UC_SEQ_H_
#define UC_SEQ_H_
#include <stdint.h>
// Check if a is less than b, taking care of wrap arounds
+39 -4
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_STRING_H_
#define UCORE_STRING_H_
#ifndef UC_STRING_H_
#define UC_STRING_H_
#include <stddef.h>
#include <stdint.h>
@@ -17,16 +17,48 @@ uc_hex_decode(const char *in, size_t maxlen,uint8_t *out);
char*
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
uc_str_tolower(char *s);
/**
* Convert the string to uppercase, calls toupper() on each char.
* @param s string to uppercase
*/
void
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_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
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
uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout);
@@ -39,10 +71,13 @@ uc_sprintbll(char *result, unsigned long long value);
char*
uc_sprintbs(char *result, unsigned short value);
/** Like http://swtch.com/plan9port/man/man3/getfields.html
*/
int
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,
///returns the result argument
char *
+3 -2
View File
@@ -1,8 +1,9 @@
#include <stddef.h>
#ifndef UC_STRVEC_H_
#define UC_STRVEC_H_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_SUPERVISOR_H_
#define UCORE_SUPERVISOR_H_
#ifndef UC_SUPERVISOR_H_
#define UC_SUPERVISOR_H_
/** Supervises this process - restart if it dies.
*
+23 -6
View File
@@ -1,5 +1,5 @@
#ifndef _THREADQUEUE_H_
#define _THREADQUEUE_H_ 1
#ifndef UC_THREADQUEUE_H_
#define UC_THREADQUEUE_H_
#include <pthread.h>
@@ -44,7 +44,7 @@ struct uc_threadmsg{
/**
* 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 free_func pointer to function that will be called for each item.
* 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
*/
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
*
* 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
* interact with the queue, else deadlock occors.
* interact with the queue, else deadlock occurs.
*
* @param queue Pointer to the queue to walk
* @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.
* @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);
/**
* @}*/
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_TIMERS_H_
#define UCORE_TIMERS_H_
#ifndef UC_TIMERS_H_
#define UC_TIMERS_H_
#include <stddef.h>
#include <sys/queue.h>
+31 -18
View File
@@ -1,23 +1,16 @@
#ifndef UCORE_UTILS_H_
#define UCORE_UTILS_H_
#ifndef UC_UTILS_H_
#define UC_UTILS_H_
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "backtrace.h"
//Gnerate a compiler error if the compile time
//constant expression fails
#define UC_STATIC_ASSERT(expr) \
do { \
enum { assert_static__ = 1/(expr) }; \
} while (0)
enum { assert_static__ = 1/(expr) };
#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
#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_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
*/
#define UC_ASSERT(expr) do {\
#define UC_ASSERT(expr)\
do {\
if (!(expr) ) {\
fprintf(stderr,\
"UC_ASSERT failed '%s' %s:%d\n", UC_STRINGIFY(expr), __FILE__, __LINE__);\
uc_backtrace_fd(3);\
"UC_ASSERT failed '%s' %s\n", UC_STRINGIFY(expr), UC_SRC_LOCATION);\
uc_backtrace_fd(2);\
abort();\
}\
} 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,
* 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
+2 -2
View File
@@ -1,5 +1,5 @@
#ifndef UCORE_VERSION_H_
#define UCORE_VERSION_H_
#ifndef UC_VERSION_H_
#define UC_VERSION_H_
/**
* @mainpage
* @htmlonly
-35
View File
@@ -48,7 +48,6 @@ void uc_bv_free(struct UCBitVec *v)
}
}
void uc_bv_clr_bit(struct UCBitVec *v,int 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));
}
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)
{
size_t i;
+173
View File
@@ -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
View File
@@ -42,8 +42,7 @@ struct uc_log_args {
struct uc_log_destination *dest;
const struct uc_log_module *module;
int log_level;
const char *file;
int line;
const char *location;
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;
if (dest->log_location) {
fprintf(dest->type.file.file, "[%-7s] %s %s:%d [%s] : ",
uc_ll_2_str(args->log_level), time_buf, args->file,
args->line, args->module->short_name);
fprintf(dest->type.file.file, "[%-7s] %s %s [%s] : ",
uc_ll_2_str(args->log_level), time_buf,
args->location, args->module->short_name);
} else {
fprintf(dest->type.file.file, "[%-7s] %s [%s]: ",
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;
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)
goto log;
offset += rc;
@@ -543,7 +542,7 @@ void uc_log_destination_set_mask(
}
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;
struct uc_log_destination *dest;
@@ -581,8 +580,7 @@ void uc_logf(int log_level, int module, int raw,
.dest = dest,
.module = log_module,
.log_level = log_level,
.file = file,
.line = line,
.location = location,
.raw = raw
};
+73
View File
@@ -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
View File
@@ -199,19 +199,21 @@ int uc_thread_queue_tryget(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 *next;
for(p = queue->first; p; p = next) {
next = p->next;
walk_func(p);
walk_func(p, cookie);
}
}
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) {
return EINVAL;
@@ -219,7 +221,7 @@ int uc_thread_queue_walk(struct uc_threadqueue *queue,
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);
@@ -227,7 +229,8 @@ int uc_thread_queue_walk(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;
@@ -250,7 +253,7 @@ int uc_thread_queue_destroy(struct uc_threadqueue *queue,
}
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);
@@ -276,3 +279,40 @@ long uc_thread_queue_length(struct uc_threadqueue *queue)
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;
}
+2
View File
@@ -76,6 +76,8 @@ void uc_timers_remove(struct UCTimers *timers, struct UCTimer *timer)
timer->ready_entry.tqe_prev = (struct UCTimer **)105;
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
//callback to re_add it
+26
View File
@@ -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;
}
+2
View File
@@ -40,6 +40,7 @@ START_TEST (test_2bcd_2_filler)
fail_if(len != 2, "len is %zu", len);
fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]);
fail_if(bcd[1] != 0xf3,"was 0x%x",bcd[1]);
fail_if(UC_BCD_LEN(strlen(ascii)) != len);
END_TEST
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[3] != '4',"3 was %c",ascii[3]);
fail_if(ascii[4] != 0, "4 was %c",ascii[4]);
fail_if(UC_ASCII_LEN(sizeof bcd) != len);
END_TEST
START_TEST (test_2hex_2)
+379
View File
@@ -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;
}
+148
View File
@@ -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;
}
+6
View File
@@ -24,6 +24,8 @@ extern Suite *human_bytesz_suite(void);
extern Suite *dbuf_suite(void);
extern Suite *sprintb_suite(void);
extern Suite *strv_suite(void);
extern Suite *ratelimit_suite(void);
extern Suite *htable_suite(void);
static suite_func suites[] = {
bitvec_suite,
@@ -42,6 +44,8 @@ static suite_func suites[] = {
dbuf_suite,
sprintb_suite,
strv_suite,
ratelimit_suite,
htable_suite,
clock_suite,
threadqueue_suite
};
@@ -58,6 +62,8 @@ main (int argc, char *argv[])
if (xml_output)
srunner_set_xml(sr, "result.xml");
srunner_set_fork_status(sr, CK_FORK_GETENV);
for(i = 0; i < sizeof suites/sizeof suites[0]; i++) {
srunner_add_suite(sr, suites[i]());
+68 -10
View File
@@ -50,17 +50,44 @@ START_TEST (test_thread_queue_one_thread)
fail_if(my_msg->a != i);
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
//pretty ugly..
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;
fail_if(my_msg->a != 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;
uc_thread_queue_walk(&queue, test_thread_queue_walk_func);
uc_thread_queue_walk(&queue, test_thread_queue_walk_func, NULL);
END_TEST
@@ -125,7 +152,7 @@ START_TEST (test_thread_queue_reader_writer)
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
@@ -216,7 +243,7 @@ START_TEST (test_thread_queue_timeout1)
fail_if(uc_thread_queue_init(&queue, 100) != 0);
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
@@ -251,7 +278,7 @@ START_TEST (test_thread_queue_timeout2)
pthread_join(tid1, NULL);
uc_thread_queue_destroy(&queue, NULL);
uc_thread_queue_destroy(&queue, NULL, NULL);
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_destroy(&queue, NULL) != 0);
fail_if(uc_thread_queue_destroy(&queue, NULL, NULL) != 0);
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_destroy(&queue, NULL) != 0);
fail_if(uc_thread_queue_destroy(&queue, NULL, NULL) != 0);
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_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
@@ -320,6 +376,7 @@ Suite *threadqueue_suite(void)
tcase_add_test(tc1, test_thread_queue_length);
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_reader_writer);
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_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:
tcase_set_timeout(tc1, 15);