mirror of
https://github.com/tezc/sc.git
synced 2025-01-28 07:03:06 +08:00
parent
c461dbec07
commit
1bde3abd9f
@ -20,10 +20,11 @@ add_subdirectory(ini)
|
||||
add_subdirectory(linked-list)
|
||||
add_subdirectory(logger)
|
||||
add_subdirectory(map)
|
||||
add_subdirectory(memory-map)
|
||||
add_subdirectory(mutex)
|
||||
add_subdirectory(queue)
|
||||
add_subdirectory(perf)
|
||||
add_subdirectory(pipe)
|
||||
add_subdirectory(socket)
|
||||
add_subdirectory(string)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(timer)
|
||||
@ -61,7 +62,7 @@ add_custom_command(
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind ${CMAKE_COMMAND}
|
||||
|
@ -53,7 +53,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -93,7 +93,7 @@ bool sc_array_expand(void **arr, size_t elem_size)
|
||||
|
||||
// Check overflow
|
||||
if (meta->cap > max / 2) {
|
||||
sc_array_on_error("Max capacity(%zu) has been reached. ", max / 2);
|
||||
sc_array_on_error("Max+ capacity(%zu) has been reached. ", max / 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -55,10 +55,10 @@ bool sc_array_expand(void **arr, size_t elem_size);
|
||||
|
||||
|
||||
/**
|
||||
* If you want to log or abort on errors like out of memory,
|
||||
* put your error function here. It will be called with printf like error msg.
|
||||
* If you want to log or abort on out of memory, put your error function here.
|
||||
* It will be called with printf like error msg.
|
||||
*
|
||||
* my_on_error(const char* fmt, ...);
|
||||
* my_on_oom(const char* fmt, ...);
|
||||
*/
|
||||
#define sc_array_on_error(...)
|
||||
|
||||
|
@ -48,7 +48,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -34,16 +34,14 @@ void test1()
|
||||
double x = sc_buf_get_double(&buf);
|
||||
assert(x == (double)123211.323321);
|
||||
sc_buf_put_str(&buf, "test");
|
||||
assert(sc_buf_peek_strlen(&buf) == 4);
|
||||
assert(strcmp("test", sc_buf_get_str(&buf)) == 0);
|
||||
sc_buf_put_str(&buf, NULL);
|
||||
assert(sc_buf_peek_strlen(&buf) == 0);
|
||||
assert(sc_buf_get_str(&buf) == NULL);
|
||||
sc_buf_clear(&buf);
|
||||
assert(sc_buf_count(&buf) == 0);
|
||||
assert(sc_buf_size(&buf) == 0);
|
||||
assert(sc_buf_cap(&buf) == 100);
|
||||
sc_buf_compact(&buf);
|
||||
sc_buf_put_as_str(&buf, "%d", 3);
|
||||
sc_buf_put_fmt(&buf, "%d", 3);
|
||||
assert(strcmp("3", sc_buf_get_str(&buf)) == 0);
|
||||
sc_buf_put_bool(&buf, true);
|
||||
assert(sc_buf_get_bool(&buf) == true);
|
||||
@ -55,48 +53,44 @@ void test1()
|
||||
|
||||
sc_buf_put_64(&buf, 122);
|
||||
sc_buf_put_64(&buf, 133);
|
||||
sc_buf_set_64_at(&buf, 8, 144);
|
||||
sc_buf_get_64(&buf);
|
||||
assert(sc_buf_get_64(&buf) == 144);
|
||||
assert(sc_buf_get_64(&buf) == 133);
|
||||
sc_buf_clear(&buf);
|
||||
|
||||
sc_buf_put_32(&buf, 122);
|
||||
sc_buf_put_32(&buf, 133);
|
||||
sc_buf_set_32_at(&buf, 4, 144);
|
||||
sc_buf_put_32(&buf, 144);
|
||||
sc_buf_get_32(&buf);
|
||||
assert(sc_buf_get_32(&buf) == 144);
|
||||
sc_buf_clear(&buf);
|
||||
sc_buf_put_64(&buf, 222);
|
||||
sc_buf_mark_read(&buf, 8);
|
||||
assert(sc_buf_count(&buf) == 0);
|
||||
assert(sc_buf_size(&buf) == 0);
|
||||
char *c = sc_buf_write_buf(&buf);
|
||||
*c = 'c';
|
||||
sc_buf_mark_write(&buf, 1);
|
||||
assert(sc_buf_get_8(&buf) == 'c');
|
||||
sc_buf_clear(&buf);
|
||||
sc_buf_put_64(&buf, 0xFFFFFFF);
|
||||
sc_buf_memset(&buf, 0, 0, 8);
|
||||
assert(sc_buf_get_64(&buf) == 0);
|
||||
|
||||
sc_buf_clear(&buf);
|
||||
sc_buf_put_32(&buf, 2323);
|
||||
sc_buf_set_32(&buf, 3311);
|
||||
sc_buf_put_32(&buf, 3311);
|
||||
sc_buf_set_write_pos(&buf, 8);
|
||||
sc_buf_set_read_pos(&buf, 4);
|
||||
assert(sc_buf_get_32(&buf) == 3311);
|
||||
sc_buf_clear(&buf);
|
||||
sc_buf_put_64(&buf, UINT64_MAX);
|
||||
assert(sc_buf_peek_64_at(&buf, 0) == UINT64_MAX);
|
||||
assert(sc_buf_get_64(&buf) == UINT64_MAX);
|
||||
sc_buf_put_64(&buf, UINT64_MAX);
|
||||
|
||||
unsigned char* z = sc_buf_read_buf(&buf);
|
||||
assert(*z == 0xFF);
|
||||
assert(sc_buf_get_write_pos(&buf) == 8);
|
||||
assert(sc_buf_quota(&buf) == 100 - 8);
|
||||
assert(sc_buf_get_write_pos(&buf) == 16);
|
||||
assert(sc_buf_quota(&buf) == 100 - 16);
|
||||
assert(sc_buf_get_blob(&buf, 0) == NULL);
|
||||
|
||||
sc_buf_move(&buf2, &buf);
|
||||
assert(sc_buf_get_64(&buf2) == UINT64_MAX);
|
||||
assert(sc_buf_count(&buf) == 0);
|
||||
assert(sc_buf_size(&buf) == 0);
|
||||
|
||||
char tmp[] = "testtesttesttesttesttesttesttesttesttesttesttesttetesttesttesttesttesttesttesttesttesttesttesttesttestteststtest";
|
||||
sc_buf_put_str(&buf, tmp);
|
||||
@ -113,35 +107,23 @@ void test1()
|
||||
sc_buf_compact(&buf);
|
||||
assert(sc_buf_get_read_pos(&buf) == 0);
|
||||
assert(sc_buf_get_write_pos(&buf) == 8);
|
||||
assert(sc_buf_is_valid(&buf));
|
||||
assert(sc_buf_valid(&buf));
|
||||
sc_buf_term(&buf);
|
||||
|
||||
sc_buf_init(&buf, 100);
|
||||
sc_buf_limit(&buf, 128);
|
||||
sc_buf_put_str(&buf, tmp);
|
||||
assert(sc_buf_is_valid(&buf) == false);
|
||||
assert(sc_buf_valid(&buf) == false);
|
||||
assert(sc_buf_get_64(&buf) == 0);
|
||||
sc_buf_term(&buf);
|
||||
|
||||
sc_buf_init(&buf, 100);
|
||||
sc_buf_limit(&buf, 128);
|
||||
sc_buf_put_as_str(&buf, tmp);
|
||||
assert(sc_buf_is_valid(&buf) == false);
|
||||
sc_buf_put_fmt(&buf, tmp);
|
||||
assert(sc_buf_valid(&buf) == false);
|
||||
assert(sc_buf_get_64(&buf) == 0);
|
||||
sc_buf_term(&buf);
|
||||
|
||||
sc_buf_init(&buf, 16);
|
||||
sc_buf_put_64(&buf, 23131);
|
||||
sc_buf_put_64(&buf, 23131);
|
||||
sc_buf_peek_64_at(&buf, 32);
|
||||
assert(sc_buf_is_valid(&buf) == false);
|
||||
sc_buf_term(&buf);
|
||||
|
||||
sc_buf_init(&buf, 100);
|
||||
sc_buf_set_32_at(&buf, 1000, 2332),
|
||||
assert(sc_buf_is_valid(&buf) == false);
|
||||
sc_buf_term(&buf);
|
||||
|
||||
sc_buf_term(&buf2);
|
||||
}
|
||||
|
||||
|
113
buffer/sc_buf.c
113
buffer/sc_buf.c
@ -80,10 +80,17 @@
|
||||
|
||||
#define sy_buf_min(a, b) ((a) > (b) ? (b) : (a))
|
||||
|
||||
void sc_buf_init(struct sc_buf *buf, uint32_t cap)
|
||||
int sc_buf_init(struct sc_buf *buf, uint32_t cap)
|
||||
{
|
||||
void *mem = sc_buf_malloc(cap);
|
||||
if (mem == NULL) {
|
||||
sc_buf_on_error("Failed to allocate %zu bytes. ", cap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*buf = sc_buf_wrap(mem, cap, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sc_buf sc_buf_wrap(void *data, uint32_t len, bool ref)
|
||||
@ -111,8 +118,6 @@ void sc_buf_term(struct sc_buf *buf)
|
||||
|
||||
void sc_buf_limit(struct sc_buf *buf, uint32_t limit)
|
||||
{
|
||||
assert(limit < 1 * 1024 * 1024 * 1024);
|
||||
|
||||
buf->limit = limit;
|
||||
}
|
||||
|
||||
@ -149,7 +154,7 @@ static bool sc_buf_reserve(struct sc_buf *buf, uint32_t len)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sc_buf_is_valid(struct sc_buf *buf)
|
||||
bool sc_buf_valid(struct sc_buf *buf)
|
||||
{
|
||||
return !buf->corrupt;
|
||||
}
|
||||
@ -159,7 +164,7 @@ uint32_t sc_buf_quota(struct sc_buf *buf)
|
||||
return buf->cap - buf->write_pos;
|
||||
}
|
||||
|
||||
uint32_t sc_buf_count(struct sc_buf *buf)
|
||||
uint32_t sc_buf_size(struct sc_buf *buf)
|
||||
{
|
||||
return buf->write_pos - buf->read_pos;
|
||||
}
|
||||
@ -212,13 +217,6 @@ void *sc_buf_write_buf(struct sc_buf *buf)
|
||||
return buf->mem + buf->write_pos;
|
||||
}
|
||||
|
||||
void sc_buf_memset(struct sc_buf *buf, int val, uint32_t offset, uint32_t len)
|
||||
{
|
||||
assert(offset + len < buf->cap);
|
||||
|
||||
memset(buf->mem + offset, val, len);
|
||||
}
|
||||
|
||||
void sc_buf_compact(struct sc_buf *buf)
|
||||
{
|
||||
uint32_t copy;
|
||||
@ -262,7 +260,7 @@ uint32_t sc_buf_set_data(struct sc_buf *buf, uint32_t offset, const void *src,
|
||||
return len;
|
||||
}
|
||||
|
||||
void sc_buf_get_data(struct sc_buf *buf, void *dest, uint32_t len)
|
||||
void sc_buf_get_raw(struct sc_buf *buf, void *dest, uint32_t len)
|
||||
{
|
||||
if (buf->read_pos + len > buf->write_pos) {
|
||||
buf->corrupt = true;
|
||||
@ -273,7 +271,7 @@ void sc_buf_get_data(struct sc_buf *buf, void *dest, uint32_t len)
|
||||
buf->read_pos += sc_buf_peek_data(buf, buf->read_pos, dest, len);
|
||||
}
|
||||
|
||||
void sc_buf_put_data(struct sc_buf *buf, const void *ptr, uint32_t len)
|
||||
void sc_buf_put_raw(struct sc_buf *buf, const void *ptr, uint32_t len)
|
||||
{
|
||||
if (!sc_buf_reserve(buf, len)) {
|
||||
return;
|
||||
@ -296,21 +294,21 @@ uint8_t sc_buf_get_8(struct sc_buf *buf)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
sc_buf_get_data(buf, &val, 1);
|
||||
sc_buf_get_raw(buf, &val, 1);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void sc_buf_put_8(struct sc_buf *buf, uint8_t byte)
|
||||
{
|
||||
sc_buf_put_data(buf, &byte, sizeof(byte));
|
||||
sc_buf_put_raw(buf, &byte, sizeof(byte));
|
||||
}
|
||||
|
||||
uint16_t sc_buf_get_16(struct sc_buf *buf)
|
||||
{
|
||||
uint16_t val;
|
||||
|
||||
sc_buf_get_data(buf, &val, sizeof(val));
|
||||
sc_buf_get_raw(buf, &val, sizeof(val));
|
||||
|
||||
return sc_swap16(val);
|
||||
}
|
||||
@ -318,78 +316,37 @@ uint16_t sc_buf_get_16(struct sc_buf *buf)
|
||||
void sc_buf_put_16(struct sc_buf *buf, uint16_t val)
|
||||
{
|
||||
uint16_t sw = sc_swap16(val);
|
||||
sc_buf_put_data(buf, &sw, sizeof(sw));
|
||||
}
|
||||
|
||||
uint32_t sc_buf_peek_32_at(struct sc_buf *buf, uint32_t pos)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
sc_buf_peek_data(buf, pos, &val, 4);
|
||||
|
||||
return sc_swap32(val);
|
||||
}
|
||||
|
||||
uint32_t sc_buf_peek_32(struct sc_buf *buf)
|
||||
{
|
||||
return sc_buf_peek_32_at(buf, buf->read_pos);
|
||||
sc_buf_put_raw(buf, &sw, sizeof(sw));
|
||||
}
|
||||
|
||||
uint32_t sc_buf_get_32(struct sc_buf *buf)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
sc_buf_get_data(buf, &val, sizeof(val));
|
||||
sc_buf_get_raw(buf, &val, sizeof(val));
|
||||
|
||||
return sc_swap32(val);
|
||||
}
|
||||
|
||||
void sc_buf_set_32_at(struct sc_buf *buf, uint32_t pos, uint32_t val)
|
||||
{
|
||||
uint32_t sw = sc_swap32(val);
|
||||
sc_buf_set_data(buf, pos, &sw, sizeof(sw));
|
||||
}
|
||||
|
||||
void sc_buf_set_32(struct sc_buf *buf, uint32_t val)
|
||||
{
|
||||
uint32_t sw = sc_swap32(val);
|
||||
sc_buf_set_data(buf, buf->write_pos, &sw, sizeof(sw));
|
||||
}
|
||||
|
||||
void sc_buf_put_32(struct sc_buf *buf, uint32_t val)
|
||||
{
|
||||
uint32_t sw = sc_swap32(val);
|
||||
sc_buf_put_data(buf, &sw, sizeof(sw));
|
||||
}
|
||||
|
||||
uint64_t sc_buf_peek_64_at(struct sc_buf *buf, uint32_t pos)
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
sc_buf_peek_data(buf, pos, &val, sizeof(val));
|
||||
|
||||
return sc_swap64(val);
|
||||
sc_buf_put_raw(buf, &sw, sizeof(sw));
|
||||
}
|
||||
|
||||
uint64_t sc_buf_get_64(struct sc_buf *buf)
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
sc_buf_get_data(buf, &val, sizeof(val));
|
||||
sc_buf_get_raw(buf, &val, sizeof(val));
|
||||
|
||||
return sc_swap64(val);
|
||||
}
|
||||
|
||||
void sc_buf_set_64_at(struct sc_buf *buf, uint32_t pos, uint64_t val)
|
||||
{
|
||||
uint64_t sw = sc_swap64(val);
|
||||
sc_buf_set_data(buf, pos, &sw, sizeof(sw));
|
||||
}
|
||||
|
||||
void sc_buf_put_64(struct sc_buf *buf, uint64_t val)
|
||||
{
|
||||
uint64_t sw = sc_swap64(val);
|
||||
sc_buf_put_data(buf, &sw, sizeof(sw));
|
||||
sc_buf_put_raw(buf, &sw, sizeof(sw));
|
||||
}
|
||||
|
||||
double sc_buf_get_double(struct sc_buf *buf)
|
||||
@ -397,7 +354,7 @@ double sc_buf_get_double(struct sc_buf *buf)
|
||||
double d;
|
||||
uint64_t val;
|
||||
|
||||
sc_buf_get_data(buf, &val, 8);
|
||||
sc_buf_get_raw(buf, &val, 8);
|
||||
val = sc_swap64(val);
|
||||
|
||||
memcpy(&d, &val, 8);
|
||||
@ -410,19 +367,7 @@ void sc_buf_put_double(struct sc_buf *buf, double val)
|
||||
memcpy(&sw, &val, 8);
|
||||
|
||||
sw = sc_swap64(sw);
|
||||
sc_buf_put_data(buf, &sw, 8);
|
||||
}
|
||||
|
||||
uint32_t sc_buf_peek_strlen(struct sc_buf *buf)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = sc_buf_peek_32(buf);
|
||||
if (len == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
sc_buf_put_raw(buf, &sw, 8);
|
||||
}
|
||||
|
||||
const char *sc_buf_get_str(struct sc_buf *buf)
|
||||
@ -453,12 +398,13 @@ void sc_buf_put_str(struct sc_buf *buf, const char *str)
|
||||
size = strlen(str);
|
||||
|
||||
sc_buf_put_32(buf, size);
|
||||
sc_buf_put_data(buf, str, size + sc_buf_8bit_len('\0'));
|
||||
sc_buf_put_raw(buf, str, size + sc_buf_8bit_len('\0'));
|
||||
}
|
||||
|
||||
void sc_buf_put_as_str(struct sc_buf *buf, const char *fmt, ...)
|
||||
void sc_buf_put_fmt(struct sc_buf *buf, const char *fmt, ...)
|
||||
{
|
||||
int rc;
|
||||
uint32_t tmp;
|
||||
va_list args;
|
||||
void *mem = (char *) sc_buf_write_buf(buf) + sc_buf_32bit_len(0);
|
||||
uint32_t pos = sc_buf_get_write_pos(buf);
|
||||
@ -473,7 +419,8 @@ void sc_buf_put_as_str(struct sc_buf *buf, const char *fmt, ...)
|
||||
return;
|
||||
}
|
||||
|
||||
sc_buf_set_32_at(buf, pos, rc);
|
||||
tmp = sc_swap32(rc);
|
||||
sc_buf_set_data(buf, pos, &tmp, sizeof(tmp));
|
||||
sc_buf_mark_write(buf, rc + sc_buf_32bit_len(0) + sc_buf_8bit_len('\0'));
|
||||
}
|
||||
|
||||
@ -492,14 +439,14 @@ void *sc_buf_get_blob(struct sc_buf *buf, uint32_t len)
|
||||
void sc_buf_put_blob(struct sc_buf *buf, const void *ptr, uint32_t len)
|
||||
{
|
||||
sc_buf_put_32(buf, len);
|
||||
sc_buf_put_data(buf, ptr, len);
|
||||
sc_buf_put_raw(buf, ptr, len);
|
||||
}
|
||||
|
||||
void sc_buf_move(struct sc_buf *dest, struct sc_buf *src)
|
||||
{
|
||||
uint32_t size = sy_buf_min(sc_buf_quota(dest), sc_buf_count(src));
|
||||
uint32_t size = sy_buf_min(sc_buf_quota(dest), sc_buf_size(src));
|
||||
|
||||
sc_buf_put_data(dest, &src->mem[sc_buf_get_read_pos(src)], size);
|
||||
sc_buf_put_raw(dest, &src->mem[sc_buf_get_read_pos(src)], size);
|
||||
src->read_pos += size;
|
||||
}
|
||||
|
||||
|
@ -42,11 +42,19 @@ struct sc_buf
|
||||
bool oom;
|
||||
};
|
||||
|
||||
/**
|
||||
* If you want to log or abort on out of memory, put your error function here.
|
||||
* It will be called with printf like error msg.
|
||||
*
|
||||
* my_on_oom(const char* fmt, ...);
|
||||
*/
|
||||
#define sc_buf_on_error(...)
|
||||
|
||||
#define sc_buf_malloc malloc
|
||||
#define sc_buf_realloc realloc
|
||||
#define sc_buf_free free
|
||||
|
||||
void sc_buf_init(struct sc_buf *buf, uint32_t cap);
|
||||
int sc_buf_init(struct sc_buf *buf, uint32_t cap);
|
||||
void sc_buf_term(struct sc_buf *buf);
|
||||
|
||||
struct sc_buf sc_buf_wrap(void *data, uint32_t len, bool ref);
|
||||
@ -56,14 +64,12 @@ void sc_buf_limit(struct sc_buf *buf, uint32_t limit);
|
||||
void *sc_buf_at(struct sc_buf *buf, uint32_t pos);
|
||||
uint32_t sc_buf_cap(struct sc_buf *buf);
|
||||
|
||||
bool sc_buf_is_valid(struct sc_buf *buf);
|
||||
bool sc_buf_valid(struct sc_buf *buf);
|
||||
uint32_t sc_buf_quota(struct sc_buf *buf);
|
||||
uint32_t sc_buf_count(struct sc_buf *buf);
|
||||
uint32_t sc_buf_size(struct sc_buf *buf);
|
||||
void sc_buf_clear(struct sc_buf *buf);
|
||||
void sc_buf_compact(struct sc_buf *buf);
|
||||
|
||||
void sc_buf_memset(struct sc_buf *buf, int val, uint32_t offset, uint32_t len);
|
||||
|
||||
void sc_buf_mark_read(struct sc_buf *buf, uint32_t len);
|
||||
void sc_buf_mark_write(struct sc_buf *buf, uint32_t len);
|
||||
|
||||
@ -81,8 +87,9 @@ uint32_t sc_buf_peek_data(struct sc_buf *buf, uint32_t offset, void *dest,
|
||||
uint32_t len);
|
||||
uint32_t sc_buf_set_data(struct sc_buf *buf, uint32_t offset, const void *src,
|
||||
uint32_t len);
|
||||
void sc_buf_get_data(struct sc_buf *buf, void *dest, uint32_t len);
|
||||
void sc_buf_put_data(struct sc_buf *buf, const void *ptr, uint32_t len);
|
||||
|
||||
void sc_buf_get_raw(struct sc_buf *buf, void *dest, uint32_t len);
|
||||
void sc_buf_put_raw(struct sc_buf *buf, const void *ptr, uint32_t len);
|
||||
|
||||
bool sc_buf_get_bool(struct sc_buf *buf);
|
||||
void sc_buf_put_bool(struct sc_buf *buf, bool val);
|
||||
@ -93,26 +100,18 @@ void sc_buf_put_8(struct sc_buf *buf, uint8_t byte);
|
||||
uint16_t sc_buf_get_16(struct sc_buf *buf);
|
||||
void sc_buf_put_16(struct sc_buf *buf, uint16_t val);
|
||||
|
||||
uint32_t sc_buf_peek_32_at(struct sc_buf *buf, uint32_t pos);
|
||||
uint32_t sc_buf_peek_32(struct sc_buf *buf);
|
||||
uint32_t sc_buf_get_32(struct sc_buf *buf);
|
||||
void sc_buf_set_32_at(struct sc_buf *buf, uint32_t pos, uint32_t val);
|
||||
void sc_buf_set_32(struct sc_buf *buf, uint32_t val);
|
||||
void sc_buf_put_32(struct sc_buf *buf, uint32_t val);
|
||||
|
||||
uint64_t sc_buf_peek_64_at(struct sc_buf *buf, uint32_t pos);
|
||||
uint64_t sc_buf_get_64(struct sc_buf *buf);
|
||||
void sc_buf_set_64_at(struct sc_buf *buf, uint32_t pos, uint64_t val);
|
||||
void sc_buf_put_64(struct sc_buf *buf, uint64_t val);
|
||||
|
||||
double sc_buf_get_double(struct sc_buf *buf);
|
||||
void sc_buf_put_double(struct sc_buf *buf, double val);
|
||||
|
||||
|
||||
uint32_t sc_buf_peek_strlen(struct sc_buf *buf);
|
||||
const char *sc_buf_get_str(struct sc_buf *buf);
|
||||
void sc_buf_put_str(struct sc_buf *buf, const char *str);
|
||||
void sc_buf_put_as_str(struct sc_buf *buf, const char *fmt, ...);
|
||||
void sc_buf_put_fmt(struct sc_buf *buf, const char *fmt, ...);
|
||||
|
||||
void sc_buf_put_blob(struct sc_buf *buf, const void *ptr, uint32_t len);
|
||||
void *sc_buf_get_blob(struct sc_buf *buf, uint32_t len);
|
||||
|
@ -50,7 +50,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -105,71 +105,81 @@ int sc_cond_init(struct sc_cond *cond)
|
||||
|
||||
cond->mtx = mut;
|
||||
|
||||
// May fail on OOM
|
||||
rc = pthread_mutexattr_init(&attr);
|
||||
if (rc != 0) {
|
||||
sc_cond_on_error("pthread_mutexattr_init : errno(%d) \n", rc);
|
||||
return rc;
|
||||
sc_cond_on_error("pthread_mutexattr_init : %s \n", strerror(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This won't fail as long as we pass correct params.
|
||||
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
|
||||
assert(rc == 0);
|
||||
|
||||
// May fail on OOM
|
||||
rc = pthread_mutex_init(&cond->mtx, &attr);
|
||||
if (rc != 0) {
|
||||
sc_cond_on_error("pthread_mutex_init : errno(%d) \n", rc);
|
||||
sc_cond_on_error("pthread_mutex_init : %s ", strerror(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This won't fail as long as we pass correct param.
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
|
||||
return pthread_cond_init(&cond->cond, NULL);
|
||||
rc = pthread_cond_init(&cond->cond, NULL);
|
||||
if (rc != 0) {
|
||||
sc_cond_on_error("pthread_cond_init : %s ", strerror(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sc_cond_term(struct sc_cond *cond)
|
||||
{
|
||||
int rc;
|
||||
int rv, rc = 0;
|
||||
|
||||
rc = pthread_mutex_destroy(&cond->mtx);
|
||||
rc |= pthread_cond_destroy(&cond->cond);
|
||||
rv = pthread_mutex_destroy(&cond->mtx);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
sc_cond_on_error("pthread_mutex_destroy : %s ", strerror(rv));
|
||||
}
|
||||
|
||||
rv = pthread_cond_destroy(&cond->cond);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
sc_cond_on_error("pthread_cond_destroy : %s ", strerror(rv));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sc_cond_finish(struct sc_cond *cond, void *var)
|
||||
{
|
||||
int rc, rv;
|
||||
int rc;
|
||||
|
||||
rv = pthread_mutex_lock(&cond->mtx);
|
||||
assert(rv == 0);
|
||||
pthread_mutex_lock(&cond->mtx);
|
||||
|
||||
cond->data = var;
|
||||
cond->done = true;
|
||||
|
||||
rc = pthread_cond_signal(&cond->cond);
|
||||
if (rc != 0) {
|
||||
sc_cond_on_error("pthread_cond_signal : errno(%d) \n", rc);
|
||||
sc_cond_on_error("pthread_cond_signal : %s ", strerror(rc));
|
||||
}
|
||||
rv = pthread_mutex_unlock(&cond->mtx);
|
||||
assert(rv == 0);
|
||||
|
||||
pthread_mutex_unlock(&cond->mtx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sc_cond_sync(struct sc_cond *cond, void **data)
|
||||
{
|
||||
int rc, rv;
|
||||
int rc;
|
||||
|
||||
rv = pthread_mutex_lock(&cond->mtx);
|
||||
assert(rv == 0);
|
||||
pthread_mutex_lock(&cond->mtx);
|
||||
|
||||
while (cond->done == false) {
|
||||
rc = pthread_cond_wait(&cond->cond, &cond->mtx);
|
||||
if (rc != 0) {
|
||||
sc_cond_on_error("pthread_mutex_init : errno(%d) \n", rc);
|
||||
sc_cond_on_error("pthread_mutex_init : %s ", strerror(rc));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -182,8 +192,7 @@ int sc_cond_sync(struct sc_cond *cond, void **data)
|
||||
cond->done = false;
|
||||
|
||||
out:
|
||||
rv = pthread_mutex_unlock(&cond->mtx);
|
||||
assert(rv == 0);
|
||||
pthread_mutex_unlock(&cond->mtx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -50,7 +50,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -45,8 +45,8 @@ struct sc_heap
|
||||
};
|
||||
|
||||
/**
|
||||
* If you want to log or abort on errors like out of memory,
|
||||
* put your error function here. It will be called with printf like error msg.
|
||||
* If you want to log or abort on out of memory, put your error function here.
|
||||
* It will be called with printf like error msg.
|
||||
*
|
||||
* my_on_error(const char* fmt, ...);
|
||||
*/
|
||||
|
@ -40,7 +40,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -39,7 +39,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -51,7 +51,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -101,7 +101,7 @@ int sc_log_mutex_init(struct sc_log_mutex *mtx)
|
||||
|
||||
rc = pthread_mutexattr_init(&attr);
|
||||
if (rc != 0) {
|
||||
sc_log_on_error("pthread_mutexattr_init : errcode(%d) ", rc);
|
||||
sc_log_on_error("pthread_mutexattr_init : %s ", strerror(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ int sc_log_mutex_init(struct sc_log_mutex *mtx)
|
||||
|
||||
rc = pthread_mutex_init(&mtx->mtx, &attr);
|
||||
if (rc != 0) {
|
||||
sc_log_on_error("pthread_mutex_init : errcode(%d) ", rc);
|
||||
sc_log_on_error("pthread_mutex_init : %s ", strerror(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@ int sc_log_mutex_term(struct sc_log_mutex *mtx)
|
||||
|
||||
rc = pthread_mutex_destroy(&mtx->mtx);
|
||||
if (rc != 0) {
|
||||
sc_log_on_error("pthread_mutex_destroy : errcode(%d) ", rc);
|
||||
sc_log_on_error("pthread_mutex_destroy : %s ", strerror(rc));
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -131,18 +131,12 @@ int sc_log_mutex_term(struct sc_log_mutex *mtx)
|
||||
|
||||
void sc_log_mutex_lock(struct sc_log_mutex *mtx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pthread_mutex_lock(&mtx->mtx);
|
||||
assert(rc == 0);
|
||||
pthread_mutex_lock(&mtx->mtx);
|
||||
}
|
||||
|
||||
void sc_log_mutex_unlock(struct sc_log_mutex *mtx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pthread_mutex_unlock(&mtx->mtx);
|
||||
assert(rc == 0);
|
||||
pthread_mutex_unlock(&mtx->mtx);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -174,14 +168,21 @@ int sc_log_init(void)
|
||||
|
||||
int sc_log_term(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc = 0, rv;
|
||||
|
||||
if (sc_log.fp) {
|
||||
rc = fclose(sc_log.fp);
|
||||
assert(rc == 0);
|
||||
rv = fclose(sc_log.fp);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
sc_log_on_error("fclose() : %s ", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
rv = sc_log_mutex_term(&sc_log.mtx);
|
||||
if (rv == -1) {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
sc_log_mutex_term(&sc_log.mtx);
|
||||
sc_log = (struct sc_log){0};
|
||||
|
||||
return rc;
|
||||
@ -220,14 +221,17 @@ int sc_log_set_stdout(bool enable)
|
||||
|
||||
int sc_log_set_file(const char *prev_file, const char *current_file)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc = 0, rv;
|
||||
long size;
|
||||
FILE *fp = NULL;
|
||||
|
||||
sc_log_mutex_lock(&sc_log.mtx);
|
||||
|
||||
if (sc_log.fp != NULL) {
|
||||
rc = fclose(sc_log.fp);
|
||||
rv = fclose(sc_log.fp);
|
||||
if (rv != 0) {
|
||||
sc_log_on_error("fclose() : %s ", strerror(errno));
|
||||
}
|
||||
sc_log.fp = NULL;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ const static struct sc_log_level_pair
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* If you want to log or abort on errors like mutex init which is not supposed
|
||||
* If you want to log or abort on errors like 'mutex init' which is not supposed
|
||||
* to fail ever(?), put your error function here. It will be called with printf
|
||||
* like error msg.
|
||||
*
|
||||
|
@ -52,7 +52,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -1,14 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.5.1)
|
||||
project(sc_pipe C)
|
||||
project(sc_mmap C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
add_executable(sc_pipe pipe_example.c sc_pipe.h sc_pipe.c)
|
||||
add_executable(sc_mmap mmap_example.c sc_mmap.h sc_mmap.c)
|
||||
|
||||
if (NOT CMAKE_C_COMPILER_ID MATCHES "MSVC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -pedantic -Werror -D_GNU_SOURCE")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -pedantic -Werror -D_GNU_SOURCE -pthread")
|
||||
endif ()
|
||||
|
||||
|
||||
@ -21,9 +21,9 @@ include(CheckCCompilerFlag)
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_executable(${PROJECT_NAME}_test pipe_test.c sc_pipe.c)
|
||||
add_executable(${PROJECT_NAME}_test mmap_test.c sc_mmap.c)
|
||||
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_SIZE_MAX=4000ul)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_SIZE_MAX=1400000ul)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
||||
@ -32,9 +32,10 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_HAVE_WRAP)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fno-builtin)
|
||||
target_link_options(${PROJECT_NAME}_test PRIVATE
|
||||
-Wl,--wrap=pipe,--wrap=close)
|
||||
-Wl,--wrap=pthread_mmapattr_init)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang" OR
|
||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
@ -51,7 +52,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
8
memory-map/mmap_example.c
Normal file
8
memory-map/mmap_example.c
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
8
memory-map/mmap_test.c
Normal file
8
memory-map/mmap_test.c
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
3
memory-map/sc_mmap.c
Normal file
3
memory-map/sc_mmap.c
Normal file
@ -0,0 +1,3 @@
|
||||
#include "sc_mmap.h"
|
||||
|
||||
|
14
memory-map/sc_mmap.h
Normal file
14
memory-map/sc_mmap.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef SC_MMAP_H
|
||||
#define SC_MMAP_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
enum sc_mmap_flag
|
||||
{
|
||||
SC_MMAP_READ,
|
||||
SC_MMAP_WRITE,
|
||||
SC_MMAP_EXEC
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -52,7 +52,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Ozan Tezcan
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
109
pipe/pipe_test.c
109
pipe/pipe_test.c
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Ozan Tezcan
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sc_pipe.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef SC_HAVE_WRAP
|
||||
#include <unistd.h>
|
||||
|
||||
bool fail_close = false;
|
||||
int __real_close(int fd);
|
||||
int __wrap_close(int fd)
|
||||
{
|
||||
if (fail_close) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return __real_close(fd);
|
||||
}
|
||||
|
||||
bool fail_pipe = false;
|
||||
int __real_pipe(int __pipedes[2]);
|
||||
int __wrap_pipe(int __pipedes[2])
|
||||
{
|
||||
if (fail_pipe) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return __real_pipe(__pipedes);
|
||||
}
|
||||
|
||||
void fail_test()
|
||||
{
|
||||
struct sc_pipe pipe;
|
||||
fail_pipe = true;
|
||||
assert(sc_pipe_init(&pipe, 0) != 0);
|
||||
fail_pipe = false;
|
||||
assert(sc_pipe_init(&pipe, 0) == 0);
|
||||
fail_close = true;
|
||||
assert(sc_pipe_term(&pipe) == -1);
|
||||
fail_close = false;
|
||||
assert(sc_pipe_term(&pipe) == 0);
|
||||
}
|
||||
|
||||
#else
|
||||
void fail_test()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void test1(void)
|
||||
{
|
||||
char buf[5];
|
||||
struct sc_pipe pipe;
|
||||
|
||||
sc_pipe_init(&pipe, 0);
|
||||
sc_pipe_write(&pipe, "test", 5);
|
||||
sc_pipe_read(&pipe, buf, 5);
|
||||
sc_pipe_term(&pipe);
|
||||
|
||||
assert(strcmp("test", buf) == 0);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
WSADATA data;
|
||||
|
||||
int rc = WSAStartup(MAKEWORD(2, 2), &data);
|
||||
assert(rc == 0);
|
||||
assert(LOBYTE(data.wVersion) == 2 &&
|
||||
HIBYTE(data.wVersion) == 2);
|
||||
#endif
|
||||
test1();
|
||||
fail_test();
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
rc = WSACleanup();
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
214
pipe/sc_pipe.c
214
pipe/sc_pipe.c
@ -1,214 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Ozan Tezcan
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sc_pipe.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
int sc_pipe_init(struct sc_pipe *p)
|
||||
{
|
||||
SOCKET listener;
|
||||
int rc;
|
||||
struct sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
int val = 1;
|
||||
BOOL nodelay = 1;
|
||||
|
||||
p->w = INVALID_SOCKET;
|
||||
p->r = INVALID_SOCKET;
|
||||
|
||||
/* Create listening socket. */
|
||||
listener = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listener == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
rc = setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &val,
|
||||
sizeof(val));
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
addr.sin_port = 0;
|
||||
|
||||
rc = bind(listener, (const struct sockaddr *) &addr, sizeof(addr));
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
rc = getsockname(listener, (struct sockaddr *) &addr, &addrlen);
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
rc = listen(listener, 1);
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
p->w = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listener == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
rc = setsockopt(p->w, IPPROTO_TCP, TCP_NODELAY, (char *) &nodelay,
|
||||
sizeof(nodelay));
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
rc = connect(p->w, (struct sockaddr *) &addr, sizeof(addr));
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
p->r = accept(listener, (struct sockaddr *) &addr, &addrlen);
|
||||
if (p->r == INVALID_SOCKET) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
closesocket(listener);
|
||||
|
||||
return 0;
|
||||
|
||||
wsafail:
|
||||
sc_pipe_on_error("sc_pipe_init() : %d ", WSAGetLastError())
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sc_pipe_term(struct sc_pipe *p)
|
||||
{
|
||||
int rc = 0, rv;
|
||||
|
||||
rv = closesocket(p->r);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
sc_pipe_on_error("closesocket() : errcode(%d) ", WSAGetLastError());
|
||||
}
|
||||
|
||||
rv = closesocket(p->w);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
sc_pipe_on_error("closesocket() : errcode(%d) ", WSAGetLastError());
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sc_pipe_write(struct sc_pipe *p, void *data, int len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = send(p->w, data, len, 0);
|
||||
if (rc == SOCKET_ERROR || rc != len) {
|
||||
sc_pipe_on_error("send() : errcode(%d) ", WSAGetLastError());
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sc_pipe_read(struct sc_pipe *p, void *data, int len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = recv(p->r, (char *) data, len, 0);
|
||||
if (rc == SOCKET_ERROR || rc != len) {
|
||||
sc_pipe_on_error("recv() : errcode(%d) ", WSAGetLastError());
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
int sc_pipe_init(struct sc_pipe *p, int type)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pipe(p->fds);
|
||||
if (rc == -1) {
|
||||
sc_pipe_on_error("pipe() : %d ", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->type = type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sc_pipe_term(struct sc_pipe *nfd)
|
||||
{
|
||||
int rc = 0, rv;
|
||||
|
||||
rv = close(nfd->fds[0]);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
sc_pipe_on_error("pipe() : %d ", errno);
|
||||
}
|
||||
|
||||
rv = close(nfd->fds[1]);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
sc_pipe_on_error("pipe() : %d ", errno);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sc_pipe_write(struct sc_pipe *nfd, void *data, int len)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
n = write(nfd->fds[1], data, len);
|
||||
if (n != len) {
|
||||
sc_pipe_on_error("pipe() : %d ", errno);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int sc_pipe_read(struct sc_pipe *nfd, void *data, int len)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
n = read(nfd->fds[0], data, len);
|
||||
if (n != len) {
|
||||
sc_pipe_on_error("pipe() : %d ", errno);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Ozan Tezcan
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef SC_PIPE_H
|
||||
#define SC_PIPE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
|
||||
struct sc_pipe
|
||||
{
|
||||
int type;
|
||||
SOCKET r;
|
||||
SOCKET w;
|
||||
};
|
||||
|
||||
#else
|
||||
struct sc_pipe
|
||||
{
|
||||
int type;
|
||||
int fds[2];
|
||||
};
|
||||
#endif
|
||||
|
||||
int sc_pipe_init(struct sc_pipe *pipe, int type);
|
||||
int sc_pipe_term(struct sc_pipe *pipe);
|
||||
int sc_pipe_write(struct sc_pipe *pipe, void *data, int len);
|
||||
int sc_pipe_read(struct sc_pipe *pipe, void *data, int len);
|
||||
|
||||
/**
|
||||
* If you want to log or abort on errors like mutex init,
|
||||
* put your error function here. It will be called with printf like error msg.
|
||||
*
|
||||
* my_on_error(const char* fmt, ...);
|
||||
*/
|
||||
#define sc_pipe_on_error(...)
|
||||
|
||||
#endif
|
@ -53,7 +53,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
97
socket/CMakeLists.txt
Normal file
97
socket/CMakeLists.txt
Normal file
@ -0,0 +1,97 @@
|
||||
cmake_minimum_required(VERSION 3.5.1)
|
||||
project(sc_socket C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
add_executable(sc_socket sock_example.c sc_sock.h sc_sock.c)
|
||||
|
||||
if (NOT CMAKE_C_COMPILER_ID MATCHES "MSVC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -pedantic -pthread -Werror -D_GNU_SOURCE")
|
||||
endif ()
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# --------------------- Test Configuration Start ---------------------------- #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
include(CTest)
|
||||
include(CheckCCompilerFlag)
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_executable(${PROJECT_NAME}_test sock_test.c sc_sock.c)
|
||||
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_SIZE_MAX=1400000ul)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fno-omit-frame-pointer)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_HAVE_WRAP)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fno-builtin)
|
||||
target_link_options(${PROJECT_NAME}_test PRIVATE -Wl,--wrap=pipe,--wrap=close)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang" OR
|
||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fno-omit-frame-pointer)
|
||||
|
||||
if (SANITIZER)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fsanitize=${SANITIZER})
|
||||
target_link_options(${PROJECT_NAME}_test PRIVATE -fsanitize=${SANITIZER})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
-E env CTEST_OUTPUT_ON_FAILURE=1
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIG>
|
||||
--overwrite MemoryCheckCommandOptions=${MEMORYCHECK_COMMAND_OPTIONS}
|
||||
--verbose -T memcheck WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
add_custom_target(check_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
-E env CTEST_OUTPUT_ON_FAILURE=1
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIG> --verbose
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# ----------------------- - Code Coverage Start ----------------------------- #
|
||||
|
||||
if (${CMAKE_BUILD_TYPE} MATCHES "Coverage")
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE --coverage)
|
||||
target_link_libraries(${PROJECT_NAME}_test gcov)
|
||||
else()
|
||||
message(FATAL_ERROR "Only GCC is supported for coverage")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
add_custom_target(coverage_${PROJECT_NAME})
|
||||
add_custom_command(
|
||||
TARGET coverage_${PROJECT_NAME}
|
||||
COMMAND lcov --capture --directory ..
|
||||
--output-file coverage.info --rc lcov_branch_coverage=1
|
||||
COMMAND lcov --remove coverage.info '/usr/*' '*example*' '*test*'
|
||||
--output-file coverage.info --rc lcov_branch_coverage=1
|
||||
COMMAND lcov --list coverage.info --rc lcov_branch_coverage=1
|
||||
)
|
||||
|
||||
add_dependencies(coverage_${PROJECT_NAME} check_${PROJECT_NAME})
|
||||
|
||||
# -------------------------- Code Coverage End ------------------------------ #
|
||||
|
||||
|
||||
# ----------------------- Test Configuration End ---------------------------- #
|
||||
|
1439
socket/sc_sock.c
Normal file
1439
socket/sc_sock.c
Normal file
File diff suppressed because it is too large
Load Diff
166
socket/sc_sock.h
Normal file
166
socket/sc_sock.h
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Ozan Tezcan
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef SC_SOCK_H
|
||||
#define SC_SOCK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <Ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
typedef SOCKET sc_sock_int;
|
||||
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
typedef int sc_sock_int;
|
||||
#endif
|
||||
|
||||
#define SC_SOCK_BUF_SIZE 8192
|
||||
|
||||
|
||||
enum sc_sock_rc
|
||||
{
|
||||
SC_SOCK_WANT_READ = -4,
|
||||
SC_SOCK_WANT_WRITE = -2,
|
||||
SC_SOCK_ERROR = -1,
|
||||
SC_SOCK_OK = 0
|
||||
};
|
||||
|
||||
enum sc_sock_ev
|
||||
{
|
||||
SC_SOCK_NONE = 0u,
|
||||
SC_SOCK_READ = 1u,
|
||||
SC_SOCK_WRITE = 2u,
|
||||
};
|
||||
|
||||
enum sc_sock_family
|
||||
{
|
||||
SC_SOCK_INET = AF_INET,
|
||||
SC_SOCK_INET6 = AF_INET6,
|
||||
SC_SOCK_UNIX = AF_UNIX
|
||||
};
|
||||
|
||||
struct sc_sock_fd
|
||||
{
|
||||
sc_sock_int fd;
|
||||
enum sc_sock_ev op;
|
||||
int type;
|
||||
int index;
|
||||
};
|
||||
|
||||
struct sc_sock
|
||||
{
|
||||
struct sc_sock_fd fdt;
|
||||
bool blocking;
|
||||
int family;
|
||||
char err[128];
|
||||
};
|
||||
|
||||
void sc_sock_init(struct sc_sock* sock, int type, bool blocking, int family);
|
||||
int sc_sock_term(struct sc_sock* sock);
|
||||
|
||||
int sc_sock_listen(struct sc_sock* sock, const char* host, const char* port);
|
||||
int sc_sock_accept(struct sc_sock* sock, struct sc_sock* in);
|
||||
|
||||
int sc_sock_connect(struct sc_sock* sock, const char* dest_addr,
|
||||
const char* dest_port, const char* source_addr,
|
||||
const char* source_port);
|
||||
|
||||
int sc_sock_finish_connect(struct sc_sock* sock);
|
||||
|
||||
int sc_sock_send(struct sc_sock* sock, char* buf, int len);
|
||||
int sc_sock_recv(struct sc_sock* sock, char* buf, int len);
|
||||
|
||||
const char* sc_sock_error(struct sc_sock* sock);
|
||||
void sc_sock_print(struct sc_sock* sock, char* buf, int len);
|
||||
|
||||
|
||||
struct sc_sock_pipe
|
||||
{
|
||||
struct sc_sock_fd fdt;
|
||||
sc_sock_int fds[2];
|
||||
};
|
||||
|
||||
int sc_sock_pipe_init(struct sc_sock_pipe* pipe, int type);
|
||||
int sc_sock_pipe_term(struct sc_sock_pipe* pipe);
|
||||
int sc_sock_pipe_write(struct sc_sock_pipe* pipe, void* data, int len);
|
||||
int sc_sock_pipe_read(struct sc_sock_pipe* pipe, void* data, int len);
|
||||
|
||||
#define sc_sock_on_error(...)
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/epoll.h>
|
||||
|
||||
|
||||
struct sc_sock_poll
|
||||
{
|
||||
int fds;
|
||||
size_t count;
|
||||
size_t cap;
|
||||
struct epoll_event* events;
|
||||
};
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__APPLE__)
|
||||
#include <sys/event.h>
|
||||
|
||||
struct sc_sock_poll
|
||||
{
|
||||
int fds;
|
||||
size_t count;
|
||||
size_t cap;
|
||||
struct kevent* events;
|
||||
};
|
||||
#else
|
||||
#if !defined(_WIN32)
|
||||
#include <sys/poll.h>
|
||||
#endif
|
||||
|
||||
struct sc_sock_poll
|
||||
{
|
||||
size_t count;
|
||||
size_t cap;
|
||||
void** data;
|
||||
struct pollfd* events;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
int sc_sock_poll_init(struct sc_sock_poll* poll);
|
||||
int sc_sock_poll_term(struct sc_sock_poll* poll);
|
||||
|
||||
int sc_sock_poll_add(struct sc_sock_poll* poll, struct sc_sock_fd* fdt,
|
||||
enum sc_sock_ev events, void* data);
|
||||
int sc_sock_poll_del(struct sc_sock_poll* poll, struct sc_sock_fd* fdt,
|
||||
enum sc_sock_ev events, void* data);
|
||||
|
||||
void* sc_sock_poll_data(struct sc_sock_poll* poll, size_t i);
|
||||
uint32_t sc_sock_poll_event(struct sc_sock_poll* poll, size_t i);
|
||||
int sc_sock_poll_wait(struct sc_sock_poll* poll, int timeout);
|
||||
|
||||
#endif
|
5
socket/sock_example.c
Normal file
5
socket/sock_example.c
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
586
socket/sock_test.c
Normal file
586
socket/sock_test.c
Normal file
@ -0,0 +1,586 @@
|
||||
|
||||
#include "sc_sock.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <synchapi.h>
|
||||
#define sleep(n) (Sleep(n * 1000))
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
struct sc_thread
|
||||
{
|
||||
HANDLE id;
|
||||
void* (*fn)(void*);
|
||||
void* arg;
|
||||
void* ret;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct sc_thread
|
||||
{
|
||||
pthread_t id;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
void sc_thread_init(struct sc_thread* thread);
|
||||
int sc_thread_term(struct sc_thread* thread);
|
||||
int sc_thread_start(struct sc_thread* thread, void* (*fn)(void*), void* arg);
|
||||
int sc_thread_stop(struct sc_thread* thread, void** ret);
|
||||
|
||||
void sc_thread_init(struct sc_thread* thread)
|
||||
{
|
||||
thread->id = 0;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <process.h>
|
||||
|
||||
unsigned int __stdcall sc_thread_fn(void* arg)
|
||||
{
|
||||
struct sc_thread* thread = arg;
|
||||
|
||||
thread->ret = thread->fn(thread->arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sc_thread_start(struct sc_thread* thread, void* (*fn)(void*), void* arg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
thread->fn = fn;
|
||||
thread->arg = arg;
|
||||
|
||||
thread->id =
|
||||
(HANDLE)_beginthreadex(NULL, 0, sc_thread_fn, thread, 0, NULL);
|
||||
rc = thread->id == 0 ? -1 : 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sc_thread_stop(struct sc_thread* thread, void** ret)
|
||||
{
|
||||
int rc = 0;
|
||||
DWORD rv;
|
||||
BOOL brc;
|
||||
|
||||
if (thread->id == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = WaitForSingleObject(thread->id, INFINITE);
|
||||
if (rv == WAIT_FAILED) {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
brc = CloseHandle(thread->id);
|
||||
if (!brc) {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
thread->id = 0;
|
||||
if (ret != NULL) {
|
||||
*ret = thread->ret;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
|
||||
int sc_thread_start(struct sc_thread* thread, void* (*fn)(void*), void* arg)
|
||||
{
|
||||
int rc;
|
||||
pthread_attr_t hndl;
|
||||
|
||||
rc = pthread_attr_init(&hndl);
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This may only fail with EINVAL.
|
||||
pthread_attr_setdetachstate(&hndl, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
rc = pthread_create(&thread->id, &hndl, fn, arg);
|
||||
|
||||
// This may only fail with EINVAL.
|
||||
pthread_attr_destroy(&hndl);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sc_thread_stop(struct sc_thread* thread, void** ret)
|
||||
{
|
||||
int rc;
|
||||
void* val;
|
||||
|
||||
if (thread->id == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = pthread_join(thread->id, &val);
|
||||
thread->id = 0;
|
||||
|
||||
if (ret != NULL) {
|
||||
*ret = val;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int sc_thread_term(struct sc_thread* thread)
|
||||
{
|
||||
return sc_thread_stop(thread, NULL);
|
||||
}
|
||||
|
||||
void* server_ip4(void* arg)
|
||||
{
|
||||
char buf[5];
|
||||
char tmp[128];
|
||||
struct sc_sock sock, accepted;
|
||||
|
||||
sc_sock_init(&sock, 0, true, AF_INET);
|
||||
assert(sc_sock_listen(&sock, "127.0.0.1", "8004") == 0);
|
||||
sc_sock_print(&sock, tmp, sizeof(tmp));
|
||||
assert(strcmp(tmp, "Local(127.0.0.1:8004), Remote() ") == 0);
|
||||
|
||||
assert(sc_sock_accept(&sock, &accepted) == 0);
|
||||
assert(sc_sock_recv(&accepted, buf, 5) == 5);
|
||||
assert(strcmp("test", buf) == 0);
|
||||
|
||||
assert(sc_sock_term(&sock) == 0);
|
||||
assert(sc_sock_term(&accepted) == 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* client_ip4(void* arg)
|
||||
{
|
||||
int rc;
|
||||
char tmp[128];
|
||||
struct sc_sock sock;
|
||||
|
||||
sc_sock_init(&sock, 0, true, AF_INET);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
rc = sc_sock_connect(&sock, "127.0.0.1", "8004", NULL, NULL);
|
||||
if (rc == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
assert(rc == 0);
|
||||
sc_sock_print(&sock, tmp, sizeof(tmp));
|
||||
assert(sc_sock_send(&sock, "test", 5) == 5);
|
||||
assert(sc_sock_term(&sock) == 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void test_ip4()
|
||||
{
|
||||
struct sc_thread thread1;
|
||||
struct sc_thread thread2;
|
||||
|
||||
sc_thread_init(&thread1);
|
||||
sc_thread_init(&thread2);
|
||||
|
||||
assert(sc_thread_start(&thread1, server_ip4, NULL) == 0);
|
||||
assert(sc_thread_start(&thread2, client_ip4, NULL) == 0);
|
||||
|
||||
assert(sc_thread_term(&thread1) == 0);
|
||||
assert(sc_thread_term(&thread2) == 0);
|
||||
}
|
||||
|
||||
void* server_ip6(void* arg)
|
||||
{
|
||||
char buf[5];
|
||||
char tmp[128];
|
||||
struct sc_sock sock, accepted;
|
||||
|
||||
sc_sock_init(&sock, 0, true, AF_INET6);
|
||||
assert(sc_sock_listen(&sock, "::1", "8006") == 0);
|
||||
sc_sock_print(&sock, tmp, sizeof(tmp));
|
||||
assert(strcmp(tmp, "Local(::1:8006), Remote() ") == 0);
|
||||
assert(sc_sock_accept(&sock, &accepted) == 0);
|
||||
assert(sc_sock_recv(&accepted, buf, 5) == 5);
|
||||
assert(strcmp("test", buf) == 0);
|
||||
|
||||
assert(sc_sock_term(&sock) == 0);
|
||||
assert(sc_sock_term(&accepted) == 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* client_ip6(void* arg)
|
||||
{
|
||||
int rc;
|
||||
struct sc_sock sock;
|
||||
|
||||
sc_sock_init(&sock, 0, true, AF_INET6);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
rc = sc_sock_connect(&sock, "::1", "8006", NULL, NULL);
|
||||
if (rc == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
assert(rc == 0);
|
||||
assert(sc_sock_send(&sock, "test", 5) == 5);
|
||||
|
||||
assert(sc_sock_term(&sock) == 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void test_ip6()
|
||||
{
|
||||
struct sc_thread thread1;
|
||||
struct sc_thread thread2;
|
||||
|
||||
sc_thread_init(&thread1);
|
||||
sc_thread_init(&thread2);
|
||||
|
||||
assert(sc_thread_start(&thread1, server_ip6, NULL) == 0);
|
||||
assert(sc_thread_start(&thread2, client_ip6, NULL) == 0);
|
||||
|
||||
assert(sc_thread_term(&thread1) == 0);
|
||||
assert(sc_thread_term(&thread2) == 0);
|
||||
}
|
||||
|
||||
void* server_unix(void* arg)
|
||||
{
|
||||
char buf[5];
|
||||
char tmp[128];
|
||||
struct sc_sock sock, accepted;
|
||||
|
||||
sc_sock_init(&sock, 0, true, AF_UNIX);
|
||||
assert(sc_sock_listen(&sock, "x.sock", NULL) == 0);
|
||||
sc_sock_print(&sock, tmp, sizeof(tmp));
|
||||
assert(strcmp(tmp, "Local(x.sock), Remote() ") == 0);
|
||||
int rc = sc_sock_accept(&sock, &accepted);
|
||||
if (rc != 0) {
|
||||
printf("error(%d) : %s\n", errno, sock.err);
|
||||
}
|
||||
|
||||
assert(rc == 0);
|
||||
assert(sc_sock_recv(&accepted, buf, 5) == 5);
|
||||
assert(strcmp("test", buf) == 0);
|
||||
|
||||
assert(sc_sock_term(&sock) == 0);
|
||||
assert(sc_sock_term(&accepted) == 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* client_unix(void* arg)
|
||||
{
|
||||
int rc;
|
||||
struct sc_sock sock;
|
||||
|
||||
sleep(3);
|
||||
sc_sock_init(&sock, 0, true, AF_UNIX);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
printf("Will connect to x.sock \n");
|
||||
rc = sc_sock_connect(&sock, "x.sock", NULL, NULL, NULL);
|
||||
if (rc == 0) {
|
||||
printf("Connected to x.sock \n");
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Failed to connect to x.sock \n");
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
assert(rc == 0);
|
||||
assert(sc_sock_send(&sock, "test", 5) == 5);
|
||||
assert(sc_sock_term(&sock) == 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void test_unix()
|
||||
{
|
||||
struct sc_thread thread1;
|
||||
struct sc_thread thread2;
|
||||
|
||||
sc_thread_init(&thread1);
|
||||
sc_thread_init(&thread2);
|
||||
|
||||
assert(sc_thread_start(&thread1, server_unix, NULL) == 0);
|
||||
assert(sc_thread_start(&thread2, client_unix, NULL) == 0);
|
||||
|
||||
assert(sc_thread_term(&thread1) == 0);
|
||||
assert(sc_thread_term(&thread2) == 0);
|
||||
}
|
||||
|
||||
|
||||
void test1()
|
||||
{
|
||||
char tmp[5];
|
||||
struct sc_sock sock;
|
||||
|
||||
sc_sock_init(&sock, 0, false, AF_INET);
|
||||
assert(sc_sock_connect(&sock, "3127.0.0.1", "2131", NULL, NULL) != 0);
|
||||
assert(sc_sock_finish_connect(&sock) != 0);
|
||||
assert(sc_sock_connect(&sock, "3127.0.0.1", "2131", "127.90.1.1", "50") !=
|
||||
0);
|
||||
assert(sc_sock_finish_connect(&sock) != 0);
|
||||
assert(sc_sock_send(&sock, "test", 5) == -1);
|
||||
assert(sc_sock_recv(&sock, tmp, sizeof(tmp)) == -1);
|
||||
assert(sc_sock_connect(&sock, "131s::1", "2131", "::1", "50") != 0);
|
||||
assert(sc_sock_finish_connect(&sock) != 0);
|
||||
assert(sc_sock_connect(&sock, "d::1", "2131", "dsad", "50") != 0);
|
||||
assert(sc_sock_finish_connect(&sock) != 0);
|
||||
assert(sc_sock_connect(&sock, "dsadas", "2131", "::1", "50") != 0);
|
||||
|
||||
sc_sock_term(&sock);
|
||||
}
|
||||
|
||||
void test_pipe(void)
|
||||
{
|
||||
char buf[5];
|
||||
struct sc_sock_pipe pipe;
|
||||
|
||||
sc_sock_pipe_init(&pipe, 0);
|
||||
sc_sock_pipe_write(&pipe, "test", 5);
|
||||
sc_sock_pipe_read(&pipe, buf, 5);
|
||||
sc_sock_pipe_term(&pipe);
|
||||
|
||||
assert(strcmp("test", buf) == 0);
|
||||
}
|
||||
|
||||
#ifdef SC_HAVE_WRAP
|
||||
#include <unistd.h>
|
||||
|
||||
bool fail_close = false;
|
||||
int __real_close(int fd);
|
||||
int __wrap_close(int fd)
|
||||
{
|
||||
if (fail_close) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return __real_close(fd);
|
||||
}
|
||||
|
||||
bool fail_pipe = false;
|
||||
int __real_pipe(int __pipedes[2]);
|
||||
int __wrap_pipe(int __pipedes[2])
|
||||
{
|
||||
if (fail_pipe) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return __real_pipe(__pipedes);
|
||||
}
|
||||
|
||||
void pipe_fail_test()
|
||||
{
|
||||
struct sc_sock_pipe pipe;
|
||||
fail_pipe = true;
|
||||
assert(sc_sock_pipe_init(&pipe, 0) != 0);
|
||||
fail_pipe = false;
|
||||
assert(sc_sock_pipe_init(&pipe, 0) == 0);
|
||||
fail_close = true;
|
||||
assert(sc_sock_pipe_term(&pipe) == -1);
|
||||
fail_close = false;
|
||||
assert(sc_sock_pipe_term(&pipe) == 0);
|
||||
}
|
||||
|
||||
#else
|
||||
void pipe_fail_test()
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void* server(void* arg)
|
||||
{
|
||||
int write_triggered = 2;
|
||||
int rc, received = 0;
|
||||
struct sc_sock server;
|
||||
struct sc_sock accepted;
|
||||
struct sc_sock_poll poll;
|
||||
|
||||
|
||||
assert(sc_sock_poll_init(&poll) == 0);
|
||||
assert(sc_sock_poll_term(&poll) == 0);
|
||||
assert(sc_sock_poll_init(&poll) == 0);
|
||||
|
||||
sc_sock_init(&server, 0, true, SC_SOCK_INET);
|
||||
rc = sc_sock_listen(&server, "127.0.0.1", "11000");
|
||||
assert(rc == 0);
|
||||
|
||||
rc = sc_sock_poll_add(&poll, &server.fdt, SC_SOCK_READ, &server);
|
||||
assert(rc == 0);
|
||||
bool done = false;
|
||||
|
||||
while (!done) {
|
||||
int count = sc_sock_poll_wait(&poll, -1);
|
||||
assert(rc != -1);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int ev = sc_sock_poll_event(&poll, i);
|
||||
struct sc_sock* sock = sc_sock_poll_data(&poll, i);
|
||||
|
||||
if (ev == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sock == &server) {
|
||||
if (ev & SC_SOCK_READ) {
|
||||
rc = sc_sock_accept(&server, &accepted);
|
||||
printf("accepted \n");
|
||||
|
||||
assert(rc == 0);
|
||||
assert(sc_sock_poll_add(&poll, &accepted.fdt,
|
||||
SC_SOCK_WRITE,
|
||||
&accepted) == 0);
|
||||
}
|
||||
|
||||
if (ev & SC_SOCK_WRITE) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ev & SC_SOCK_READ) {
|
||||
char buf[8];
|
||||
rc = sc_sock_recv(&accepted, buf, sizeof(buf));
|
||||
if (rc == 8) {
|
||||
assert(strcmp(buf, "dataxxx") == 0);
|
||||
received++;
|
||||
}
|
||||
else if (rc == 0 || rc < 0) {
|
||||
rc = sc_sock_poll_del(&poll, &accepted.fdt,
|
||||
SC_SOCK_READ |
|
||||
SC_SOCK_WRITE,
|
||||
&accepted);
|
||||
assert(rc == 0);
|
||||
rc = sc_sock_term(&accepted);
|
||||
assert(rc == 0);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (write_triggered > 0) {
|
||||
write_triggered--;
|
||||
if (write_triggered == 0) {
|
||||
rc = sc_sock_poll_del(&poll, &accepted.fdt, SC_SOCK_WRITE, &accepted);
|
||||
assert(rc == 0);
|
||||
}
|
||||
else {
|
||||
rc = sc_sock_poll_add(&poll, &accepted.fdt, SC_SOCK_READ, &accepted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(write_triggered == 0);
|
||||
assert(sc_sock_term(&server) == 0);
|
||||
assert(sc_sock_poll_term(&poll) == 0);
|
||||
|
||||
printf("Received :%d \n", received);
|
||||
assert(received == 10000);
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* client(void* arg)
|
||||
{
|
||||
int rc;
|
||||
struct sc_sock sock;
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
sc_sock_init(&sock, 0, true, SC_SOCK_INET);
|
||||
|
||||
rc = sc_sock_connect(&sock, "127.0.0.1", "11000", NULL, NULL);
|
||||
if (rc != 0) {
|
||||
assert(sc_sock_term(&sock) == 0);
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 10000; j++) {
|
||||
rc = sc_sock_send(&sock, "dataxxx", 8);
|
||||
assert(rc == 8);
|
||||
}
|
||||
|
||||
rc = sc_sock_term(&sock);
|
||||
assert(rc == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void test_poll()
|
||||
{
|
||||
struct sc_thread thread1;
|
||||
struct sc_thread thread2;
|
||||
|
||||
sc_thread_init(&thread1);
|
||||
sc_thread_init(&thread2);
|
||||
|
||||
assert(sc_thread_start(&thread1, server, NULL) == 0);
|
||||
assert(sc_thread_start(&thread2, client, NULL) == 0);
|
||||
|
||||
assert(sc_thread_term(&thread1) == 0);
|
||||
assert(sc_thread_term(&thread2) == 0);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
WSADATA data;
|
||||
|
||||
int rc = WSAStartup(MAKEWORD(2, 2), &data);
|
||||
assert(rc == 0);
|
||||
assert(LOBYTE(data.wVersion) == 2 && HIBYTE(data.wVersion) == 2);
|
||||
#endif
|
||||
|
||||
test1();
|
||||
test_ip4();
|
||||
|
||||
#if defined(__x86_64__)
|
||||
test_ip6();
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
test_unix();
|
||||
#endif
|
||||
test_pipe();
|
||||
pipe_fail_test();
|
||||
test_poll();
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
rc = WSACleanup();
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
@ -51,7 +51,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -202,7 +202,7 @@ bool sc_str_append(char **str, const char *param)
|
||||
size_t alloc = sc_str_bytes(meta->len + len);
|
||||
|
||||
if (alloc > SC_SIZE_MAX || (meta = sc_str_realloc(meta, alloc)) == NULL) {
|
||||
sc_str_on_error("Out of memory. alloc(%zu). ", alloc);
|
||||
sc_str_on_error("Out of memory. alloc(%zu bytes). ", alloc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -39,7 +39,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -73,7 +73,7 @@ uint64_t sc_time_ns()
|
||||
rc = clock_gettime(CLOCK_REALTIME, &ts);
|
||||
assert(rc == 0);
|
||||
|
||||
return ts.tv_sec * 1000000000 + ts.tv_nsec;
|
||||
return ts.tv_sec * (uint64_t)1000000000 + ts.tv_nsec;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -127,21 +127,27 @@ uint64_t sc_time_mono_ns()
|
||||
#endif
|
||||
}
|
||||
|
||||
void sc_time_sleep(uint64_t milliseconds)
|
||||
int sc_time_sleep(uint64_t milliseconds)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
Sleep(milliseconds);
|
||||
return 0;
|
||||
#else
|
||||
int rc;
|
||||
struct timespec t;
|
||||
struct timespec t, rem;
|
||||
|
||||
t.tv_sec = milliseconds / 1000;
|
||||
t.tv_nsec = (milliseconds % 1000) * 1000000;
|
||||
rem.tv_sec = milliseconds / 1000;
|
||||
rem.tv_nsec = (milliseconds % 1000) * 1000000;
|
||||
|
||||
do {
|
||||
rc = nanosleep(&t, NULL);
|
||||
t = rem;
|
||||
rc = nanosleep(&t, &rem);
|
||||
} while (rc != 0 && errno != EINTR);
|
||||
|
||||
assert(rc == 0);
|
||||
if (rc != 0) {
|
||||
sc_time_on_error("nanosleep() : %s ", strerror(errno));
|
||||
}
|
||||
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
@ -26,6 +26,14 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* If you want to log or abort on errors, put your error function here.
|
||||
* It will be called with printf like error msg.
|
||||
*
|
||||
* my_on_error(const char* fmt, ...);
|
||||
*/
|
||||
#define sc_time_on_error(...)
|
||||
|
||||
/**
|
||||
* This is not a monotonic timer.
|
||||
* @return Current timestamp in milliseconds.
|
||||
@ -52,7 +60,8 @@ uint64_t sc_time_mono_ns();
|
||||
|
||||
/**
|
||||
* @param milliseconds Milliseconds to sleep.
|
||||
* @return '0' on success, negative number on failure.
|
||||
*/
|
||||
void sc_time_sleep(uint64_t milliseconds);
|
||||
int sc_time_sleep(uint64_t milliseconds);
|
||||
|
||||
#endif
|
||||
|
@ -52,7 +52,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
@ -49,7 +49,7 @@ add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all --show-reachable=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
|
Loading…
x
Reference in New Issue
Block a user