Portability (#5)

socket
This commit is contained in:
Tezc 2020-11-25 09:25:38 +03:00 committed by GitHub
parent c461dbec07
commit 1bde3abd9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 2496 additions and 627 deletions

View File

@ -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}

View File

@ -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}

View File

@ -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;
}

View File

@ -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(...)

View File

@ -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}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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}

View File

@ -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;
}

View File

@ -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}

View File

@ -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}

View File

@ -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, ...);
*/

View File

@ -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}

View File

@ -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}

View File

@ -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}

View File

@ -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;
}

View File

@ -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.
*

View File

@ -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}

View File

@ -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}

View File

@ -0,0 +1,8 @@
int main(int argc, char *argv[])
{
return 0;
}

8
memory-map/mmap_test.c Normal file
View File

@ -0,0 +1,8 @@
int main(int argc, char *argv[])
{
return 0;
}

3
memory-map/sc_mmap.c Normal file
View File

@ -0,0 +1,3 @@
#include "sc_mmap.h"

14
memory-map/sc_mmap.h Normal file
View 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

View File

@ -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}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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
View 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

File diff suppressed because it is too large Load Diff

166
socket/sc_sock.h Normal file
View 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
View File

@ -0,0 +1,5 @@
int main()
{
return 0;
}

586
socket/sock_test.c Normal file
View 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;
}

View File

@ -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}

View File

@ -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;
}

View File

@ -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}

View File

@ -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}

View File

@ -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
}

View File

@ -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

View File

@ -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}

View File

@ -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}