Merge branch 'master' of /var/lib/git/libucore
This commit is contained in:
@@ -4,3 +4,4 @@ build/
|
|||||||
tags
|
tags
|
||||||
doc/
|
doc/
|
||||||
log_subdir/
|
log_subdir/
|
||||||
|
coverage/
|
||||||
|
|||||||
@@ -655,7 +655,7 @@ WARN_LOGFILE =
|
|||||||
# directories like "/usr/src/myproject". Separate the files or directories
|
# directories like "/usr/src/myproject". Separate the files or directories
|
||||||
# with spaces.
|
# with spaces.
|
||||||
|
|
||||||
INPUT = src
|
INPUT = include
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||||
|
|||||||
+14
@@ -36,6 +36,12 @@ AddOption('--test_xml',
|
|||||||
help='Create a result.xml when running the testsuite'
|
help='Create a result.xml when running the testsuite'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AddOption('--coverage',
|
||||||
|
dest='coverage',
|
||||||
|
action='store_true',
|
||||||
|
help='Build with coverage (gcov) support'
|
||||||
|
)
|
||||||
|
|
||||||
AddOption('--stack-protection',
|
AddOption('--stack-protection',
|
||||||
dest = 'stack_protection',
|
dest = 'stack_protection',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@@ -59,6 +65,11 @@ def InstallPerm(env, dest, files, perm):
|
|||||||
|
|
||||||
|
|
||||||
env = Environment(tools = ['default', 'textfile'])
|
env = Environment(tools = ['default', 'textfile'])
|
||||||
|
|
||||||
|
#allow shell environment to override compiler
|
||||||
|
if os.environ.has_key('CC'):
|
||||||
|
env['CC'] = os.environ['CC']
|
||||||
|
|
||||||
env.AddMethod(InstallPerm)
|
env.AddMethod(InstallPerm)
|
||||||
Export('env', 'build_type', 'prefix', 'version_info', 'test_xml')
|
Export('env', 'build_type', 'prefix', 'version_info', 'test_xml')
|
||||||
|
|
||||||
@@ -80,6 +91,9 @@ if GetOption('stack_protection'):
|
|||||||
env.Append(CFLAGS = ['-fstack-protector', '--param=ssp-buffer-size=4'])
|
env.Append(CFLAGS = ['-fstack-protector', '--param=ssp-buffer-size=4'])
|
||||||
env.Append(CPPDEFINES = ['_FORTIFY_SOURCE=2'])
|
env.Append(CPPDEFINES = ['_FORTIFY_SOURCE=2'])
|
||||||
|
|
||||||
|
if GetOption('coverage'):
|
||||||
|
env.Append(CFLAGS = ['--coverage'])
|
||||||
|
env.Append(LINKFLAGS = ['--coverage'])
|
||||||
|
|
||||||
#put all .sconsign files in one place
|
#put all .sconsign files in one place
|
||||||
env.SConsignFile()
|
env.SConsignFile()
|
||||||
|
|||||||
Executable
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
scons --coverage test
|
||||||
|
mkdir -p coverage && cd coverage
|
||||||
|
lcov -c -d ../build/src/ -o libucore.info
|
||||||
|
genhtml libucore.info
|
||||||
|
|
||||||
|
echo "Test report available at file:///$(pwd)/index.html"
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
* Atomically increment *ptr
|
* Atomically increment *ptr
|
||||||
* @return *ptr before the increment
|
* @return *ptr before the increment
|
||||||
*/
|
*/
|
||||||
#define UC_ATOMIC_INC(ptr) UC_ATOMIC_SUB((ptr), 1)
|
#define UC_ATOMIC_INC(ptr) UC_ATOMIC_ADD((ptr), 1)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
/** @addtogroup Timers
|
||||||
|
* @{
|
||||||
|
* Clock abstractions
|
||||||
|
*/
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -117,5 +120,6 @@ void uc_settable_clock_set(struct UCoreSettableClock *uclock,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} (addtogroup) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
#ifndef dbuf_H_
|
||||||
|
#define dbuf_H_
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dbuf is a generic buffer that will grow automatically.
|
||||||
|
* call buf_ensure() to reserve space, and don't write more data
|
||||||
|
* than you told buf_ensure() to reserve.
|
||||||
|
*
|
||||||
|
* You write data to buf->end
|
||||||
|
* When finished writing data
|
||||||
|
* you call dbuf_added/( with the no. of bytes you've added.
|
||||||
|
*
|
||||||
|
* You read data from buf->start, the buffer has dbuf_len() bytes of data
|
||||||
|
* When you've read and processed the data, call dbuf_take()
|
||||||
|
* to indicate you're done with the data.
|
||||||
|
*
|
||||||
|
* typically(but add error checking)
|
||||||
|
* @code
|
||||||
|
* DBuf buf;
|
||||||
|
* dbuf_init(&buf,4096);
|
||||||
|
* for(;;) {
|
||||||
|
* dbuf_ensure(buf,4096);
|
||||||
|
* size_t len = fread(buf,4096,1,f);
|
||||||
|
* dbuf_added(&buf,len);
|
||||||
|
* char *end;
|
||||||
|
* while((end = memchr(buf.start,'\n',dbuf_len(&dbuf))) != NULL) { //look for a newline
|
||||||
|
* ++end;
|
||||||
|
* int linelen = end - buf.start;
|
||||||
|
* process_line(buf.start,linelen);
|
||||||
|
* dbuf_take(&dbuf,linelen);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
typedef struct DBuf DBuf;
|
||||||
|
struct DBuf {
|
||||||
|
/** Start of user data */
|
||||||
|
unsigned char *start;
|
||||||
|
/** End of user data */
|
||||||
|
unsigned char *end;
|
||||||
|
/** Start of underlying buffer. Internal use.*/
|
||||||
|
unsigned char *bufstart;
|
||||||
|
/** End of underlying buffer. Internal use.*/
|
||||||
|
unsigned char *bufend;
|
||||||
|
};
|
||||||
|
/** Free the internals of a DBuf, does not free buf itself.
|
||||||
|
* Does nothing if buf == NULL
|
||||||
|
*
|
||||||
|
* @param buf buffer to free
|
||||||
|
*/
|
||||||
|
void uc_dbuf_free(DBuf *buf);
|
||||||
|
|
||||||
|
/** Initialize a dbuf.
|
||||||
|
*
|
||||||
|
* @param buf buffer to initialize
|
||||||
|
* @param initlen inital capacity of the buffer
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
int uc_dbuf_init(DBuf *buf,size_t initlen);
|
||||||
|
|
||||||
|
/** Get length of user data in the buffer
|
||||||
|
*
|
||||||
|
* @param buf buffer to get length of
|
||||||
|
* @return length of the user data
|
||||||
|
*/
|
||||||
|
size_t uc_dbuf_len(DBuf *buf);
|
||||||
|
|
||||||
|
/** Allocated size of the buffer
|
||||||
|
*
|
||||||
|
* @param buf buffer to get allocated length of
|
||||||
|
* @return allocated length of the underlying buffer
|
||||||
|
*/
|
||||||
|
size_t uc_dbuf_buflen(DBuf *buf);
|
||||||
|
|
||||||
|
/** Get remaining space in the buffer
|
||||||
|
*
|
||||||
|
* @param buf buffer
|
||||||
|
* @return remaining space (after buf->end) in the buffer
|
||||||
|
*/
|
||||||
|
size_t uc_dbuf_remaining(DBuf *buf);
|
||||||
|
|
||||||
|
/** ensure the buffer can hold 'capacity' no of bytes,
|
||||||
|
*
|
||||||
|
* @param buf buffer
|
||||||
|
* @param capacity ensure there is room for capacity bytes after buf->end
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
int uc_dbuf_ensure(DBuf *buf,size_t capacity);
|
||||||
|
|
||||||
|
/** Trim the buffer to hold no more space than needed.
|
||||||
|
*
|
||||||
|
* @param buf buffer to trum
|
||||||
|
*/
|
||||||
|
void uc_dbuf_trim(DBuf *buf);
|
||||||
|
|
||||||
|
/** Indicate you've taken 'len' bytes out of the buffer.
|
||||||
|
* Advances buf->start by len bytes
|
||||||
|
* This may re-set buf->start and buf->end if e.g. all data
|
||||||
|
* is taken out of the buffer.
|
||||||
|
*
|
||||||
|
* @param buf buffer
|
||||||
|
* @param len length that was taken out of the buffer
|
||||||
|
* @return 0 on success. Non-zero if len is larger than the bufer capacity
|
||||||
|
*/
|
||||||
|
int uc_dbuf_take(DBuf *buf,size_t len);
|
||||||
|
|
||||||
|
/** Indicate you've added 'len' bytes to the buffer
|
||||||
|
* Advances buf->end by len bytes
|
||||||
|
* User must always make sure (e.g. by using uc_dbuf_ensure)
|
||||||
|
* that the buffer has the capacity to add @len bytes
|
||||||
|
*
|
||||||
|
* @param buf buffer
|
||||||
|
* @param len length that was added to the buffer.
|
||||||
|
*/
|
||||||
|
void uc_dbuf_added(DBuf *buf,size_t len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -10,42 +10,66 @@ extern "C" {
|
|||||||
* @param fd file descriptor
|
* @param fd file descriptor
|
||||||
* @return 0 on success -1 on failure
|
* @return 0 on success -1 on failure
|
||||||
*/
|
*/
|
||||||
int set_nonblocking(int fd);
|
int uc_set_nonblocking(int fd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the file descriptor to blocking
|
* set the file descriptor to blocking
|
||||||
* @param fd file descriptor
|
* @param fd file descriptor
|
||||||
* @return 0 on success -1 on failure
|
* @return 0 on success -1 on failure
|
||||||
*/
|
*/
|
||||||
int set_blocking(int fd);
|
int uc_set_blocking(int fd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the socket file descriptor to SO_REUSEADDR
|
* set the socket file descriptor to SO_REUSEADDR
|
||||||
* @param fd file descriptor
|
* @param fd file descriptor
|
||||||
* @return 0 on success -1 on failure
|
* @return 0 on success -1 on failure
|
||||||
*/
|
*/
|
||||||
int set_reuseaddr(int sockfd);
|
int uc_set_reuseaddr(int sockfd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enable TCP keepalive on the socket
|
* enable TCP keepalive on the socket
|
||||||
* @param fd file descriptor
|
* @param fd file descriptor
|
||||||
* @return 0 on success -1 on failure
|
* @return 0 on success -1 on failure
|
||||||
*/
|
*/
|
||||||
int set_tcp_keepalive(int sockfd);
|
int uc_set_tcp_keepalive(int sockfd);
|
||||||
|
|
||||||
|
|
||||||
|
struct UCKeepConfig {
|
||||||
|
/** The maximum number of keepalive probes TCP should
|
||||||
|
* send before dropping the connection. (TCP_KEEPCNT socket option)
|
||||||
|
*/
|
||||||
|
int keepcnt;
|
||||||
|
/** The time (in seconds) the connection needs to remain
|
||||||
|
* idle before TCP starts sending keepalive probes (TCP_KEEPIDLE socket option)
|
||||||
|
*/
|
||||||
|
int keepidle;
|
||||||
|
/** The time (in seconds) between individual keepalive probes.
|
||||||
|
* (TCP_KEEPINTVL socket option)
|
||||||
|
*/
|
||||||
|
int keepintvl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Set the keepalive options on the socket
|
||||||
|
* This also enables TCP keepalive on the socket
|
||||||
|
*
|
||||||
|
* @param fd file descriptor
|
||||||
|
* @param fd file descriptor
|
||||||
|
* @return 0 on success -1 on failure
|
||||||
|
*/
|
||||||
|
int uc_set_tcp_keepalive_cfg(int sockfd, const struct UCKeepConfig *cfg);
|
||||||
/**
|
/**
|
||||||
* Set the socket send timeout, in miliseconds
|
* Set the socket send timeout, in miliseconds
|
||||||
* @param fd file descriptor
|
* @param fd file descriptor
|
||||||
* @return 0 on success -1 on failure
|
* @return 0 on success -1 on failure
|
||||||
*/
|
*/
|
||||||
int set_send_timeout(int sockfd,long timeoutms);
|
int uc_set_send_timeout(int sockfd,long timeoutms);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the socket receive timeout, in miliseconds
|
* Set the socket receive timeout, in miliseconds
|
||||||
* @param fd file descriptor
|
* @param fd file descriptor
|
||||||
* @return 0 on success -1 on failure
|
* @return 0 on success -1 on failure
|
||||||
*/
|
*/
|
||||||
int set_receive_timeout(int sockfd,long timeoutms);
|
int uc_set_receive_timeout(int sockfd,long timeoutms);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the IP DSCP (differnetiated services code point) header value
|
* Set the IP DSCP (differnetiated services code point) header value
|
||||||
@@ -53,7 +77,7 @@ int set_receive_timeout(int sockfd,long timeoutms);
|
|||||||
* @param fd file descriptor
|
* @param fd file descriptor
|
||||||
* @return 0 on success -1 on failure
|
* @return 0 on success -1 on failure
|
||||||
*/
|
*/
|
||||||
int set_ip_dscp(int fd, unsigned int dscp);
|
int uc_set_ip_dscp(int fd, unsigned int dscp);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
+45
-8
@@ -2,7 +2,18 @@
|
|||||||
#define IO_MUX_H_
|
#define IO_MUX_H_
|
||||||
|
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
/** @addtogroup IOMux
|
||||||
|
* @{
|
||||||
|
* The IOMux is an I/O multiplexer, implementing a main eventloop.
|
||||||
|
* The event loop can be used to register callbacks for activity on
|
||||||
|
* file descriptors such as sockets and pips, and for timers.
|
||||||
|
*
|
||||||
|
* The IOMux is backed either by the select() system call, or the epoll
|
||||||
|
* facility on Linux. Several IOMuxes can run in different threads concurrently,
|
||||||
|
* but note that the IOMux itself is not thread safe so operations in one thread
|
||||||
|
* cannot work on an IOMux running in another thread.
|
||||||
|
*
|
||||||
|
* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -22,9 +33,20 @@ enum IOMUX_TYPE {
|
|||||||
IOMUX_TYPE_EPOLL
|
IOMUX_TYPE_EPOLL
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Opaque struct */
|
/** The IOMux used to issue mux operations. This is to be treated as an opaque
|
||||||
|
* handle. Use iomux_create() or iomux_create_ex() to create an IOMux, register
|
||||||
|
* callbakcs, and call iomux_run() to process the events
|
||||||
|
*/
|
||||||
struct IOMux;
|
struct IOMux;
|
||||||
|
|
||||||
struct IOMuxFD;
|
struct IOMuxFD;
|
||||||
|
|
||||||
|
/** Callback function used in struct IOMuxFD
|
||||||
|
* @param mux the mux that issued the callback.
|
||||||
|
* @param fd the file desciptor structure.
|
||||||
|
* @param event A bitmask of the MUX_EV_XX values. Both a read and a write event
|
||||||
|
* might be signalled in the same callback
|
||||||
|
*/
|
||||||
typedef void (*iomux_cb)(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event);
|
typedef void (*iomux_cb)(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event);
|
||||||
|
|
||||||
/** Represents a watched file descriptor */
|
/** Represents a watched file descriptor */
|
||||||
@@ -43,6 +65,9 @@ struct IOMuxFD {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Creates a new IOMux.
|
/** Creates a new IOMux.
|
||||||
|
*
|
||||||
|
* @param type the underlying implementation to use @see IOMUX_TYPE
|
||||||
|
* @return Newly allocated IOMux. NULL if memory allocation fails.
|
||||||
*/
|
*/
|
||||||
struct IOMux *iomux_create(enum IOMUX_TYPE type);
|
struct IOMux *iomux_create(enum IOMUX_TYPE type);
|
||||||
|
|
||||||
@@ -58,19 +83,30 @@ struct IOMux *iomux_create_ex(enum IOMUX_TYPE type, struct UCoreClock *uclock);
|
|||||||
void iomux_delete(struct IOMux *mux);
|
void iomux_delete(struct IOMux *mux);
|
||||||
|
|
||||||
/** Runs the event loop of the mux
|
/** Runs the event loop of the mux
|
||||||
* returns if the number of file descriptors and timers are 0 or
|
*
|
||||||
|
* @return if the number of file descriptors and timers are 0 or
|
||||||
* an error occurs */
|
* an error occurs */
|
||||||
int iomux_run(struct IOMux *mux);
|
int iomux_run(struct IOMux *mux);
|
||||||
|
|
||||||
/* Adds a file descriptor to the watch set,
|
/* Adds a file descriptor to the watch set.
|
||||||
* returns 0 on success, an errno value on error */
|
* The file descriptor integer value must reside in only
|
||||||
|
* one struct IOMuxFD. Adding e.g. the same file descriptor
|
||||||
|
* in 2 different struct IOMuxFD, one for read events and one for
|
||||||
|
* write events is not supported.
|
||||||
|
*
|
||||||
|
* @return 0 on success, an errno value on error
|
||||||
|
*/
|
||||||
int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd);
|
int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd);
|
||||||
|
|
||||||
/** Removes the file descriptor*/
|
/** Removes the file descriptor
|
||||||
|
*
|
||||||
|
* @return 0 on success, an errno value on error
|
||||||
|
*/
|
||||||
int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd);
|
int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd);
|
||||||
|
|
||||||
/** Updates the events to watch for in fd->what
|
/** Updates the events to watch for in fd->what
|
||||||
* returns 0 on success, an errno value on error */
|
* @return 0 on success, an errno value on error
|
||||||
|
*/
|
||||||
int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd);
|
int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd);
|
||||||
|
|
||||||
|
|
||||||
@@ -100,7 +136,7 @@ int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd);
|
|||||||
iomux_update_events((mux), (fd));\
|
iomux_update_events((mux), (fd));\
|
||||||
})
|
})
|
||||||
|
|
||||||
/** Returns a UCTimer instance tied to this mux.
|
/** @return a UCTimer instance tied to this mux.
|
||||||
* Used to schedule timers within this mux.
|
* Used to schedule timers within this mux.
|
||||||
*/
|
*/
|
||||||
struct UCTimers *iomux_get_timers(struct IOMux *mux);
|
struct UCTimers *iomux_get_timers(struct IOMux *mux);
|
||||||
@@ -109,5 +145,6 @@ struct UCTimers *iomux_get_timers(struct IOMux *mux);
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} (addtogroup)*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#ifndef UC_MBUF_H_
|
||||||
|
#define UC_MBUF_H_
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# define UC_INLINE inline __attribute__((always_inline))
|
||||||
|
#else
|
||||||
|
# define UC_INLINE inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum UC_MBUF_FLAGS {
|
||||||
|
UC_MBUF_FL_MALLOC = 0x0001, //MBuf and MBuf->bufstart are seperatly malloc'd
|
||||||
|
UC_MBUF_FL_MALLOC_BUF = 0x0001, //MBuf is not malloc'd. MBuf->bufstart is malloc'd
|
||||||
|
UC_MBUF_FL_MALLOC_INLINE = 0x0002, //MBuf is one big malloc. Can't be resized
|
||||||
|
UC_MBUF_FL_STATIC = 0x0004, //MBuf and MBuf->bustart is user controlled. Can't be resized
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MBuf {
|
||||||
|
struct MBuf *next;
|
||||||
|
uint8_t *p1;
|
||||||
|
uint8_t *p2;
|
||||||
|
uint8_t *p3;
|
||||||
|
uint8_t *p4;
|
||||||
|
void *cookie;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t allocated;
|
||||||
|
uint8_t *bufstart;
|
||||||
|
uint8_t *head;
|
||||||
|
uint8_t *tail;
|
||||||
|
uint8_t inline_data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Conventions:
|
||||||
|
* push - prepend data to the buffer (in the head room part)
|
||||||
|
* pull - remove data from the beginning of the message.
|
||||||
|
* put - Add data to the buffer.
|
||||||
|
*/
|
||||||
|
struct MBuf *uc_mbuf_new_hr(uint32_t len, uint32_t headroom);
|
||||||
|
#define uc_mbuf_new(len) uc_mbuf_new_hr((len), 0)
|
||||||
|
|
||||||
|
struct MBuf *uc_mbuf_new_inline_hr(uint32_t len, uint32_t headroom);
|
||||||
|
#define uc_mbuf_new_inline(len) uc_mbuf_new_inline_hr((len), 0)
|
||||||
|
|
||||||
|
void uc_mbuf_free(struct MBuf *mbuf);
|
||||||
|
struct MBuf *uc_mbuf_copy_data(struct MBuf *mbuf);
|
||||||
|
|
||||||
|
void uc_mbuf_init(struct MBuf *mbuf, uint8_t *buf, uint32_t len, uint32_t headroom, uint32_t flags);
|
||||||
|
void uc_mbuf_zero(struct MBuf *mbuf);
|
||||||
|
void uc_mbuf_reset(struct MBuf *mbuf);
|
||||||
|
|
||||||
|
static UC_INLINE uint32_t uc_mbuf_len(struct MBuf *mbuf)
|
||||||
|
{
|
||||||
|
return (uint32_t)(mbuf->tail - mbuf->head);
|
||||||
|
}
|
||||||
|
|
||||||
|
static UC_INLINE uint32_t uc_mbuf_tailroom(struct MBuf *mbuf)
|
||||||
|
{
|
||||||
|
return mbuf->allocated - (uint32_t)(mbuf->tail - mbuf->bufstart);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t uc_mbuf_headroom(struct MBuf *mbuf)
|
||||||
|
{
|
||||||
|
return (uint32_t)(mbuf->head - mbuf->bufstart);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *uc_mbuf_put(struct MBuf *mbuf, uint32_t size);
|
||||||
|
|
||||||
|
uint8_t *uc_mbuf_push(struct MBuf *mbuf, uint32_t size);
|
||||||
|
|
||||||
|
uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size);
|
||||||
|
|
||||||
|
#undef UC_INLINE
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/** Implementation of saturated operation on uintaa_t.
|
/** Implementation of saturated operation on uintxx_t.
|
||||||
* Opaerations are clamped betweehn 0 and UINTaa_MAa instead of
|
*
|
||||||
* wrapping around*/
|
* Operations are clamped between 0 and UINTxx_MAX instead of
|
||||||
|
* wrapping around.
|
||||||
|
*
|
||||||
|
* multiplication, subtraction and addition operations are provided.*/
|
||||||
|
|
||||||
#define UC_SAT_ADD(a, b, type, max_val)\
|
#define UC_SAT_ADD(a, b, type, max_val)\
|
||||||
((type)((a) + (b)) >= (a) ? (a) + (b) : (max_val))
|
((type)((a) + (b)) >= (a) ? (a) + (b) : (max_val))
|
||||||
|
|||||||
@@ -9,10 +9,6 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
size_t
|
|
||||||
uc_base64_enc(const unsigned char *data,size_t len,unsigned char *result);
|
|
||||||
size_t
|
|
||||||
uc_base64_dec(const unsigned char *data, size_t len, unsigned char *result);
|
|
||||||
|
|
||||||
char*
|
char*
|
||||||
uc_hex_encode(const uint8_t *in, size_t len, char *out);
|
uc_hex_encode(const uint8_t *in, size_t len, char *out);
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef UC_STRVEC_H_
|
||||||
|
#define UC_STRVEC_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/** A Vector of strings.*/
|
||||||
|
struct UCStrv
|
||||||
|
{
|
||||||
|
/** number of strings */
|
||||||
|
size_t cnt;
|
||||||
|
/** allocated room in strings (internal use) */
|
||||||
|
size_t allocated;
|
||||||
|
/** Array of strings */
|
||||||
|
char **strings;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Initialize a UCStrv
|
||||||
|
*
|
||||||
|
* @param strv
|
||||||
|
*/
|
||||||
|
void uc_strv_init(struct UCStrv *strv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grow the UCStrv so it can hold n more items
|
||||||
|
*
|
||||||
|
* @param strv UCStrv to grow
|
||||||
|
* @param cnt expand strvec to hold this cnt more items
|
||||||
|
* @return 0 on success, otherwise failure
|
||||||
|
**/
|
||||||
|
int uc_strv_grow(struct UCStrv *strv, size_t cnt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand the UCStrv to hold 1 more item
|
||||||
|
*
|
||||||
|
* @param strv UCStrv to expand
|
||||||
|
* @return 0 on success, otherwise failure
|
||||||
|
**/
|
||||||
|
int uc_strv_expand(struct UCStrv *strv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a string to the UCStrv, the string will be copied in
|
||||||
|
*
|
||||||
|
* @param strv UCStrv to append to
|
||||||
|
* @param str String to append, the string will be copied.
|
||||||
|
* @return 0 on success, otherwise failure
|
||||||
|
**/
|
||||||
|
int uc_strv_append(struct UCStrv *strv, const char *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a string to the strvec, nocopy variang.
|
||||||
|
* The string shold be dynamically allocated, as
|
||||||
|
* destroying the UCStrv will free() all items.
|
||||||
|
*
|
||||||
|
* @param strv UCStrv to add to
|
||||||
|
* @param str the string to append
|
||||||
|
* @return 0 on success, otherwise failure
|
||||||
|
**/
|
||||||
|
int uc_strv_append_nocopy(struct UCStrv *strv, char *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a NULL pointer to the UCStrv, (cnt is not increased,
|
||||||
|
* so another _appended item will overwrite this NULL terminator)
|
||||||
|
*
|
||||||
|
* @param strv UCStrv to append to
|
||||||
|
* @return 0 on success, otherwise failure
|
||||||
|
**/
|
||||||
|
int uc_strv_null_terminate(struct UCStrv *strv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* free all strings in this UCStrv, cnt will be 0 after this
|
||||||
|
* @param strv UCStrv to clear
|
||||||
|
*/
|
||||||
|
void uc_strv_clear(struct UCStrv *strv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* free all elements as well as the underlying array, the UCStrv is
|
||||||
|
* unusable after this call
|
||||||
|
*
|
||||||
|
* @param strv UCStrv to destroy
|
||||||
|
*/
|
||||||
|
void uc_strv_destroy(struct UCStrv *strv);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef UCORE_SUPERVISOR_H_
|
||||||
|
#define UCORE_SUPERVISOR_H_
|
||||||
|
|
||||||
|
/** Supervises this process - restart if it dies.
|
||||||
|
*
|
||||||
|
* The program should call supervise() at a pristine state (all relevant file descriptors closed, etc).
|
||||||
|
* supervise() will return 0 if all is ok, and the program can continue.(returning != 0 means
|
||||||
|
* the supervisor couldn't start, and the calling process must exit)
|
||||||
|
*
|
||||||
|
* This will run the actual process as a child process. If that child process dies by any means,
|
||||||
|
* supervise will create another child process, where supervise() returns 0 again.
|
||||||
|
*
|
||||||
|
* To kill the supervisor process and the supervised process, send SIGERM/SIGHUP/SIGINT to the
|
||||||
|
* parent supervisor process.
|
||||||
|
* Sending SIGUSR1 to the parent supervisor process will terminate the current child process and
|
||||||
|
* restart it.
|
||||||
|
*
|
||||||
|
* The supervised child process must exit if it recieves a SIGTERM
|
||||||
|
* @return 0 on success, non-zero on failure (e.g. fork() fails)*/
|
||||||
|
int uc_supervise(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -6,6 +6,11 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include "rbtree.h"
|
#include "rbtree.h"
|
||||||
|
|
||||||
|
/** @addtogroup Timers
|
||||||
|
* @{
|
||||||
|
* Timer management for managing timeouts
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -147,4 +152,5 @@ int uc_timers_run(struct UCTimers *timers);
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @{ (addtogroup) */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -48,12 +48,14 @@
|
|||||||
//struct foo *f = CONTAINER_OF(p, struct foo, zap);
|
//struct foo *f = CONTAINER_OF(p, struct foo, zap);
|
||||||
#define CONTAINER_OF(ptr, type, member) ({ \
|
#define CONTAINER_OF(ptr, type, member) ({ \
|
||||||
typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
(type *)( (unsigned char *)__mptr - offsetof(type, member) ); })
|
(type *)((void *)(unsigned char *)__mptr - offsetof(type, member) ); })
|
||||||
|
|
||||||
|
//the void* cast is to suppress alignment warnings
|
||||||
|
|
||||||
//Same as CONTAINER_OF, but for a const pointer to avoid gcc warnings..
|
//Same as CONTAINER_OF, but for a const pointer to avoid gcc warnings..
|
||||||
#define CONST_CONTAINER_OF(ptr, type, member) ({ \
|
#define CONST_CONTAINER_OF(ptr, type, member) ({ \
|
||||||
const typeof( ((const type *)0)->member ) *__mptr = (ptr); \
|
const typeof( ((const type *)0)->member ) *__mptr = (ptr); \
|
||||||
(const type *)( (const unsigned char *)__mptr - offsetof(const type, member) ); })
|
(const type *)((const void *)(const unsigned char *)__mptr - offsetof(const type, member) ); })
|
||||||
|
|
||||||
/** Align a value.
|
/** Align a value.
|
||||||
* @param val value to align
|
* @param val value to align
|
||||||
|
|||||||
+10
-8
@@ -35,16 +35,18 @@ void uc_backtrace_buf(char *buf, size_t len)
|
|||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
|
|
||||||
lines = backtrace_symbols(buffer, ptrs);
|
lines = backtrace_symbols(buffer, ptrs);
|
||||||
for (i = 1; i < ptrs; i++) {
|
if (lines != NULL) {
|
||||||
|
for (i = 1; i < ptrs; i++) {
|
||||||
|
|
||||||
int rc = snprintf(buf, remaining, "%s\n", lines[i]);
|
int rc = snprintf(buf, remaining, "%s\n", lines[i]);
|
||||||
|
|
||||||
if (rc <= 0 || (size_t)rc >= remaining) {
|
if (rc <= 0 || (size_t)rc >= remaining) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining -= rc;
|
||||||
|
buf += rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining -= rc;
|
|
||||||
buf += rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(lines);
|
free(lines);
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "ucore/string.h"
|
|
||||||
|
|
||||||
static const uint8_t basecode[128] =
|
|
||||||
{
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
|
|
||||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
||||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
|
||||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff
|
|
||||||
};
|
|
||||||
|
|
||||||
#define deccode(c) ((c > 127) ? 0xff : basecode[(c)])
|
|
||||||
|
|
||||||
size_t
|
|
||||||
uc_base64_dec(const unsigned char *data, size_t len, unsigned char *result)
|
|
||||||
{
|
|
||||||
size_t i = 0, j = 0, pad;
|
|
||||||
uint8_t c[4];
|
|
||||||
|
|
||||||
while ((i + 3) < len) {
|
|
||||||
|
|
||||||
pad = 0;
|
|
||||||
c[0] = deccode(data[i ]); pad += (c[0] == 0xff);
|
|
||||||
c[1] = deccode(data[i+1]); pad += (c[1] == 0xff);
|
|
||||||
c[2] = deccode(data[i+2]); pad += (c[2] == 0xff);
|
|
||||||
c[3] = deccode(data[i+3]); pad += (c[3] == 0xff);
|
|
||||||
switch (pad) {
|
|
||||||
case 1:
|
|
||||||
result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4);
|
|
||||||
result[j++] = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2);
|
|
||||||
result[j] = (c[2] & 0x03) << 6;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4);
|
|
||||||
result[j] = (c[1] & 0x0f) << 4;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4);
|
|
||||||
result[j++] = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2);
|
|
||||||
result[j++] = ((c[2] & 0x03) << 6) | (c[3] & 0x3f);
|
|
||||||
}
|
|
||||||
|
|
||||||
i += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "ucore/string.h"
|
|
||||||
|
|
||||||
static const char basecode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
||||||
#define PAD '='
|
|
||||||
|
|
||||||
size_t
|
|
||||||
uc_base64_enc(const unsigned char *data,size_t len,unsigned char *result)
|
|
||||||
{
|
|
||||||
|
|
||||||
size_t i = 0, j = 0;
|
|
||||||
size_t pad;
|
|
||||||
|
|
||||||
|
|
||||||
while (i < len) {
|
|
||||||
pad = 3 - (len - i);
|
|
||||||
switch(pad) {
|
|
||||||
case 2:
|
|
||||||
result[j] = basecode[data[i]>>2];
|
|
||||||
result[j+1] = basecode[(data[i] & 0x03) << 4];
|
|
||||||
result[j+2] = PAD;
|
|
||||||
result[j+3] = PAD;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
result[j ] = basecode[data[i]>>2];
|
|
||||||
result[j+1] = basecode[((data[i] & 0x03) << 4) | ((data[i+1] & 0xf0) >> 4)];
|
|
||||||
result[j+2] = basecode[(data[i+1] & 0x0f) << 2];
|
|
||||||
result[j+3] = PAD;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result[j ] = basecode[data[i]>>2];
|
|
||||||
result[j+1] = basecode[((data[i] & 0x03) << 4) | ((data[i+1] & 0xf0) >> 4)];
|
|
||||||
result[j+2] = basecode[((data[i+1] & 0x0f) << 2) | ((data[i+2] & 0xc0) >> 6)];
|
|
||||||
result[j+3] = basecode[data[i+2] & 0x3f];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
j += 4;
|
|
||||||
i += 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "ucore/dbuf.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_dbuf_free(DBuf *buf)
|
||||||
|
{
|
||||||
|
if (buf != NULL)
|
||||||
|
free(buf->bufstart);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_dbuf_init(DBuf *buf, size_t initlen)
|
||||||
|
{
|
||||||
|
unsigned char *tmp = malloc(initlen);
|
||||||
|
if (tmp == NULL)
|
||||||
|
return -1;
|
||||||
|
buf->start = buf->bufstart = buf->end = tmp;
|
||||||
|
buf->bufend = tmp + initlen;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_dbuf_len(DBuf *buf)
|
||||||
|
{
|
||||||
|
return buf->end - buf->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_dbuf_buflen(DBuf *buf)
|
||||||
|
{
|
||||||
|
return buf->bufend - buf->bufstart;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
uc_dbuf_remaining(DBuf *buf)
|
||||||
|
{
|
||||||
|
return buf->bufend - buf->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_dbuf_ensure(DBuf *buf, size_t capacity)
|
||||||
|
{
|
||||||
|
size_t sz, remaining, len;
|
||||||
|
|
||||||
|
remaining = uc_dbuf_remaining(buf);
|
||||||
|
if (remaining >= capacity)
|
||||||
|
return 0;
|
||||||
|
len = uc_dbuf_len(buf);
|
||||||
|
sz = buf->start - buf->bufstart;
|
||||||
|
|
||||||
|
if (buf->bufstart != buf->start)
|
||||||
|
memmove(buf->bufstart, buf->start, len);
|
||||||
|
|
||||||
|
if (sz + remaining < capacity) {
|
||||||
|
size_t newlen = uc_dbuf_buflen(buf) + capacity;
|
||||||
|
void *tmp = realloc(buf->bufstart, newlen);
|
||||||
|
if (tmp == NULL)
|
||||||
|
return 1;
|
||||||
|
buf->bufstart = tmp;
|
||||||
|
buf->bufend = buf->bufstart + newlen;
|
||||||
|
|
||||||
|
}
|
||||||
|
buf->start = buf->bufstart;
|
||||||
|
buf->end = buf->start + len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_dbuf_trim(DBuf *buf)
|
||||||
|
{
|
||||||
|
size_t len = uc_dbuf_len(buf);
|
||||||
|
void *tmp;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (buf->bufstart != buf->start)
|
||||||
|
memmove(buf->bufstart, buf->start, len);
|
||||||
|
|
||||||
|
tmp = realloc(buf->bufstart, len);
|
||||||
|
if (tmp != NULL)
|
||||||
|
buf->bufstart = tmp;
|
||||||
|
|
||||||
|
buf->start = buf->bufstart;
|
||||||
|
buf->bufend = buf->end = buf->bufstart + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
uc_dbuf_take(DBuf *buf, size_t len)
|
||||||
|
{
|
||||||
|
size_t buflen = uc_dbuf_len(buf);
|
||||||
|
|
||||||
|
if (len == buflen) {
|
||||||
|
buf->start = buf->end = buf->bufstart;
|
||||||
|
} else if (len < buflen) {
|
||||||
|
buf->start = buf->start + len;
|
||||||
|
} else {
|
||||||
|
//should maybe assert. This is a serious offence
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uc_dbuf_added(DBuf *buf, size_t len)
|
||||||
|
{
|
||||||
|
assert(len <= uc_dbuf_remaining(buf));
|
||||||
|
buf->end += len;
|
||||||
|
}
|
||||||
+43
-9
@@ -2,20 +2,23 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include "ucore/fd_utils.h"
|
#include "ucore/fd_utils.h"
|
||||||
|
|
||||||
int set_nonblocking(int fd)
|
int uc_set_nonblocking(int fd)
|
||||||
{
|
{
|
||||||
int flags = fcntl(fd,F_GETFL,NULL);
|
int flags = fcntl(fd,F_GETFL,NULL);
|
||||||
|
|
||||||
if(flags < 0 ) {
|
if(flags < 0 ) {
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fcntl(fd,F_SETFL,flags | O_NONBLOCK);
|
return fcntl(fd,F_SETFL,flags | O_NONBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_blocking(int fd)
|
int uc_set_blocking(int fd)
|
||||||
{
|
{
|
||||||
int flags = fcntl(fd,F_GETFL,NULL);
|
int flags = fcntl(fd,F_GETFL,NULL);
|
||||||
if(flags < 0 ) {
|
if(flags < 0 ) {
|
||||||
@@ -25,43 +28,74 @@ int set_blocking(int fd)
|
|||||||
return fcntl(fd,F_SETFL,flags&~O_NONBLOCK);
|
return fcntl(fd,F_SETFL,flags&~O_NONBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_reuseaddr(int sockfd)
|
int uc_set_reuseaddr(int sockfd)
|
||||||
{
|
{
|
||||||
int opt = 1;
|
int opt = 1;
|
||||||
return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
|
return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_tcp_keepalive(int sockfd)
|
int uc_set_tcp_keepalive(int sockfd)
|
||||||
{
|
{
|
||||||
int optval = 1;
|
int optval = 1;
|
||||||
|
|
||||||
return setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
|
return setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int uc_set_tcp_keepalive_cfg(int sockfd, const struct UCKeepConfig *cfg)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
int set_send_timeout(int sockfd,long timeoutms)
|
//first turn on keepalive
|
||||||
|
rc = uc_set_tcp_keepalive(sockfd);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//set the keepalive options
|
||||||
|
rc = setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &cfg->keepcnt, sizeof cfg->keepcnt);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &cfg->keepidle, sizeof cfg->keepintvl);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &cfg->keepintvl, sizeof cfg->keepintvl);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_set_send_timeout(int sockfd,long timeoutms)
|
||||||
{
|
{
|
||||||
struct timeval so_sndtimeo = {timeoutms/1000,(timeoutms%1000)*1000};
|
struct timeval so_sndtimeo = {timeoutms/1000,(timeoutms%1000)*1000};
|
||||||
|
|
||||||
return setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &so_sndtimeo, sizeof(so_sndtimeo));
|
return setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &so_sndtimeo, sizeof(so_sndtimeo));
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_receive_timeout(int sockfd,long timeoutms)
|
int uc_set_receive_timeout(int sockfd,long timeoutms)
|
||||||
{
|
{
|
||||||
struct timeval so_sndtimeo = {timeoutms/1000,(timeoutms%1000)*1000};
|
struct timeval so_sndtimeo = {timeoutms/1000,(timeoutms%1000)*1000};
|
||||||
|
|
||||||
return setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &so_sndtimeo, sizeof(so_sndtimeo));
|
return setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &so_sndtimeo, sizeof(so_sndtimeo));
|
||||||
}
|
}
|
||||||
int
|
|
||||||
set_ip_dscp(int fd, unsigned int dscp) {
|
int uc_set_ip_dscp(int fd, unsigned int dscp)
|
||||||
|
{
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
|
//only 6 bits for dscp
|
||||||
if (dscp > 63) {
|
if (dscp > 63) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
val = dscp << 2;
|
val = dscp << 2;
|
||||||
|
|
||||||
return setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof val);
|
return setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -183,7 +183,7 @@ again:
|
|||||||
fd->callback(mux_, fd, events);
|
fd->callback(mux_, fd, events);
|
||||||
//be sure not to use fd after the callback, it might been removed.
|
//be sure not to use fd after the callback, it might been removed.
|
||||||
|
|
||||||
mux->pending_events[i].data.ptr = NULL;
|
mux->pending_events[i].data.ptr = NULL; //clear from pending list
|
||||||
|
|
||||||
event_cnt++;
|
event_cnt++;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -168,17 +168,18 @@ again:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(mux->descriptors[i]->fd, &read_set)) {
|
if (FD_ISSET(mux->descriptors[i]->fd, &read_set)) {
|
||||||
|
rc--;
|
||||||
events |= MUX_EV_READ;
|
events |= MUX_EV_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(mux->descriptors[i]->fd, &write_set)) {
|
if (FD_ISSET(mux->descriptors[i]->fd, &write_set)) {
|
||||||
|
rc--;
|
||||||
events |= MUX_EV_WRITE;
|
events |= MUX_EV_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events) {
|
if (events) {
|
||||||
assert(mux->descriptors[i]->callback != NULL);
|
assert(mux->descriptors[i]->callback != NULL);
|
||||||
mux->descriptors[i]->callback(mux_, mux->descriptors[i], events);
|
mux->descriptors[i]->callback(mux_, mux->descriptors[i], events);
|
||||||
rc--;
|
|
||||||
event_cnt++;
|
event_cnt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ucore/mbuf.h"
|
||||||
|
|
||||||
|
uint8_t *uc_mbuf_put(struct MBuf *mbuf, uint32_t size)
|
||||||
|
{
|
||||||
|
uint8_t *data = mbuf->tail;
|
||||||
|
|
||||||
|
if (uc_mbuf_tailroom(mbuf) < size) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbuf->tail += size;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *uc_mbuf_push(struct MBuf *mbuf, uint32_t size)
|
||||||
|
{
|
||||||
|
if (uc_mbuf_headroom(mbuf) < size) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbuf->head -= size;
|
||||||
|
|
||||||
|
return mbuf->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size)
|
||||||
|
{
|
||||||
|
uint8_t *data = mbuf->head;
|
||||||
|
|
||||||
|
if (uc_mbuf_len(mbuf) < size) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbuf->head += size;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_mbuf_init(struct MBuf *mbuf, uint8_t *buf, uint32_t len, uint32_t headroom, uint32_t flags)
|
||||||
|
{
|
||||||
|
mbuf->bufstart = buf;
|
||||||
|
mbuf->next = NULL;
|
||||||
|
mbuf->p1 = mbuf->p2 = mbuf->p3 = mbuf->p4 = NULL;
|
||||||
|
mbuf->cookie = NULL;
|
||||||
|
mbuf->flags = flags;
|
||||||
|
mbuf->allocated = len + headroom;
|
||||||
|
mbuf->head = mbuf->bufstart + headroom;
|
||||||
|
mbuf->tail = mbuf->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MBuf *uc_mbuf_new_hr(uint32_t len, uint32_t headroom)
|
||||||
|
{
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
uint8_t *buf;
|
||||||
|
|
||||||
|
mbuf = malloc(sizeof *mbuf);
|
||||||
|
if (mbuf == NULL)
|
||||||
|
return mbuf;
|
||||||
|
|
||||||
|
buf = malloc(len + headroom);
|
||||||
|
if (buf == NULL) {
|
||||||
|
free(mbuf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc_mbuf_init(mbuf, buf, len, headroom, UC_MBUF_FL_MALLOC);
|
||||||
|
|
||||||
|
return mbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MBuf *uc_mbuf_new_inline_hr(uint32_t len, uint32_t headroom)
|
||||||
|
{
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
|
||||||
|
mbuf = malloc(sizeof *mbuf + len + headroom);
|
||||||
|
if (mbuf == NULL)
|
||||||
|
return mbuf;
|
||||||
|
|
||||||
|
uc_mbuf_init(mbuf, mbuf->inline_data, len, headroom, UC_MBUF_FL_MALLOC_INLINE);
|
||||||
|
|
||||||
|
return mbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_mbuf_free(struct MBuf *mbuf)
|
||||||
|
{
|
||||||
|
if (mbuf->flags & (UC_MBUF_FL_MALLOC | UC_MBUF_FL_MALLOC_BUF))
|
||||||
|
free(mbuf->bufstart);
|
||||||
|
|
||||||
|
if (mbuf->flags & (UC_MBUF_FL_MALLOC | UC_MBUF_FL_MALLOC_INLINE))
|
||||||
|
free(mbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_mbuf_zero(struct MBuf *mbuf)
|
||||||
|
{
|
||||||
|
memset(mbuf->bufstart, 0, mbuf->allocated);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MBuf *uc_mbuf_copy_data(struct MBuf *mbuf)
|
||||||
|
{
|
||||||
|
uint32_t len;
|
||||||
|
struct MBuf *copy;
|
||||||
|
uint8_t *data;
|
||||||
|
|
||||||
|
len = uc_mbuf_len(mbuf);
|
||||||
|
|
||||||
|
copy = uc_mbuf_new_hr(len, uc_mbuf_headroom(mbuf));
|
||||||
|
if (copy == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = uc_mbuf_put(copy, len);
|
||||||
|
memcpy(data, mbuf->head, len);
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ucore/strvec.h"
|
||||||
|
|
||||||
|
void uc_strv_init(struct UCStrv *strv)
|
||||||
|
{
|
||||||
|
strv->cnt = 0;
|
||||||
|
strv->allocated = 0;
|
||||||
|
strv->strings = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_strv_grow(struct UCStrv *strv, size_t cnt)
|
||||||
|
{
|
||||||
|
|
||||||
|
size_t allocate = strv->allocated + cnt;
|
||||||
|
void *tmp = realloc(strv->strings, sizeof *strv->strings * allocate);
|
||||||
|
|
||||||
|
if (tmp == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strv->strings = tmp;
|
||||||
|
strv->allocated = allocate;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_strv_expand(struct UCStrv *strv)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (strv->cnt >= strv->allocated) {
|
||||||
|
rc = uc_strv_grow(strv, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_strv_append(struct UCStrv *strv, const char *str)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
char *dup;
|
||||||
|
|
||||||
|
rc = uc_strv_expand(strv);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
dup = strdup(str);
|
||||||
|
if (dup == NULL) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
strv->strings[strv->cnt] = dup;
|
||||||
|
strv->cnt++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_strv_append_nocopy(struct UCStrv *strv, char *str)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
rc = uc_strv_expand(strv);
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
strv->strings[strv->cnt] = str;
|
||||||
|
strv->cnt++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_strv_null_terminate(struct UCStrv *strv)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_strv_expand(strv);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
strv->strings[strv->cnt] = NULL;
|
||||||
|
strv->cnt++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_strv_clear(struct UCStrv *strv)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < strv->cnt; i++) {
|
||||||
|
free(strv->strings[i]);
|
||||||
|
strv->strings[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strv->cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_strv_destroy(struct UCStrv *strv)
|
||||||
|
{
|
||||||
|
uc_strv_clear(strv);
|
||||||
|
free(strv->strings);
|
||||||
|
strv->strings = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define CLEAN_EXIT 11
|
||||||
|
#define BAD_EXIT 22
|
||||||
|
#define RESTART 33
|
||||||
|
|
||||||
|
//seconds to wait before restarting the process
|
||||||
|
#define RESTART_GRACE 1
|
||||||
|
|
||||||
|
static volatile sig_atomic_t restart_flag = 0;
|
||||||
|
static volatile sig_atomic_t exit_flag = 0;
|
||||||
|
|
||||||
|
static void restart_handler(int sig)
|
||||||
|
{
|
||||||
|
(void)sig;
|
||||||
|
restart_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exit_handler(int sig)
|
||||||
|
{
|
||||||
|
(void)sig;
|
||||||
|
exit_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kill_supervised_process(pid_t pid)
|
||||||
|
{
|
||||||
|
kill(pid, SIGTERM);
|
||||||
|
/* Todo.. verify we killed it, otherwise take more
|
||||||
|
* desperate measures*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static int watch(pid_t pid)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
pid_t rc;
|
||||||
|
|
||||||
|
again:
|
||||||
|
rc = waitpid(pid, &status, 0);
|
||||||
|
if (rc == -1 && errno == EINTR) {
|
||||||
|
if (restart_flag) {
|
||||||
|
restart_flag = 0;
|
||||||
|
kill_supervised_process(pid);
|
||||||
|
/* next waitpid should notify us of the death and
|
||||||
|
* we'll restart the process */
|
||||||
|
goto again;
|
||||||
|
} else if (exit_flag) {
|
||||||
|
exit_flag = 0;
|
||||||
|
return CLEAN_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto again;
|
||||||
|
|
||||||
|
} else if (rc == -1) {
|
||||||
|
return BAD_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WIFSIGNALED(status)) {
|
||||||
|
syslog(LOG_ERR, "supervised process(pid %ld) exited cause of signal %d, status = 0x%X", (long)pid, WTERMSIG(status), status);
|
||||||
|
return RESTART;
|
||||||
|
} else if (WIFEXITED(status)) {
|
||||||
|
syslog(LOG_ERR, "supervised process(pid %ld) exited with code %d, status = 0x%X", (long)pid, WTERMSIG(status), status);
|
||||||
|
return RESTART;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ok, can we ever get here ? */
|
||||||
|
|
||||||
|
syslog(LOG_ERR, "waitpid of supervised process(pid %ld) status = 0x%X", (long)pid, status);
|
||||||
|
if (kill(pid, 0) == 0) {
|
||||||
|
syslog(LOG_ERR, "supervised process(pid %ld) seems to still be alive, not restarting", (long)pid);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESTART;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sigaction orig_usr1_sa;
|
||||||
|
static struct sigaction orig_term_sa;
|
||||||
|
static struct sigaction orig_hup_sa;
|
||||||
|
static struct sigaction orig_int_sa;
|
||||||
|
|
||||||
|
static void restore_signal_handlers(void)
|
||||||
|
{
|
||||||
|
sigaction(SIGUSR1, &orig_usr1_sa, NULL);
|
||||||
|
sigaction(SIGTERM, &orig_term_sa, NULL);
|
||||||
|
sigaction(SIGHUP, &orig_hup_sa, NULL);
|
||||||
|
sigaction(SIGINT, &orig_int_sa, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void install_signal_handlers(void)
|
||||||
|
{
|
||||||
|
struct sigaction act;
|
||||||
|
memset(&act, 0, sizeof act);
|
||||||
|
|
||||||
|
act.sa_handler = restart_handler;
|
||||||
|
sigaction(SIGUSR1, &act, &orig_usr1_sa);
|
||||||
|
|
||||||
|
act.sa_handler = exit_handler;
|
||||||
|
sigaction(SIGTERM, &act, &orig_term_sa);
|
||||||
|
sigaction(SIGHUP, &act, &orig_hup_sa);
|
||||||
|
sigaction(SIGINT, &act, &orig_int_sa);
|
||||||
|
}
|
||||||
|
|
||||||
|
//See notes in supervisor.h
|
||||||
|
int uc_supervise(void)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid == -1) {
|
||||||
|
syslog(LOG_ERR, "Cannot create supervisor : %s", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
} else if (pid == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//close_files();
|
||||||
|
install_signal_handlers();
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "Supervising pid %ld", (long)pid);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int cmd = watch(pid);
|
||||||
|
switch (cmd) {
|
||||||
|
|
||||||
|
case CLEAN_EXIT:
|
||||||
|
syslog(LOG_INFO, "Terminating supervised pid %lu", (unsigned long)pid);
|
||||||
|
kill_supervised_process(pid);
|
||||||
|
wait(NULL);
|
||||||
|
syslog(LOG_INFO, "Exiting");
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BAD_EXIT:
|
||||||
|
syslog(LOG_ERR, "watch() error, exiting");
|
||||||
|
exit(55);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RESTART: {
|
||||||
|
pid_t new_pid = -1;
|
||||||
|
|
||||||
|
while (new_pid == -1) {
|
||||||
|
sleep(RESTART_GRACE);
|
||||||
|
syslog(LOG_INFO, "Restarting supervised pid %lu", (unsigned long)pid);
|
||||||
|
closelog();
|
||||||
|
new_pid = fork();
|
||||||
|
if (new_pid == -1) {
|
||||||
|
syslog(LOG_INFO, "Cannot restart. %s", strerror(errno));
|
||||||
|
} else if (new_pid == 0) { //return so the original process continues
|
||||||
|
restore_signal_handlers();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = new_pid;
|
||||||
|
syslog(LOG_INFO, "Supervising new pid %lu", (unsigned long)new_pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
exit(38);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0x76;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+4
-3
@@ -19,11 +19,11 @@ static int timers_cmp(const RBNode *a_, const RBNode *b_)
|
|||||||
} else if (a->seq > b->seq) {
|
} else if (a->seq > b->seq) {
|
||||||
return 1;
|
return 1;
|
||||||
} else { //should never happen
|
} else { //should never happen
|
||||||
//assert(0);
|
assert(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//assert(0);
|
assert(0);
|
||||||
return 0; //silence compiler
|
return 0; //silence compiler
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,8 +56,9 @@ void uc_timers_add(struct UCTimers *timers, struct UCTimer *timer, int sec, int
|
|||||||
struct timeval tmp;
|
struct timeval tmp;
|
||||||
|
|
||||||
assert(timer->callback != NULL);
|
assert(timer->callback != NULL);
|
||||||
if (timer->callback == NULL) //must be set.
|
if (timer->callback == NULL) { //must be set.
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tmp.tv_sec = sec;
|
tmp.tv_sec = sec;
|
||||||
tmp.tv_usec = usec;
|
tmp.tv_usec = usec;
|
||||||
|
|||||||
+9
-5
@@ -6,8 +6,10 @@ uc_tvadd(struct timeval *dst, const struct timeval *a, const struct timeval *b)
|
|||||||
dst->tv_sec = a->tv_sec + b->tv_sec;
|
dst->tv_sec = a->tv_sec + b->tv_sec;
|
||||||
dst->tv_usec = a->tv_usec + b->tv_usec;
|
dst->tv_usec = a->tv_usec + b->tv_usec;
|
||||||
|
|
||||||
if (dst->tv_usec >= 1000000)
|
if (dst->tv_usec >= 1000000) {
|
||||||
dst->tv_sec++, dst->tv_usec -= 1000000;
|
dst->tv_sec++;
|
||||||
|
dst->tv_usec -= 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
@@ -18,8 +20,10 @@ uc_tvsub(struct timeval *dst, const struct timeval *a, const struct timeval *b)
|
|||||||
dst->tv_sec = a->tv_sec - b->tv_sec;
|
dst->tv_sec = a->tv_sec - b->tv_sec;
|
||||||
dst->tv_usec = a->tv_usec - b->tv_usec;
|
dst->tv_usec = a->tv_usec - b->tv_usec;
|
||||||
|
|
||||||
if (dst->tv_usec < 0)
|
if (dst->tv_usec < 0) {
|
||||||
dst->tv_sec--, dst->tv_usec += 1000000;
|
dst->tv_sec--;
|
||||||
|
dst->tv_usec += 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
@@ -41,7 +45,7 @@ uc_tvcmp(const struct timeval *a, const struct timeval *b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct timeval *
|
struct timeval *
|
||||||
uc_to2tv(struct timeval *dst, unsigned long ms)
|
uc_ms2tv(struct timeval *dst, unsigned long long ms)
|
||||||
{
|
{
|
||||||
dst->tv_sec = ms / 1000;
|
dst->tv_sec = ms / 1000;
|
||||||
dst->tv_usec = ms % 1000 * 1000;
|
dst->tv_usec = ms % 1000 * 1000;
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ START_TEST (test_bitvec_setall_clearall)
|
|||||||
for (i = 0; i < sizeof(unsigned long) * 8; i++)
|
for (i = 0; i < sizeof(unsigned long) * 8; i++)
|
||||||
fail_if(uc_bv_get_bit(v, i) != 0 , "bit %zu is not 0", i);
|
fail_if(uc_bv_get_bit(v, i) != 0 , "bit %zu is not 0", i);
|
||||||
|
|
||||||
|
uc_bv_free(v);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
Suite *bitvec_suite(void)
|
Suite *bitvec_suite(void)
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ucore/dbuf.h>
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_dbuf)
|
||||||
|
DBuf buf;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_dbuf_init(&buf, 10);
|
||||||
|
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 10);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 10);
|
||||||
|
|
||||||
|
strcpy((char *)buf.end, "12345679");
|
||||||
|
uc_dbuf_added(&buf, 10);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 10);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 0);
|
||||||
|
|
||||||
|
rc = uc_dbuf_ensure(&buf, 110);
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 110);
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 120);
|
||||||
|
|
||||||
|
rc = uc_dbuf_ensure(&buf, 5);
|
||||||
|
fail_if(rc != 0);
|
||||||
|
strcpy((char *)buf.end, "ABCD");
|
||||||
|
uc_dbuf_added(&buf, 5);
|
||||||
|
uc_dbuf_take(&buf, 10);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 105);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 5);
|
||||||
|
ck_assert_str_eq((char *)buf.start, "ABCD");
|
||||||
|
|
||||||
|
uc_dbuf_take(&buf, 5);
|
||||||
|
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 120);
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 120);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 0);
|
||||||
|
|
||||||
|
strcpy((char *)buf.end, "EFGH");
|
||||||
|
uc_dbuf_added(&buf, 5);
|
||||||
|
uc_dbuf_trim(&buf);
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 5);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 5);
|
||||||
|
|
||||||
|
uc_dbuf_take(&buf, 1);
|
||||||
|
rc = uc_dbuf_ensure(&buf, 10);
|
||||||
|
fail_if(rc != 0);
|
||||||
|
ck_assert_str_eq((char *)buf.start, "FGH");
|
||||||
|
|
||||||
|
uc_dbuf_take(&buf, 1);
|
||||||
|
uc_dbuf_trim(&buf);
|
||||||
|
ck_assert_str_eq((char *)buf.start, "GH");
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 3);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 3);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uc_dbuf_free(&buf);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_dbuf_take_fail)
|
||||||
|
DBuf buf;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = uc_dbuf_init(&buf, 10);
|
||||||
|
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(uc_dbuf_buflen(&buf) != 10);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 10);
|
||||||
|
|
||||||
|
strcpy((char *)buf.end, "12345679");
|
||||||
|
uc_dbuf_added(&buf, 10);
|
||||||
|
fail_if(uc_dbuf_len(&buf) != 10);
|
||||||
|
fail_if(uc_dbuf_remaining(&buf) != 0);
|
||||||
|
|
||||||
|
rc = uc_dbuf_take(&buf, 11);
|
||||||
|
fail_if(rc == 0);
|
||||||
|
|
||||||
|
uc_dbuf_free(&buf);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Suite *dbuf_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("dbuf");
|
||||||
|
TCase *tc = tcase_create("dbuf tests");
|
||||||
|
tcase_add_test(tc, test_dbuf);
|
||||||
|
tcase_add_test(tc, test_dbuf_take_fail);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -164,6 +164,18 @@ START_TEST (test_uc_hex_encode_delim_zero_len)
|
|||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_uc_hex_decode_lowercase)
|
||||||
|
char hex[] = "1f";
|
||||||
|
uint8_t binary[2] = {0x11,0x22};
|
||||||
|
uint8_t *res;
|
||||||
|
|
||||||
|
res = uc_hex_decode(hex, 2, binary);
|
||||||
|
|
||||||
|
fail_if(binary[0] != 0x1f);
|
||||||
|
fail_if(binary[1] != 0x22);
|
||||||
|
fail_if(res != binary + 1, "binary %p, res %p", &binary[0], res);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
Suite *hex_suite(void)
|
Suite *hex_suite(void)
|
||||||
{
|
{
|
||||||
Suite *s = suite_create("hex");
|
Suite *s = suite_create("hex");
|
||||||
@@ -185,6 +197,8 @@ Suite *hex_suite(void)
|
|||||||
tcase_add_test(tc, test_uc_hex_decode_invalid);
|
tcase_add_test(tc, test_uc_hex_decode_invalid);
|
||||||
tcase_add_test(tc, test_uc_hex_decode_empty_string);
|
tcase_add_test(tc, test_uc_hex_decode_empty_string);
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_uc_hex_decode_lowercase);
|
||||||
|
|
||||||
|
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include <ucore/string.h>
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_human_bytesz_bytes)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_human_bytesz(999, result, sizeof result);
|
||||||
|
fail_if(rc == NULL);
|
||||||
|
ck_assert_str_eq(result, "999 b");
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_human_bytesz_bytes_0)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_human_bytesz(0, result, sizeof result);
|
||||||
|
fail_if(rc == NULL);
|
||||||
|
ck_assert_str_eq(result, "0 b");
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_human_bytesz_kilobytes)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_human_bytesz(64000, result, sizeof result);
|
||||||
|
fail_if(rc == NULL);
|
||||||
|
ck_assert_str_eq(result, "64.00 kB");
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_human_bytesz_megabytes)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_human_bytesz(6409000, result, sizeof result);
|
||||||
|
fail_if(rc == NULL);
|
||||||
|
ck_assert_str_eq(result, "6.41 MB");
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_human_bytesz_gigabytes)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_human_bytesz(126999400000, result, sizeof result);
|
||||||
|
fail_if(rc == NULL);
|
||||||
|
ck_assert_str_eq(result, "127.00 GB");
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_human_bytesz_terrabytes)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_human_bytesz(12453400030000, result, sizeof result);
|
||||||
|
fail_if(rc == NULL);
|
||||||
|
ck_assert_str_eq(result, "12.45 TB");
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_human_bytesz_petabytes)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_human_bytesz(~0LL, result, sizeof result);
|
||||||
|
fail_if(rc == NULL);
|
||||||
|
ck_assert_str_eq(result, "18446.74 PB");
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
Suite *human_bytesz_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("human_bytesz");
|
||||||
|
TCase *tc = tcase_create("human_bytesz tests");
|
||||||
|
tcase_add_test(tc, test_human_bytesz_bytes);
|
||||||
|
tcase_add_test(tc, test_human_bytesz_bytes_0);
|
||||||
|
tcase_add_test(tc, test_human_bytesz_kilobytes);
|
||||||
|
tcase_add_test(tc, test_human_bytesz_megabytes);
|
||||||
|
tcase_add_test(tc, test_human_bytesz_gigabytes);
|
||||||
|
tcase_add_test(tc, test_human_bytesz_terrabytes);
|
||||||
|
tcase_add_test(tc, test_human_bytesz_petabytes);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -50,6 +50,7 @@ START_TEST (test_logfile_location)
|
|||||||
dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1);
|
dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1);
|
||||||
fail_if(dest == NULL);
|
fail_if(dest == NULL);
|
||||||
uc_log_add_destination(dest);
|
uc_log_add_destination(dest);
|
||||||
|
uc_log_add_destination(dest); //adding this twice should do nothing
|
||||||
|
|
||||||
UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1);
|
UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1);
|
||||||
UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson 2\n");
|
UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson 2\n");
|
||||||
@@ -62,6 +63,54 @@ START_TEST (test_logfile_location)
|
|||||||
fail_if(st.st_size != 380, "was %ld\n", (long)st.st_size);
|
fail_if(st.st_size != 380, "was %ld\n", (long)st.st_size);
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_logfile_delete_destination)
|
||||||
|
|
||||||
|
struct uc_log_module m = {
|
||||||
|
.id = 0,
|
||||||
|
.short_name = "MOD1",
|
||||||
|
.long_name = "Module 1",
|
||||||
|
.log_level = UC_LL_DEBUG,
|
||||||
|
};
|
||||||
|
struct uc_log_modules mods = {
|
||||||
|
.mods = &m,
|
||||||
|
.cnt = 1,
|
||||||
|
};
|
||||||
|
struct stat st;
|
||||||
|
struct uc_log_destination *dest;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
uc_log_init(&mods);
|
||||||
|
|
||||||
|
dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1);
|
||||||
|
fail_if(dest == NULL);
|
||||||
|
uc_log_add_destination(dest);
|
||||||
|
uc_log_add_destination(dest); //adding this twice should do nothing
|
||||||
|
|
||||||
|
UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1);
|
||||||
|
UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson 2\n");
|
||||||
|
UC_LOGF(UC_LL_INFO, 0, "Lorum ipson 3\n");
|
||||||
|
UC_LOGF(UC_LL_WARNING, 0, "Lorum ipson 4\n");
|
||||||
|
UC_LOGF(UC_LL_ERROR, 0, "Lorum ipson 5\n");
|
||||||
|
|
||||||
|
rc = stat(FILE_NAME, &st);
|
||||||
|
fail_if(rc != 0, "stat failed: %s\n", strerror(errno));
|
||||||
|
fail_if(st.st_size != 380, "was %ld\n", (long)st.st_size);
|
||||||
|
|
||||||
|
uc_log_delete_destination(dest);
|
||||||
|
|
||||||
|
UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1);
|
||||||
|
UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson 2\n");
|
||||||
|
UC_LOGF(UC_LL_INFO, 0, "Lorum ipson 3\n");
|
||||||
|
UC_LOGF(UC_LL_WARNING, 0, "Lorum ipson 4\n");
|
||||||
|
UC_LOGF(UC_LL_ERROR, 0, "Lorum ipson 5\n");
|
||||||
|
|
||||||
|
//since we deleted destinatiion, no more logging should appear in the file
|
||||||
|
rc = stat(FILE_NAME, &st);
|
||||||
|
fail_if(rc != 0, "stat failed: %s\n", strerror(errno));
|
||||||
|
fail_if(st.st_size != 380, "was %ld\n", (long)st.st_size);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_logfile_no_location)
|
START_TEST (test_logfile_no_location)
|
||||||
|
|
||||||
struct uc_log_module m = {
|
struct uc_log_module m = {
|
||||||
@@ -476,6 +525,7 @@ Suite *logging_suite(void)
|
|||||||
TCase *tc2 = tcase_create("ucore_logging2");
|
TCase *tc2 = tcase_create("ucore_logging2");
|
||||||
|
|
||||||
tcase_add_test(tc1, test_logfile_location);
|
tcase_add_test(tc1, test_logfile_location);
|
||||||
|
tcase_add_test(tc1, test_logfile_delete_destination);
|
||||||
tcase_add_test(tc1, test_logfile_no_location);
|
tcase_add_test(tc1, test_logfile_no_location);
|
||||||
tcase_add_test(tc1, test_logfile_loglevel_surpressed_dest);
|
tcase_add_test(tc1, test_logfile_loglevel_surpressed_dest);
|
||||||
tcase_add_test(tc1, test_logfile_loglevel_surpressed_module);
|
tcase_add_test(tc1, test_logfile_loglevel_surpressed_module);
|
||||||
|
|||||||
@@ -0,0 +1,266 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ucore/mbuf.h>
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_new)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new(110);
|
||||||
|
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
fail_if(uc_mbuf_len(mbuf) != 0);
|
||||||
|
fail_if(uc_mbuf_headroom(mbuf) != 0);
|
||||||
|
fail_if(uc_mbuf_tailroom(mbuf) != 110);
|
||||||
|
fail_if(mbuf->next != NULL);
|
||||||
|
fail_if(mbuf->p1 != NULL);
|
||||||
|
fail_if(mbuf->p2 != NULL);
|
||||||
|
fail_if(mbuf->p3 != NULL);
|
||||||
|
fail_if(mbuf->p4 != NULL);
|
||||||
|
fail_if(mbuf->cookie != NULL);
|
||||||
|
fail_if(mbuf->head != mbuf->tail);
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_new_inline)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new_inline(110);
|
||||||
|
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
fail_if(uc_mbuf_len(mbuf) != 0);
|
||||||
|
fail_if(uc_mbuf_headroom(mbuf) != 0);
|
||||||
|
fail_if(uc_mbuf_tailroom(mbuf) != 110);
|
||||||
|
fail_if(mbuf->next != NULL);
|
||||||
|
fail_if(mbuf->p1 != NULL);
|
||||||
|
fail_if(mbuf->p2 != NULL);
|
||||||
|
fail_if(mbuf->p3 != NULL);
|
||||||
|
fail_if(mbuf->p4 != NULL);
|
||||||
|
fail_if(mbuf->cookie != NULL);
|
||||||
|
fail_if(mbuf->head != mbuf->tail);
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_new_headroom)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new_hr(110,20);
|
||||||
|
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
fail_if(uc_mbuf_len(mbuf) != 0);
|
||||||
|
fail_if(uc_mbuf_headroom(mbuf) != 20);
|
||||||
|
fail_if(uc_mbuf_tailroom(mbuf) != 110);
|
||||||
|
fail_if(mbuf->next != NULL);
|
||||||
|
fail_if(mbuf->p1 != NULL);
|
||||||
|
fail_if(mbuf->p2 != NULL);
|
||||||
|
fail_if(mbuf->p3 != NULL);
|
||||||
|
fail_if(mbuf->p4 != NULL);
|
||||||
|
fail_if(mbuf->cookie != NULL);
|
||||||
|
fail_if(mbuf->head != mbuf->tail);
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_put)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
uint8_t *data;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new_inline(111);
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
|
||||||
|
data = uc_mbuf_put(mbuf, 111);
|
||||||
|
fail_if(data == NULL);
|
||||||
|
fail_if(uc_mbuf_len(mbuf) != 111);
|
||||||
|
fail_if(uc_mbuf_tailroom(mbuf) != 0);
|
||||||
|
|
||||||
|
memset(data, 0, 111);
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_put_fail)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
uint8_t *data;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new_inline(10);
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
|
||||||
|
data = uc_mbuf_put(mbuf, 11);
|
||||||
|
fail_if(data != NULL);
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_push)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
uint8_t *data;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new_hr(10,1);
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
|
||||||
|
data = uc_mbuf_push(mbuf, 1);
|
||||||
|
fail_if(data == NULL);
|
||||||
|
fail_if(uc_mbuf_len(mbuf) != 1);
|
||||||
|
fail_if(uc_mbuf_headroom(mbuf) != 0);
|
||||||
|
|
||||||
|
*data = 0;
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_push_fail)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
uint8_t *data;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new_hr(1,2);
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
|
||||||
|
data = uc_mbuf_push(mbuf, 3);
|
||||||
|
fail_if(data != NULL);
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_pull)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
uint8_t *data1;
|
||||||
|
uint8_t *data2;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new_inline(10);
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
|
||||||
|
data1 = uc_mbuf_put(mbuf, 10);
|
||||||
|
fail_if(data1 == NULL);
|
||||||
|
fail_if(uc_mbuf_tailroom(mbuf) != 0);
|
||||||
|
fail_if(uc_mbuf_len(mbuf) != 10);
|
||||||
|
|
||||||
|
data2 = uc_mbuf_pull(mbuf,10);
|
||||||
|
fail_if(data2 == NULL);
|
||||||
|
fail_if(data1 != data2);
|
||||||
|
fail_if(uc_mbuf_len(mbuf) != 0);
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_pull_fail)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
uint8_t *data1;
|
||||||
|
uint8_t *data2;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new_inline(10);
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
|
||||||
|
data1 = uc_mbuf_put(mbuf, 10);
|
||||||
|
fail_if(data1 == NULL);
|
||||||
|
fail_if(uc_mbuf_len(mbuf) != 10);
|
||||||
|
|
||||||
|
data2 = uc_mbuf_pull(mbuf,11);
|
||||||
|
fail_if(data2 != NULL);
|
||||||
|
fail_if(uc_mbuf_len(mbuf) != 10);
|
||||||
|
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_copy)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
uint8_t *data1;
|
||||||
|
struct MBuf *copy;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new_inline_hr(10,5);
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
|
||||||
|
data1 = uc_mbuf_put(mbuf, 10);
|
||||||
|
fail_if(data1 == NULL);
|
||||||
|
|
||||||
|
strcpy((char*)data1, "123456789");
|
||||||
|
|
||||||
|
copy = uc_mbuf_copy_data(mbuf);
|
||||||
|
fail_if(copy == NULL);
|
||||||
|
fail_if(uc_mbuf_len(copy) != 10);
|
||||||
|
fail_if(uc_mbuf_headroom(copy) != 5);
|
||||||
|
fail_if(memcmp(mbuf->head, copy->head, 10) != 0);
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
uc_mbuf_free(copy);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_zero)
|
||||||
|
struct MBuf *mbuf;
|
||||||
|
uint8_t *data1;
|
||||||
|
|
||||||
|
mbuf = uc_mbuf_new_inline(10);
|
||||||
|
fail_if(mbuf == NULL);
|
||||||
|
|
||||||
|
data1 = uc_mbuf_put(mbuf, 10);
|
||||||
|
fail_if(data1 == NULL);
|
||||||
|
|
||||||
|
strcpy((char*)data1, "123456789");
|
||||||
|
uc_mbuf_zero(mbuf);
|
||||||
|
|
||||||
|
fail_if(memcmp(mbuf->head, "\0\0\0\0\0\0\0\0\0\0", 10) != 0);
|
||||||
|
|
||||||
|
uc_mbuf_free(mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_mbuf_static)
|
||||||
|
|
||||||
|
uint8_t data[1024];
|
||||||
|
struct MBuf mbuf;
|
||||||
|
|
||||||
|
uc_mbuf_init(&mbuf, data, 1000, 24, UC_MBUF_FL_STATIC);
|
||||||
|
|
||||||
|
fail_if(uc_mbuf_len(&mbuf) != 0);
|
||||||
|
fail_if(uc_mbuf_headroom(&mbuf) != 24);
|
||||||
|
fail_if(uc_mbuf_tailroom(&mbuf) != 1000);
|
||||||
|
fail_if(mbuf.next != NULL);
|
||||||
|
fail_if(mbuf.p1 != NULL);
|
||||||
|
fail_if(mbuf.p2 != NULL);
|
||||||
|
fail_if(mbuf.p3 != NULL);
|
||||||
|
fail_if(mbuf.p4 != NULL);
|
||||||
|
fail_if(mbuf.cookie != NULL);
|
||||||
|
fail_if(mbuf.head != mbuf.tail);
|
||||||
|
fail_if(mbuf.head != &data[24]);
|
||||||
|
|
||||||
|
uc_mbuf_free(&mbuf);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Suite *mbuf_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("mbuf");
|
||||||
|
TCase *tc = tcase_create("mbuf tests");
|
||||||
|
tcase_add_test(tc, test_mbuf_new);
|
||||||
|
tcase_add_test(tc, test_mbuf_new_inline);
|
||||||
|
tcase_add_test(tc, test_mbuf_new_headroom);
|
||||||
|
tcase_add_test(tc, test_mbuf_put);
|
||||||
|
tcase_add_test(tc, test_mbuf_put_fail);
|
||||||
|
tcase_add_test(tc, test_mbuf_push);
|
||||||
|
tcase_add_test(tc, test_mbuf_push_fail);
|
||||||
|
tcase_add_test(tc, test_mbuf_pull);
|
||||||
|
tcase_add_test(tc, test_mbuf_pull_fail);
|
||||||
|
tcase_add_test(tc, test_mbuf_copy);
|
||||||
|
tcase_add_test(tc, test_mbuf_zero);
|
||||||
|
tcase_add_test(tc, test_mbuf_static);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -91,6 +91,65 @@ START_TEST (test_read_file_boundary)
|
|||||||
free(content);
|
free(content);
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_read_file_devnull)
|
||||||
|
char *content;
|
||||||
|
size_t len = 123;
|
||||||
|
|
||||||
|
content = uc_read_file("/dev/null", &len, 1024);
|
||||||
|
fail_if(content == NULL);
|
||||||
|
fail_if(len != 0);
|
||||||
|
free(content);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_read_file_too_big)
|
||||||
|
char *content;
|
||||||
|
const char *filename = "test_read_file_too_big";
|
||||||
|
size_t len;
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||||
|
fail_if(fd == -1);
|
||||||
|
|
||||||
|
rc = write(fd, "hello", 5);
|
||||||
|
fail_if(rc != 5, "rc was %ld", (long)rc);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
content = uc_read_file(filename, &len, 4);
|
||||||
|
|
||||||
|
fail_if(errno != EMSGSIZE);
|
||||||
|
fail_if(content != NULL);
|
||||||
|
|
||||||
|
unlink(filename);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_read_file_big)
|
||||||
|
char *content;
|
||||||
|
const char *filename = "test_read_file_big";
|
||||||
|
char buf[4096 * 16];
|
||||||
|
size_t len;
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||||
|
fail_if(fd == -1);
|
||||||
|
memset(buf, 'a', sizeof buf);
|
||||||
|
|
||||||
|
rc = write(fd, buf, sizeof buf);
|
||||||
|
fail_if(rc != sizeof buf, "rc was %ld", (long)rc);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
content = uc_read_file(filename, &len, 4096*16);
|
||||||
|
fail_if(content == NULL);
|
||||||
|
fail_if(len != sizeof buf);
|
||||||
|
fail_if(memcmp(content, buf, sizeof buf) != 0);
|
||||||
|
|
||||||
|
free(content);
|
||||||
|
|
||||||
|
unlink(filename);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
Suite *read_file_suite(void)
|
Suite *read_file_suite(void)
|
||||||
{
|
{
|
||||||
Suite *s = suite_create("read_file");
|
Suite *s = suite_create("read_file");
|
||||||
@@ -99,6 +158,10 @@ Suite *read_file_suite(void)
|
|||||||
tcase_add_test(tc, test_read_file_simple);
|
tcase_add_test(tc, test_read_file_simple);
|
||||||
tcase_add_test(tc, test_read_file_greater_than_max);
|
tcase_add_test(tc, test_read_file_greater_than_max);
|
||||||
tcase_add_test(tc, test_read_file_boundary);
|
tcase_add_test(tc, test_read_file_boundary);
|
||||||
|
tcase_add_test(tc, test_read_file_devnull);
|
||||||
|
tcase_add_test(tc, test_read_file_too_big);
|
||||||
|
tcase_add_test(tc, test_read_file_big);
|
||||||
|
|
||||||
|
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
|||||||
+11
-1
@@ -19,6 +19,11 @@ extern Suite *clock_suite(void);
|
|||||||
extern Suite *seq_suite(void);
|
extern Suite *seq_suite(void);
|
||||||
extern Suite *sat_math_suite(void);
|
extern Suite *sat_math_suite(void);
|
||||||
extern Suite *timers_suite(void);
|
extern Suite *timers_suite(void);
|
||||||
|
extern Suite *mbuf_suite(void);
|
||||||
|
extern Suite *human_bytesz_suite(void);
|
||||||
|
extern Suite *dbuf_suite(void);
|
||||||
|
extern Suite *sprintb_suite(void);
|
||||||
|
extern Suite *strv_suite(void);
|
||||||
|
|
||||||
static suite_func suites[] = {
|
static suite_func suites[] = {
|
||||||
bitvec_suite,
|
bitvec_suite,
|
||||||
@@ -33,7 +38,12 @@ static suite_func suites[] = {
|
|||||||
clock_suite,
|
clock_suite,
|
||||||
seq_suite,
|
seq_suite,
|
||||||
sat_math_suite,
|
sat_math_suite,
|
||||||
timers_suite
|
timers_suite,
|
||||||
|
mbuf_suite,
|
||||||
|
human_bytesz_suite,
|
||||||
|
dbuf_suite,
|
||||||
|
sprintb_suite,
|
||||||
|
strv_suite
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <ucore/string.h>
|
||||||
|
|
||||||
|
//Note these tests assume
|
||||||
|
// char 8 bit
|
||||||
|
// short 16 bit
|
||||||
|
// int 32 bit
|
||||||
|
// long long 64 bit
|
||||||
|
|
||||||
|
START_TEST (test_sprintb)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_sprintb(result, 0);
|
||||||
|
ck_assert_str_eq(rc, "00000000000000000000000000000000");
|
||||||
|
|
||||||
|
rc = uc_sprintb(result, UINT_MAX);
|
||||||
|
ck_assert_str_eq(rc, "11111111111111111111111111111111");
|
||||||
|
|
||||||
|
rc = uc_sprintb(result, 0xE0A14341);
|
||||||
|
ck_assert_str_eq(rc, "11100000101000010100001101000001");
|
||||||
|
|
||||||
|
rc = uc_sprintb(result, 1);
|
||||||
|
ck_assert_str_eq(rc, "00000000000000000000000000000001");
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_sprintbc)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_sprintbc(result, 0);
|
||||||
|
ck_assert_str_eq(rc, "00000000");
|
||||||
|
|
||||||
|
rc = uc_sprintbc(result, UCHAR_MAX);
|
||||||
|
ck_assert_str_eq(rc, "11111111");
|
||||||
|
|
||||||
|
rc = uc_sprintbc(result, 0xE1);
|
||||||
|
ck_assert_str_eq(rc, "11100001");
|
||||||
|
|
||||||
|
rc = uc_sprintbc(result, 1);
|
||||||
|
ck_assert_str_eq(rc, "00000001");
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_sprintbs)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_sprintbs(result, 0);
|
||||||
|
ck_assert_str_eq(rc, "0000000000000000");
|
||||||
|
|
||||||
|
rc = uc_sprintbs(result, USHRT_MAX);
|
||||||
|
ck_assert_str_eq(rc, "1111111111111111");
|
||||||
|
|
||||||
|
rc = uc_sprintbs(result, 0xE0A1);
|
||||||
|
ck_assert_str_eq(rc, "1110000010100001");
|
||||||
|
|
||||||
|
rc = uc_sprintbs(result, 1);
|
||||||
|
ck_assert_str_eq(rc, "0000000000000001");
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_sprintbll)
|
||||||
|
char result[128];
|
||||||
|
char *rc;
|
||||||
|
|
||||||
|
rc = uc_sprintbll(result, 0);
|
||||||
|
ck_assert_str_eq(rc, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
|
|
||||||
|
rc = uc_sprintbll(result, ULLONG_MAX);
|
||||||
|
ck_assert_str_eq(rc, "1111111111111111111111111111111111111111111111111111111111111111");
|
||||||
|
|
||||||
|
rc = uc_sprintbll(result, 0xE0A14341E0A14341ULL);
|
||||||
|
ck_assert_str_eq(rc, "1110000010100001010000110100000111100000101000010100001101000001");
|
||||||
|
|
||||||
|
rc = uc_sprintbll(result, 1);
|
||||||
|
ck_assert_str_eq(rc, "0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite *sprintb_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("sprintb");
|
||||||
|
TCase *tc = tcase_create("sprintb tests");
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_sprintb);
|
||||||
|
tcase_add_test(tc, test_sprintbc);
|
||||||
|
tcase_add_test(tc, test_sprintbs);
|
||||||
|
tcase_add_test(tc, test_sprintbll);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#include <check.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ucore/strvec.h>
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_strv_append)
|
||||||
|
struct UCStrv strv;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
uc_strv_init(&strv);
|
||||||
|
|
||||||
|
rc = uc_strv_append(&strv, "string");
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(strv.cnt != 1);
|
||||||
|
ck_assert_str_eq("string", strv.strings[0]);
|
||||||
|
|
||||||
|
rc = uc_strv_append(&strv, "string2");
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(strv.cnt != 2);
|
||||||
|
ck_assert_str_eq("string2", strv.strings[1]);
|
||||||
|
|
||||||
|
uc_strv_destroy(&strv);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_strv_clear)
|
||||||
|
struct UCStrv strv;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
uc_strv_init(&strv);
|
||||||
|
|
||||||
|
rc = uc_strv_append(&strv, "string");
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(strv.cnt != 1);
|
||||||
|
|
||||||
|
uc_strv_clear(&strv);
|
||||||
|
fail_if(strv.cnt != 0);
|
||||||
|
uc_strv_destroy(&strv);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_strv_nocopy)
|
||||||
|
struct UCStrv strv;
|
||||||
|
char *str = strdup("string");
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
uc_strv_init(&strv);
|
||||||
|
|
||||||
|
rc = uc_strv_append_nocopy(&strv, str);
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(strv.cnt != 1);
|
||||||
|
fail_if(strv.strings[0] != str);
|
||||||
|
|
||||||
|
uc_strv_destroy(&strv);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_strv_null_terminate)
|
||||||
|
struct UCStrv strv;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
uc_strv_init(&strv);
|
||||||
|
|
||||||
|
rc = uc_strv_append(&strv, "string");
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(strv.cnt != 1);
|
||||||
|
|
||||||
|
rc = uc_strv_null_terminate(&strv);
|
||||||
|
fail_if(rc != 0);
|
||||||
|
fail_if(strv.strings[strv.cnt] != NULL);
|
||||||
|
|
||||||
|
uc_strv_destroy(&strv);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
Suite *strv_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("strvec");
|
||||||
|
TCase *tc = tcase_create("strvec");
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_strv_append);
|
||||||
|
tcase_add_test(tc, test_strv_clear);
|
||||||
|
tcase_add_test(tc, test_strv_nocopy);
|
||||||
|
tcase_add_test(tc, test_strv_null_terminate);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -160,6 +160,47 @@ START_TEST (test_timers_remove_from_callback)
|
|||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_timers_add_remove)
|
||||||
|
struct UCoreSettableClock clk;
|
||||||
|
struct TimerTest tt;
|
||||||
|
struct UCTimers timers;
|
||||||
|
struct UCTimer timer1;
|
||||||
|
struct UCTimer timer2;
|
||||||
|
struct UCTimer timer3;
|
||||||
|
struct UCTimer timer4;
|
||||||
|
struct timeval first;
|
||||||
|
|
||||||
|
common_init(&clk, &tt, &timers, &timer1);
|
||||||
|
memset(&timer2, 0, sizeof timer2);
|
||||||
|
memset(&timer3, 0, sizeof timer2);
|
||||||
|
memset(&timer4, 0, sizeof timer2);
|
||||||
|
|
||||||
|
timer1.callback = timer_test_cb_add;
|
||||||
|
timer2.callback = timer_test_cb_add;
|
||||||
|
timer3.callback = timer_test_cb_add;
|
||||||
|
timer4.callback = timer_test_cb_add;
|
||||||
|
|
||||||
|
uc_timers_add(&timers, &timer1, 10, 0);
|
||||||
|
uc_timers_add(&timers, &timer2, 5 , 0);
|
||||||
|
uc_timers_add(&timers, &timer3, 15, 1);
|
||||||
|
uc_timers_add(&timers, &timer4, 15, 1);
|
||||||
|
|
||||||
|
fail_if(uc_timers_first(&timers, &first) != 0);
|
||||||
|
fail_if(first.tv_sec != TEST_TIMER_START + 5);
|
||||||
|
fail_if(first.tv_usec != 0);
|
||||||
|
|
||||||
|
fail_if(uc_timers_count(&timers) != 4);
|
||||||
|
|
||||||
|
uc_timers_remove(&timers, &timer1);
|
||||||
|
uc_timers_remove(&timers, &timer2);
|
||||||
|
uc_timers_remove(&timers, &timer3);
|
||||||
|
uc_timers_remove(&timers, &timer4);
|
||||||
|
|
||||||
|
fail_if(uc_timers_count(&timers) != 0);
|
||||||
|
fail_if(uc_timers_first(&timers, &first) == 0);
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
Suite *timers_suite(void)
|
Suite *timers_suite(void)
|
||||||
{
|
{
|
||||||
@@ -168,6 +209,7 @@ Suite *timers_suite(void)
|
|||||||
tcase_add_test(tc, test_timers_simple);
|
tcase_add_test(tc, test_timers_simple);
|
||||||
tcase_add_test(tc, test_timers_add_from_callback);
|
tcase_add_test(tc, test_timers_add_from_callback);
|
||||||
tcase_add_test(tc, test_timers_remove_from_callback);
|
tcase_add_test(tc, test_timers_remove_from_callback);
|
||||||
|
tcase_add_test(tc, test_timers_add_remove);
|
||||||
|
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user