From c2af5db86ea9acdae282cf24caa13f23be7c6ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 4 Feb 2014 01:37:27 +0100 Subject: [PATCH 01/55] Add an unsigned int/string pair type, modelled on the value string of wireshark --- include/ucore/val_str.h | 37 +++++++++++++++++++++ src/val_str.c | 47 +++++++++++++++++++++++++++ test/test_runner.c | 4 ++- test/test_val_str.c | 72 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 include/ucore/val_str.h create mode 100644 src/val_str.c create mode 100644 test/test_val_str.c diff --git a/include/ucore/val_str.h b/include/ucore/val_str.h new file mode 100644 index 0000000..834f7cb --- /dev/null +++ b/include/ucore/val_str.h @@ -0,0 +1,37 @@ +#ifndef UC_VAL_STR_H_ +#define UC_VAL_STR_H_ + +#include + +struct UCValStr { + unsigned int val; + const char *str; +}; + +#define UC_VS_ENTRY(constant) {constant, #constant} +#define UC_VS_TERMINATOR {-1, NULL} + +/** Find @val in @array. + * The last .str in @array must be a NULL pointer. + * (does a linear search) + * + * @param val value to find + * @param array array to search + * @return the string associated with @val or NULL + */ +const char *uc_vs_search(unsigned int val, const struct UCValStr *array); + +/** Find @val in @array. + * @array must be sorted on val and must not be empty + * (does a binary search) + * + * @param val value to find + * @param array array to search + * @return the string associated with @val or NULL + */ +const char *uc_vs_bsearch(unsigned int val, + const struct UCValStr *array, + size_t array_len); + + +#endif diff --git a/src/val_str.c b/src/val_str.c new file mode 100644 index 0000000..40e0cd7 --- /dev/null +++ b/src/val_str.c @@ -0,0 +1,47 @@ +#include +#include +#include "ucore/val_str.h" +#include "ucore/saturating_math.h" + + +const char *uc_vs_search(unsigned int val, const struct UCValStr *array) +{ + const char *found = NULL; + + while (array->str) { + if (array->val == val) { + found = array->str; + break; + } + array++; + } + + return found; +} + +const char *uc_vs_bsearch(unsigned int val, + const struct UCValStr *array, + size_t array_len) +{ + size_t i = array_len; + const struct UCValStr *start = array; + + while (i != 0) { + const struct UCValStr *curr; + curr = start + i / 2; + + if (curr->val == val) { + return curr->str; + } + + if (curr->val < val) { + start = curr + 1; + i--; + } + + i = i / 2; + } + + return NULL; +} + diff --git a/test/test_runner.c b/test/test_runner.c index 92c0eb0..fab9686 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -29,6 +29,7 @@ extern Suite *ratelimit_suite(void); extern Suite *htable_suite(void); extern Suite *heapsort_suite(void); extern Suite *dstr_suite(void); +extern Suite *val_str_suite(void); static suite_func suites[] = { bitvec_suite, @@ -52,7 +53,8 @@ static suite_func suites[] = { clock_suite, threadqueue_suite, heapsort_suite, - dstr_suite + dstr_suite, + val_str_suite }; int diff --git a/test/test_val_str.c b/test/test_val_str.c new file mode 100644 index 0000000..96006cf --- /dev/null +++ b/test/test_val_str.c @@ -0,0 +1,72 @@ +#include +#include + + +START_TEST (test_val_str_search) + struct UCValStr vals[] = { + UC_VS_ENTRY(1), + UC_VS_ENTRY(5), + UC_VS_ENTRY(0), + UC_VS_TERMINATOR + }; + ck_assert_str_eq(uc_vs_search(0 , vals) , "0"); + ck_assert_str_eq(uc_vs_search(1 , vals) , "1"); + ck_assert_str_eq(uc_vs_search(5 , vals) , "5"); + + fail_if(uc_vs_search(10, vals) != NULL); +END_TEST + +START_TEST (test_val_str_bsearch_odd) + struct UCValStr vals[] = { + UC_VS_ENTRY(1), + UC_VS_ENTRY(2), + UC_VS_ENTRY(10), + UC_VS_ENTRY(100), + UC_VS_ENTRY(101), + }; + const size_t len = sizeof vals/sizeof vals[0]; + + ck_assert_str_eq(uc_vs_bsearch(1 , vals , len) , "1"); + ck_assert_str_eq(uc_vs_bsearch(2 , vals , len) , "2"); + ck_assert_str_eq(uc_vs_bsearch(10 , vals , len) , "10"); + ck_assert_str_eq(uc_vs_bsearch(100 , vals , len) , "100"); + ck_assert_str_eq(uc_vs_bsearch(101 , vals , len) , "101"); + + fail_if(uc_vs_bsearch(0 , vals , len) != NULL); + fail_if(uc_vs_bsearch(55 , vals , len) != NULL); + fail_if(uc_vs_bsearch(999 , vals , len) != NULL); +END_TEST + +START_TEST (test_val_str_bsearch_even) + struct UCValStr vals[] = { + UC_VS_ENTRY(1), + UC_VS_ENTRY(2), + UC_VS_ENTRY(10), + UC_VS_ENTRY(101), + }; + const size_t len = sizeof vals/sizeof vals[0]; + + ck_assert_str_eq(uc_vs_bsearch(1 , vals , len) , "1"); + ck_assert_str_eq(uc_vs_bsearch(2 , vals , len) , "2"); + ck_assert_str_eq(uc_vs_bsearch(10 , vals , len) , "10"); + ck_assert_str_eq(uc_vs_bsearch(101 , vals , len) , "101"); + + fail_if(uc_vs_bsearch(0 , vals , len) != NULL); + fail_if(uc_vs_bsearch(55 , vals , len) != NULL); + fail_if(uc_vs_bsearch(999 , vals , len) != NULL); +END_TEST + + +Suite *val_str_suite(void) +{ + Suite *s = suite_create("valstr"); + TCase *tc = tcase_create("valstr tests"); + tcase_add_test(tc, test_val_str_search); + tcase_add_test(tc, test_val_str_bsearch_odd); + tcase_add_test(tc, test_val_str_bsearch_even); + + suite_add_tcase(s, tc); + + return s; +} + From a1da276cf5c40ea77751315ddf5419d9608044b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 4 Feb 2014 01:45:02 +0100 Subject: [PATCH 02/55] cosmetic cleanup --- include/ucore/val_str.h | 4 ++-- src/val_str.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/ucore/val_str.h b/include/ucore/val_str.h index 834f7cb..eb7d056 100644 --- a/include/ucore/val_str.h +++ b/include/ucore/val_str.h @@ -30,8 +30,8 @@ const char *uc_vs_search(unsigned int val, const struct UCValStr *array); * @return the string associated with @val or NULL */ const char *uc_vs_bsearch(unsigned int val, - const struct UCValStr *array, - size_t array_len); + const struct UCValStr *array, + size_t array_len); #endif diff --git a/src/val_str.c b/src/val_str.c index 40e0cd7..94659ad 100644 --- a/src/val_str.c +++ b/src/val_str.c @@ -20,26 +20,26 @@ const char *uc_vs_search(unsigned int val, const struct UCValStr *array) } const char *uc_vs_bsearch(unsigned int val, - const struct UCValStr *array, - size_t array_len) + const struct UCValStr *array, + size_t array_len) { size_t i = array_len; const struct UCValStr *start = array; while (i != 0) { const struct UCValStr *curr; - curr = start + i / 2; + curr = &start[i / 2]; //middle if (curr->val == val) { return curr->str; } if (curr->val < val) { - start = curr + 1; + start = curr + 1; //right half i--; } - i = i / 2; + i = i / 2; } return NULL; From 3119016172f180abf5e73e3abc10a808e0d953b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 4 Feb 2014 15:15:17 +0100 Subject: [PATCH 03/55] Rename the value string functions to be a bit mroe sensible --- include/ucore/val_str.h | 5 +++-- src/val_str.c | 4 ++-- test/test_val_str.c | 38 +++++++++++++++++++------------------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/include/ucore/val_str.h b/include/ucore/val_str.h index eb7d056..860053e 100644 --- a/include/ucore/val_str.h +++ b/include/ucore/val_str.h @@ -8,6 +8,7 @@ struct UCValStr { const char *str; }; +/** Helper macro to define an entry in a UCValStr array */ #define UC_VS_ENTRY(constant) {constant, #constant} #define UC_VS_TERMINATOR {-1, NULL} @@ -19,7 +20,7 @@ struct UCValStr { * @param array array to search * @return the string associated with @val or NULL */ -const char *uc_vs_search(unsigned int val, const struct UCValStr *array); +const char *uc_val_2_str(unsigned int val, const struct UCValStr *array); /** Find @val in @array. * @array must be sorted on val and must not be empty @@ -29,7 +30,7 @@ const char *uc_vs_search(unsigned int val, const struct UCValStr *array); * @param array array to search * @return the string associated with @val or NULL */ -const char *uc_vs_bsearch(unsigned int val, +const char *uc_val_2_str_bs(unsigned int val, const struct UCValStr *array, size_t array_len); diff --git a/src/val_str.c b/src/val_str.c index 94659ad..dba9d7e 100644 --- a/src/val_str.c +++ b/src/val_str.c @@ -4,7 +4,7 @@ #include "ucore/saturating_math.h" -const char *uc_vs_search(unsigned int val, const struct UCValStr *array) +const char *uc_val_2_str(unsigned int val, const struct UCValStr *array) { const char *found = NULL; @@ -19,7 +19,7 @@ const char *uc_vs_search(unsigned int val, const struct UCValStr *array) return found; } -const char *uc_vs_bsearch(unsigned int val, +const char *uc_val_2_str_bs(unsigned int val, const struct UCValStr *array, size_t array_len) { diff --git a/test/test_val_str.c b/test/test_val_str.c index 96006cf..d025da8 100644 --- a/test/test_val_str.c +++ b/test/test_val_str.c @@ -9,11 +9,11 @@ START_TEST (test_val_str_search) UC_VS_ENTRY(0), UC_VS_TERMINATOR }; - ck_assert_str_eq(uc_vs_search(0 , vals) , "0"); - ck_assert_str_eq(uc_vs_search(1 , vals) , "1"); - ck_assert_str_eq(uc_vs_search(5 , vals) , "5"); + ck_assert_str_eq(uc_val_2_str(0 , vals) , "0"); + ck_assert_str_eq(uc_val_2_str(1 , vals) , "1"); + ck_assert_str_eq(uc_val_2_str(5 , vals) , "5"); - fail_if(uc_vs_search(10, vals) != NULL); + fail_if(uc_val_2_str(10, vals) != NULL); END_TEST START_TEST (test_val_str_bsearch_odd) @@ -26,15 +26,15 @@ START_TEST (test_val_str_bsearch_odd) }; const size_t len = sizeof vals/sizeof vals[0]; - ck_assert_str_eq(uc_vs_bsearch(1 , vals , len) , "1"); - ck_assert_str_eq(uc_vs_bsearch(2 , vals , len) , "2"); - ck_assert_str_eq(uc_vs_bsearch(10 , vals , len) , "10"); - ck_assert_str_eq(uc_vs_bsearch(100 , vals , len) , "100"); - ck_assert_str_eq(uc_vs_bsearch(101 , vals , len) , "101"); + ck_assert_str_eq(uc_val_2_str_bs(1 , vals , len) , "1"); + ck_assert_str_eq(uc_val_2_str_bs(2 , vals , len) , "2"); + ck_assert_str_eq(uc_val_2_str_bs(10 , vals , len) , "10"); + ck_assert_str_eq(uc_val_2_str_bs(100 , vals , len) , "100"); + ck_assert_str_eq(uc_val_2_str_bs(101 , vals , len) , "101"); - fail_if(uc_vs_bsearch(0 , vals , len) != NULL); - fail_if(uc_vs_bsearch(55 , vals , len) != NULL); - fail_if(uc_vs_bsearch(999 , vals , len) != NULL); + fail_if(uc_val_2_str_bs(0 , vals , len) != NULL); + fail_if(uc_val_2_str_bs(55 , vals , len) != NULL); + fail_if(uc_val_2_str_bs(999 , vals , len) != NULL); END_TEST START_TEST (test_val_str_bsearch_even) @@ -46,14 +46,14 @@ START_TEST (test_val_str_bsearch_even) }; const size_t len = sizeof vals/sizeof vals[0]; - ck_assert_str_eq(uc_vs_bsearch(1 , vals , len) , "1"); - ck_assert_str_eq(uc_vs_bsearch(2 , vals , len) , "2"); - ck_assert_str_eq(uc_vs_bsearch(10 , vals , len) , "10"); - ck_assert_str_eq(uc_vs_bsearch(101 , vals , len) , "101"); + ck_assert_str_eq(uc_val_2_str_bs(1 , vals , len) , "1"); + ck_assert_str_eq(uc_val_2_str_bs(2 , vals , len) , "2"); + ck_assert_str_eq(uc_val_2_str_bs(10 , vals , len) , "10"); + ck_assert_str_eq(uc_val_2_str_bs(101 , vals , len) , "101"); - fail_if(uc_vs_bsearch(0 , vals , len) != NULL); - fail_if(uc_vs_bsearch(55 , vals , len) != NULL); - fail_if(uc_vs_bsearch(999 , vals , len) != NULL); + fail_if(uc_val_2_str_bs(0 , vals , len) != NULL); + fail_if(uc_val_2_str_bs(55 , vals , len) != NULL); + fail_if(uc_val_2_str_bs(999 , vals , len) != NULL); END_TEST From 0c3fc0f31d3cbb5c247f32438044eed06a8d698b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 4 Feb 2014 20:51:47 +0100 Subject: [PATCH 04/55] Add a string/string mapper struct --- include/ucore/val_str.h | 21 ++++++++++++++++++--- src/val_str.c | 23 ++++++++++++++++++++--- test/test_val_str.c | 15 +++++++++++++++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/include/ucore/val_str.h b/include/ucore/val_str.h index 860053e..9e180b5 100644 --- a/include/ucore/val_str.h +++ b/include/ucore/val_str.h @@ -8,17 +8,23 @@ struct UCValStr { const char *str; }; +struct UCStrStr { + const char *val; + const char *str; +}; + /** Helper macro to define an entry in a UCValStr array */ #define UC_VS_ENTRY(constant) {constant, #constant} #define UC_VS_TERMINATOR {-1, NULL} +#define UC_SS_TERMINATOR {NULL, NULL} -/** Find @val in @array. - * The last .str in @array must be a NULL pointer. +/** find @val in @array. + * the last .str in @array must be a null pointer. * (does a linear search) * * @param val value to find * @param array array to search - * @return the string associated with @val or NULL + * @return the string associated with @val or null */ const char *uc_val_2_str(unsigned int val, const struct UCValStr *array); @@ -34,5 +40,14 @@ const char *uc_val_2_str_bs(unsigned int val, const struct UCValStr *array, size_t array_len); +/** find @val in @array. + * the last .val in @array must be a null pointer. + * (does a linear search) + * + * @param val value to find, using strcmp + * @param array array to search + * @return the string associated with @val or null + */ +const char *uc_str_2_str(const char *val, const struct UCStrStr *array); #endif diff --git a/src/val_str.c b/src/val_str.c index dba9d7e..4ff0fe0 100644 --- a/src/val_str.c +++ b/src/val_str.c @@ -1,4 +1,4 @@ -#include +#include #include #include "ucore/val_str.h" #include "ucore/saturating_math.h" @@ -25,13 +25,15 @@ const char *uc_val_2_str_bs(unsigned int val, { size_t i = array_len; const struct UCValStr *start = array; + const char *found = NULL; while (i != 0) { const struct UCValStr *curr; curr = &start[i / 2]; //middle if (curr->val == val) { - return curr->str; + found = curr->str; + break; } if (curr->val < val) { @@ -42,6 +44,21 @@ const char *uc_val_2_str_bs(unsigned int val, i = i / 2; } - return NULL; + return found; +} + +const char *uc_str_2_str(const char *val, const struct UCStrStr *array) +{ + const char *found = NULL; + + while (array->val) { + if (strcmp(val, array->val) == 0) { + found = array->str; + break; + } + array++; + } + + return found; } diff --git a/test/test_val_str.c b/test/test_val_str.c index d025da8..fb104bd 100644 --- a/test/test_val_str.c +++ b/test/test_val_str.c @@ -56,6 +56,19 @@ START_TEST (test_val_str_bsearch_even) fail_if(uc_val_2_str_bs(999 , vals , len) != NULL); END_TEST +START_TEST (test_str_str_search) + struct UCStrStr vals[] = { + {"1", "A"}, + {"2", "B"}, + {"3", "C"}, + UC_SS_TERMINATOR + }; + ck_assert_str_eq(uc_str_2_str("1" , vals) , "A"); + ck_assert_str_eq(uc_str_2_str("2" , vals) , "B"); + ck_assert_str_eq(uc_str_2_str("3" , vals) , "C"); + + fail_if(uc_str_2_str("10", vals) != NULL); +END_TEST Suite *val_str_suite(void) { @@ -65,6 +78,8 @@ Suite *val_str_suite(void) tcase_add_test(tc, test_val_str_bsearch_odd); tcase_add_test(tc, test_val_str_bsearch_even); + tcase_add_test(tc, test_str_str_search); + suite_add_tcase(s, tc); return s; From c3a900ea533b4fe77ad02b8484f86392d52facc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 2 Mar 2014 03:59:18 +0100 Subject: [PATCH 05/55] Change library suffix from _debug to D for debug build. And no suffix for a release build. --- SConstruct | 4 +++- src/SConscript | 4 ++-- test/SConscript | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/SConstruct b/SConstruct index 4a4e817..2afb480 100644 --- a/SConstruct +++ b/SConstruct @@ -74,6 +74,7 @@ assertions = GetOption('assertions') stack_protection = GetOption('stack_protection') test_xml = GetOption('test_xml') prefix = GetOption('prefix') +lib_suffix = '' if not (build_type in ['debug', 'release']): print "Error: expected 'debug' or 'release', found: " + build_type Exit(1) @@ -111,6 +112,7 @@ if build_type == 'release': env.Append(CPPDEFINES = ['NDEBUG']) elif build_type == 'debug': + lib_suffix = 'D' env.Append(CPPDEFINES = ['DEBUG']) if stack_protection: @@ -132,7 +134,7 @@ if stack_protection: subst_info['@build_host@'] = platform.node() -Export('env', 'build_type', 'prefix', 'version_info', 'test_xml', 'subst_info') +Export('env', 'build_type', 'prefix', 'lib_suffix', 'version_info', 'test_xml', 'subst_info') #put all .sconsign files in one place env.SConsignFile() diff --git a/src/SConscript b/src/SConscript index c11d3ac..1367097 100644 --- a/src/SConscript +++ b/src/SConscript @@ -1,6 +1,6 @@ import os -Import('env', 'build_type', 'prefix', 'subst_info') +Import('env', 'build_type', 'prefix', 'lib_suffix', 'subst_info') ucore_env = env.Clone() @@ -13,7 +13,7 @@ sources = ucore_env.Glob('*.c') #print 'sources:', sources[len(sources)-2] #Build library -ucore_lib = ucore_env.StaticLibrary(target='ucore_' + build_type , source=sources) +ucore_lib = ucore_env.StaticLibrary(target='ucore' + lib_suffix , source=sources) #install targets ucore_env.Alias('install', diff --git a/test/SConscript b/test/SConscript index 074db11..911dc9d 100644 --- a/test/SConscript +++ b/test/SConscript @@ -1,10 +1,10 @@ import platform -Import('env', 'build_type', 'prefix', 'version_info', 'test_xml') +Import('env', 'build_type', 'prefix', 'lib_suffix', 'version_info', 'test_xml') test_env = env.Clone() test_env.Append(LIBPATH = ['#build/src']); -test_env.Append(LIBS = ['ucore_' + build_type, 'check']) +test_env.Append(LIBS = ['ucore' + lib_suffix, 'check']) system = platform.system() From 8fca5333d92fafed558b31650d72a26ceeab2f97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 2 Mar 2014 06:00:05 +0100 Subject: [PATCH 06/55] Implement generalied IOMux implementation operations Fix serious bug in iomix_timers_run --- src/iomux_epoll.c | 16 ++++++++++------ src/iomux_impl.c | 20 +++++++++++--------- src/iomux_impl.h | 36 +++++++++++++++++++++--------------- src/iomux_select.c | 16 ++++++++++------ 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/src/iomux_epoll.c b/src/iomux_epoll.c index 7dfc343..586b5f0 100644 --- a/src/iomux_epoll.c +++ b/src/iomux_epoll.c @@ -213,6 +213,14 @@ static void iomux_epoll_delete(struct IOMux *mux) mux->instance = NULL; } } + +static const struct IOMuxOps epoll_ops = { + .run_impl = iomux_epoll_run, + .delete_impl = iomux_epoll_delete, + .register_fd_impl = iomux_epoll_register_fd, + .unregister_fd_impl = iomux_epoll_unregister_fd, + .update_events_impl = iomux_epoll_update_events, +}; int iomux_epoll_init(struct IOMux *mux) { @@ -226,12 +234,8 @@ int iomux_epoll_init(struct IOMux *mux) return errno; } - mux->instance = mux_epoll; - mux->run_impl = iomux_epoll_run; - mux->delete_impl = iomux_epoll_delete; - mux->register_fd_impl = iomux_epoll_register_fd; - mux->unregister_fd_impl = iomux_epoll_unregister_fd; - mux->update_events_impl = iomux_epoll_update_events; + mux->instance = mux_epoll; + mux->ops = epoll_ops; return 0; } diff --git a/src/iomux_impl.c b/src/iomux_impl.c index d4b14ed..a1e52c2 100644 --- a/src/iomux_impl.c +++ b/src/iomux_impl.c @@ -48,7 +48,7 @@ struct IOMux *iomux_create_ex(enum IOMUX_TYPE type, struct UCoreClock *uclock) void iomux_delete(struct IOMux *mux) { - mux->delete_impl(mux); + mux->ops.delete_impl(mux); memset(mux, 0xfa, sizeof *mux); free(mux); } @@ -74,17 +74,18 @@ static int iomux_run_timers(struct IOMux *mux, struct timeval *timeout) struct timeval now; mux->uclock->now(mux->uclock, &now); future_to_interval(&first_timer, &now, timeout); - /* TRACEF("now %d %d future %d %d interval %d %d\n", mux->now.tv_sec, mux->now.tv_usec, + /*TRACEF("now %d %d future %d %d interval %d %d\n", now.tv_sec, now.tv_usec, first_timer.tv_sec, first_timer.tv_usec, - timeout.tv_sec, timeout.tv_usec); - */ + timeout->tv_sec, timeout->tv_usec); + */ + assert(timeout->tv_sec >= 0); assert(timeout->tv_usec >= 0); return 1; } - return 9; + return 0; } int iomux_run(struct IOMux *mux) @@ -95,12 +96,13 @@ int iomux_run(struct IOMux *mux) struct timeval *timeoutp; if (iomux_run_timers(mux, &timeout)) { + TRACEF("NULL\n"); timeoutp = &timeout; } else { timeoutp = NULL; } - rc = mux->run_impl(mux, timeoutp); + rc = mux->ops.run_impl(mux, timeoutp); if (rc < 0) return rc; @@ -128,7 +130,7 @@ int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd) assert(fd != NULL); assert(fd->callback != NULL); assert(fd->fd >= 0); - return mux->register_fd_impl(mux, fd); + return mux->ops.register_fd_impl(mux, fd); } int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd) @@ -136,7 +138,7 @@ int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd) assert(mux != NULL); assert(fd != NULL); assert(fd->fd >= 0); - return mux->unregister_fd_impl(mux, fd); + return mux->ops.unregister_fd_impl(mux, fd); } int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd, unsigned int what) @@ -148,7 +150,7 @@ int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd, unsigned int what assert(fd->fd >= 0); if (fd->what != what) { - mux->update_events_impl(mux, fd); + mux->ops.update_events_impl(mux, fd); } else { rc = 0; } diff --git a/src/iomux_impl.h b/src/iomux_impl.h index 6c5484a..31944cb 100644 --- a/src/iomux_impl.h +++ b/src/iomux_impl.h @@ -4,21 +4,7 @@ #include "ucore/iomux.h" #include "ucore/timers.h" /** struct for IOMux implementations */ -struct IOMux { - - /* TImer instance */ - struct UCTimers timers; - - /** - * Clock used for driving timers, and - * providing timeouts for the mux - */ - struct UCoreClock *uclock; - - - /* Used by mux implementations to hold their own data/instance */ - void *instance; - +struct IOMuxOps { /** Run one iteration of the mux. * The mux implementation must honor the timeout, if given. * The mux implementation must call iomux_timers_run after the @@ -39,6 +25,26 @@ struct IOMux { int (*unregister_fd_impl)(struct IOMux *mux, struct IOMuxFD *fd); /** Update an IOMuxFD (due to its events ('what') has changed*/ int (*update_events_impl)(struct IOMux *mux, struct IOMuxFD *fd); + +}; +struct IOMux { + + /* TImer instance */ + struct UCTimers timers; + + /** + * Clock used for driving timers, and + * providing timeouts for the mux + */ + struct UCoreClock *uclock; + + struct IOMuxOps ops; + + + /* Used by mux implementations to hold their own data/instance */ + void *instance; + + }; int iomux_select_init(struct IOMux *mux); diff --git a/src/iomux_select.c b/src/iomux_select.c index 40156de..f680d60 100644 --- a/src/iomux_select.c +++ b/src/iomux_select.c @@ -199,6 +199,14 @@ static void iomux_select_delete(struct IOMux *mux) mux->instance = NULL; } } + +static const struct IOMuxOps select_ops = { + .run_impl = iomux_select_run, + .delete_impl = iomux_select_delete, + .register_fd_impl = iomux_select_register_fd, + .unregister_fd_impl = iomux_select_unregister_fd, + .update_events_impl = iomux_select_update_events, +}; int iomux_select_init(struct IOMux *mux) { @@ -208,12 +216,8 @@ int iomux_select_init(struct IOMux *mux) mux_select->max_fd = -1; - mux->instance = mux_select; - mux->run_impl = iomux_select_run; - mux->delete_impl = iomux_select_delete; - mux->register_fd_impl = iomux_select_register_fd; - mux->unregister_fd_impl = iomux_select_unregister_fd; - mux->update_events_impl = iomux_select_update_events; + mux->instance = mux_select; + mux->ops = select_ops; return 0; } From 15a3cbb59afb59f3f511850f10fc893bfcbee49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 9 Mar 2014 23:54:48 +0100 Subject: [PATCH 07/55] Small refactoring of ratelimit code to make more sense --- include/ucore/rate_limit.h | 4 +- src/rate_limit.c | 81 +++++++++++++++++++++----------------- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/include/ucore/rate_limit.h b/include/ucore/rate_limit.h index 7d39755..367aae9 100644 --- a/include/ucore/rate_limit.h +++ b/include/ucore/rate_limit.h @@ -62,7 +62,7 @@ struct RateLimit { //money we have to "buy" tickets long funds; //time of the previos period - long last_ts; + long last_refill_ts; }; /** Static initializer for a struct RateLimit @@ -91,7 +91,7 @@ void uc_ratelimit_init(struct RateLimit *r, long tickets, long period); * Reset a RateLimit, filling up the tickets again. * * @param r RateLimit to reset - * @param current ts, if non-zero, re-sets the last_ts to the current_ts + * @param current ts, if non-zero, re-sets the last_refill_ts to the current_ts */ void uc_ratelimit_reset(struct RateLimit *r, long current_ts); diff --git a/src/rate_limit.c b/src/rate_limit.c index 14299fe..2facdc1 100644 --- a/src/rate_limit.c +++ b/src/rate_limit.c @@ -8,11 +8,12 @@ void uc_ratelimit_init(struct RateLimit *r, long tickets, long period) r->period = period; r->funds = 0; //we fill it on first _allow call - r->last_ts = -period; //-period ensures the first tick can start + r->last_refill_ts = -period; //-period ensures the first tick can start //at >= 0 and still refill the bicket assert(tickets > 0); assert(r->period > 0); + assert(r->period != LONG_MAX); } void uc_ratelimit_reset(struct RateLimit *r, long current_ts) @@ -20,54 +21,60 @@ void uc_ratelimit_reset(struct RateLimit *r, long current_ts) r->funds = r->period * r->tickets; if (current_ts) { - r->last_ts = current_ts; + r->last_refill_ts = current_ts; } } +static void uc_ratelimit_refill(struct RateLimit *r, long current_ts) +{ + + long diff_period; + //Find elapsed time + diff_period = current_ts - r->last_refill_ts; + + if (diff_period > r->period + 1) { + //help prevent overflow when calculating available_tickets below + diff_period = r->period + 1; + } else if (diff_period < 0) { + //time went backwards, skip this round + diff_period = 0; + } + + //Calculate the cost of tickets that became available + r->funds += diff_period * r->tickets; + + //throttle handing out tickets + if (r->funds > r->period * r->tickets) { + r->funds = r->period * r->tickets; + } + + //save this period. + r->last_refill_ts = current_ts; +} + int uc_ratelimit_allow(struct RateLimit *r, long current_ts) { int allowed; - long diff_period; - if (r->funds >= r->period) { - //we have enough + if (r->funds < r->period) { //not enough funds + + uc_ratelimit_refill(r, current_ts); + + //as we keep track of the last timestamp of refilling + //We don't need to refill when there is enough funds + } + + //If we have enough to buy atleast one ticket, we can allow + if (r->funds >= r->period) { r->funds -= r->period; allowed = 1; - } else { //refill - //Find elapsed time - diff_period = current_ts - r->last_ts; - - if (diff_period > r->period + 1) { - //help prevent overflow when calculating available_tickets below - diff_period = r->period + 1; - } else if (diff_period < 0) { - //time went backwards, skip this round - diff_period = 0; - } - - //Calculate the cost of tickets that became available - r->funds += diff_period * r->tickets; - - - //throttle handing out tickets - if (r->funds > r->period * r->tickets) { - r->funds = r->period * r->tickets; - } - - //If we have enough to buy atleast one ticket, we can allow - if (r->funds >= r->period) { - r->funds -= r->period; - allowed = 1; - } else { - //not enough to buy a ticket - allowed = 0; - } - - //save this period. - r->last_ts = current_ts; + } else { + //not enough to buy a ticket + allowed = 0; } + return allowed; } From 325c36435f99e5ae8e28112e08fc3f23530cd4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 10 Mar 2014 22:02:44 +0100 Subject: [PATCH 08/55] Tidy up whitespace --- src/iomux_impl.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/iomux_impl.h b/src/iomux_impl.h index 31944cb..794c738 100644 --- a/src/iomux_impl.h +++ b/src/iomux_impl.h @@ -27,8 +27,8 @@ struct IOMuxOps { int (*update_events_impl)(struct IOMux *mux, struct IOMuxFD *fd); }; -struct IOMux { +struct IOMux { /* TImer instance */ struct UCTimers timers; @@ -40,11 +40,8 @@ struct IOMux { struct IOMuxOps ops; - /* Used by mux implementations to hold their own data/instance */ void *instance; - - }; int iomux_select_init(struct IOMux *mux); From 1844735483165aa3850e9880211860d318df3f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 12 Mar 2014 19:18:47 +0100 Subject: [PATCH 09/55] Add -Werror=implicit-function-declaration to CFLAGS --- SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index 2afb480..d650a8b 100644 --- a/SConstruct +++ b/SConstruct @@ -95,7 +95,7 @@ if os.environ.has_key('CC'): env.AddMethod(InstallPerm) env.Append(CFLAGS = ['-std=gnu99','-Wall', '-Wextra', '-Wundef', '-Wcast-qual','-Wshadow' ,'-Wcast-align','-pipe', '-ggdb', '-pthread']) -env.Append(CFLAGS = ['-Wno-unused-parameter']) +env.Append(CFLAGS = ['-Wno-unused-parameter', '-Werror=implicit-function-declaration']) env.Append(LINKFLAGS = ['-O2', '-pthread']) env.Append(CPPDEFINES = ['_FILE_OFFSET_BITS=64']) env.Append(CPPPATH = ['#include']) From 62a7a6071294ef63604a632e3cdebcf84b7456df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 13 Mar 2014 23:04:14 +0100 Subject: [PATCH 10/55] Set errno to 0, for consistent results --- test/test_read_file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_read_file.c b/test/test_read_file.c index 5bef1f4..dcd8d68 100644 --- a/test/test_read_file.c +++ b/test/test_read_file.c @@ -13,6 +13,7 @@ START_TEST (test_read_file_non_existing_file) size_t len; int saved_errno; + errno = 0; content = uc_read_file("non existing file 123765", &len, 1000000000); saved_errno = errno; From 092074bbfca05d2063cb15e39f6bf4abcbdb8939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 13 Mar 2014 23:07:57 +0100 Subject: [PATCH 11/55] Fix read_file in case file size if > SSIZE_MAX --- src/read_file.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/read_file.c b/src/read_file.c index cf6c3f5..62f0d81 100644 --- a/src/read_file.c +++ b/src/read_file.c @@ -1,10 +1,11 @@ -#include -#include -#include -#include -#include -#include -#include "ucore/read_file.h" +#include +#include +#include +#include +#include +#include +#include +#include "ucore/read_file.h" #define CHUNK_SZ 1024 @@ -27,17 +28,21 @@ uc_read_file(const char *f, size_t *length, size_t max) } if ((statb.st_mode & S_IFMT) == S_IFREG) { - if ((size_t)statb.st_size > max) { + if (statb.st_size > (off_t)max) { errno = EMSGSIZE; goto out_close; } - alloc_sz = (size_t) statb.st_size + 1; // + 1 to avoid one realloc - s = malloc((size_t) alloc_sz + 1); //+1 for nul terminator + if (statb.st_size > SSIZE_MAX) { + //otherwise we cannot detect the return value of read() + alloc_sz = SSIZE_MAX; + } else { + alloc_sz = statb.st_size; + } } else { alloc_sz = CHUNK_SZ; - s = malloc(alloc_sz + 1); //+1 for nul terminator } + s = malloc(alloc_sz + 1); //+1 for nul terminator if (s == NULL) { goto out_close; } From b93e5b6d5b2a8d598eaca29c20b697498e75a906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 13 Mar 2014 23:16:50 +0100 Subject: [PATCH 12/55] add uc_read_fd function --- include/ucore/read_file.h | 8 ++++++++ src/read_file.c | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/ucore/read_file.h b/include/ucore/read_file.h index 9e1ea10..26e4987 100644 --- a/include/ucore/read_file.h +++ b/include/ucore/read_file.h @@ -21,6 +21,14 @@ extern "C" { char * uc_read_file(const char *file_name, size_t *length, size_t max); +/** Read the content of a file descriptor as a stream. + * @see uc_read_file + * This is similar but reads from a file descriptor, + * of any type as long as it supports the read() call. + */ +char * +uc_read_fd(int fd, size_t *length, size_t max); + #ifdef __cplusplus } #endif diff --git a/src/read_file.c b/src/read_file.c index 62f0d81..2bdb9e5 100644 --- a/src/read_file.c +++ b/src/read_file.c @@ -10,9 +10,8 @@ #define CHUNK_SZ 1024 char * -uc_read_file(const char *f, size_t *length, size_t max) +uc_read_fd(int fd, size_t *length, size_t max) { - int fd; char *s = NULL; char *p; struct stat statb; @@ -20,9 +19,6 @@ uc_read_file(const char *f, size_t *length, size_t max) *length = 0; - if ((fd = open(f, O_RDONLY)) == -1) - return NULL; - if (fstat(fd, &statb) == -1) { goto out_close; } @@ -85,3 +81,15 @@ out_close: return s; } +char * +uc_read_file(const char *f, size_t *length, size_t max) +{ + int fd; + + if ((fd = open(f, O_RDONLY)) == -1) { + *length = 0; + return NULL; + } + + return uc_read_fd(fd, length, max); +} From 71c9643ee9c68f0fb94dced4b11770ada55fda9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 14 Mar 2014 00:58:09 +0100 Subject: [PATCH 13/55] Better error message for UC_STATIC_ASSERT. Also require it to be terminated by a ; --- include/ucore/utils.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/ucore/utils.h b/include/ucore/utils.h index e2b6592..70e5ca9 100644 --- a/include/ucore/utils.h +++ b/include/ucore/utils.h @@ -6,9 +6,8 @@ //Gnerate a compiler error if the compile time //constant expression fails -#define UC_STATIC_ASSERT(expr) \ - enum { assert_static__ = 1/(expr) }; - +#define UC_STATIC_ASSERT(expr)\ + typedef int STATIC_ASSERT_FAILED[(expr) ? 1 : -1] //MAX of a and b #define UC_MAX(a,b) \ From c9656fbb3c87fc5cc779bcf53311879d76c384e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 18 Mar 2014 22:33:32 +0100 Subject: [PATCH 14/55] no need for clamping to funds + 1, just to funds --- src/rate_limit.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rate_limit.c b/src/rate_limit.c index 2facdc1..a2ad6ef 100644 --- a/src/rate_limit.c +++ b/src/rate_limit.c @@ -32,9 +32,9 @@ static void uc_ratelimit_refill(struct RateLimit *r, long current_ts) //Find elapsed time diff_period = current_ts - r->last_refill_ts; - if (diff_period > r->period + 1) { - //help prevent overflow when calculating available_tickets below - diff_period = r->period + 1; + if (diff_period > r->period) { + //help prevent overflow when calculating available tickets below + diff_period = r->period; } else if (diff_period < 0) { //time went backwards, skip this round diff_period = 0; From e09a51c852414002115fec57acc9a69f56e9fc21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 9 Apr 2014 23:51:42 +0200 Subject: [PATCH 15/55] Add -Winit-self flag --- SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index d650a8b..f0fc4bb 100644 --- a/SConstruct +++ b/SConstruct @@ -95,7 +95,7 @@ if os.environ.has_key('CC'): env.AddMethod(InstallPerm) env.Append(CFLAGS = ['-std=gnu99','-Wall', '-Wextra', '-Wundef', '-Wcast-qual','-Wshadow' ,'-Wcast-align','-pipe', '-ggdb', '-pthread']) -env.Append(CFLAGS = ['-Wno-unused-parameter', '-Werror=implicit-function-declaration']) +env.Append(CFLAGS = ['-Wno-unused-parameter', '-Werror=implicit-function-declaration', '-Winit-self']) env.Append(LINKFLAGS = ['-O2', '-pthread']) env.Append(CPPDEFINES = ['_FILE_OFFSET_BITS=64']) env.Append(CPPPATH = ['#include']) From 0fe19af6b6be20c7d7f31c5d36a59df721678f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sat, 19 Apr 2014 00:20:11 +0200 Subject: [PATCH 16/55] Use TailQ instead of sys/queue.h in the logging module --- src/logging.c | 46 +++++++++++++++++++++++++++------------------ test/test_logging.c | 9 +++++++++ 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/logging.c b/src/logging.c index aad0c34..b0120e8 100644 --- a/src/logging.c +++ b/src/logging.c @@ -6,6 +6,7 @@ #include #include #include +#include "ucore/tailq.h" #include "ucore/logging.h" #include "ucore/utils.h" @@ -16,7 +17,7 @@ struct UCLogModule_setting { }; struct UCLogDestination { - SLIST_ENTRY(UCLogDestination) entry; + struct TailQ entry; enum UC_LOG_DESTINATION dest_type; //log level for this destination int log_level; @@ -63,7 +64,7 @@ static const struct UCLogModule g_unknown_module = { //All destinations. The g_log_lock must be held while accessing //this list an anything contained within it. -static SLIST_HEAD(, UCLogDestination) g_destinations; +static UC_TAILQ_HEAD(g_destinations); static int uc_log_reopen_file(struct UCLogDestination *dest); //Uses enum UC_LOG_LEVEL as index static const char *const g_log_levels[] = { @@ -122,11 +123,12 @@ static inline int uc_ll_2_syslog(enum UC_LOG_LEVEL l) } //Note, this grabs the global lock -static int uc_log_init_settings(struct UCLogDestination *dest) +static int uc_log_init_common(struct UCLogDestination *dest) { int i; int rc = -1; - + + //copy over the log_level_settings pthread_mutex_lock(&g_log_lock); dest->module_settings = calloc(g_modules.cnt, sizeof *dest->module_settings); @@ -140,6 +142,8 @@ static int uc_log_init_settings(struct UCLogDestination *dest) pthread_mutex_unlock(&g_log_lock); + uc_tailq_init(&dest->entry); + return rc; } @@ -150,11 +154,11 @@ struct UCLogDestination *uc_log_new_stderr(int log_level, int log_location) if(dest == NULL) return NULL; - if (uc_log_init_settings(dest) != 0) { + if (uc_log_init_common(dest) != 0) { free(dest); return NULL; } - + dest->dest_type = UC_LDEST_STDERR; dest->type.file.file = stderr; dest->log_level = log_level;; @@ -171,7 +175,7 @@ struct UCLogDestination *uc_log_new_syslog(const char *ident, int facility, int if (dest == NULL) return NULL; - if (uc_log_init_settings(dest) != 0) { + if (uc_log_init_common(dest) != 0) { free(dest); return NULL; } @@ -204,7 +208,7 @@ struct UCLogDestination *uc_log_new_file(const char *filename, int log_level, in if (dest == NULL) return NULL; - if (uc_log_init_settings(dest) != 0) { + if (uc_log_init_common(dest) != 0) { free(dest); return NULL; } @@ -238,6 +242,7 @@ struct UCLogDestination *uc_log_new_file(const char *filename, int log_level, in void uc_log_add_destination(struct UCLogDestination *dest) { struct UCLogDestination *it; + int exists = 0; if (dest == NULL) return; @@ -245,14 +250,16 @@ void uc_log_add_destination(struct UCLogDestination *dest) pthread_mutex_lock(&g_log_lock); //make sure the destination isn't added twice. - SLIST_FOREACH(it, &g_destinations, entry) { - if (dest == it) + UC_TAILQ_FOREACH_CONTAINER(it, entry, &g_destinations) { + if (dest == it) { + exists = 1; break; + } } //add if it isn't already in the list - if (it == NULL) { - SLIST_INSERT_HEAD(&g_destinations, dest, entry); + if (!exists) { + uc_tailq_insert_head(&g_destinations, &dest->entry); } pthread_mutex_unlock(&g_log_lock); @@ -262,15 +269,18 @@ void uc_log_add_destination(struct UCLogDestination *dest) static inline void uc_log_remove_dest_unlocked(struct UCLogDestination *dest) { struct UCLogDestination *it; + int exists = 0; //check that it's not already removed - SLIST_FOREACH(it, &g_destinations, entry) { - if (it == dest) + UC_TAILQ_FOREACH_CONTAINER(it, entry, &g_destinations) { + if (it == dest) { + exists = 1; break; + } } - if (it != NULL) { - SLIST_REMOVE(&g_destinations, dest, UCLogDestination, entry); + if (exists) { + uc_tailq_remove(&dest->entry); } } @@ -373,7 +383,7 @@ int uc_log_reopen_files(void) pthread_mutex_lock(&g_log_lock); - SLIST_FOREACH(dest, &g_destinations, entry) { + UC_TAILQ_FOREACH_CONTAINER(dest, entry, &g_destinations) { if (dest->dest_type == UC_LDEST_FILE) { rc = uc_log_reopen_file(dest); @@ -553,7 +563,7 @@ void uc_logf(int log_level, int module, int raw, pthread_mutex_lock(&g_log_lock); //do logging for each destination - SLIST_FOREACH(dest, &g_destinations, entry) { + UC_TAILQ_FOREACH_CONTAINER(dest, entry, &g_destinations) { const struct UCLogModule *log_module; va_list apc; int module_log_level; diff --git a/test/test_logging.c b/test/test_logging.c index 783357d..f91150a 100644 --- a/test/test_logging.c +++ b/test/test_logging.c @@ -292,6 +292,15 @@ START_TEST (test_logfile_remove_dest) fail_if(rc != 0, "2. stat failed: %s\n", strerror(errno)); fail_if(st.st_size != 77*2, "was %ld\n", (long)st.st_size);//should be same size + //removing the last destination should be fine too + uc_log_remove_destination(dest2); + + UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1); + + rc = stat(FILE_NAME, &st); + fail_if(rc != 0, "2. stat failed: %s\n", strerror(errno)); + fail_if(st.st_size != 77*2, "was %ld\n", (long)st.st_size);//should be same size + END_TEST START_TEST (test_logfile_full_filesystem) From bb1b152fd003108903821a41640d95adf4414cfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sat, 19 Apr 2014 00:36:24 +0200 Subject: [PATCH 17/55] Slight refactor of checking if a destination exists --- src/logging.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/logging.c b/src/logging.c index b0120e8..f0d44ab 100644 --- a/src/logging.c +++ b/src/logging.c @@ -239,24 +239,30 @@ struct UCLogDestination *uc_log_new_file(const char *filename, int log_level, in return dest; } -void uc_log_add_destination(struct UCLogDestination *dest) +//Check if a destination already exists (hold g_log_lock when calling this) +static int uc_log_dest_exists_unlocked(struct UCLogDestination *dest) { struct UCLogDestination *it; - int exists = 0; + + UC_TAILQ_FOREACH_CONTAINER(it, entry, &g_destinations) { + if (dest == it) { + return 1; + } + } + + return 0; +} + +void uc_log_add_destination(struct UCLogDestination *dest) +{ + int exists; if (dest == NULL) return; pthread_mutex_lock(&g_log_lock); - //make sure the destination isn't added twice. - UC_TAILQ_FOREACH_CONTAINER(it, entry, &g_destinations) { - if (dest == it) { - exists = 1; - break; - } - } - + exists = uc_log_dest_exists_unlocked(dest); //add if it isn't already in the list if (!exists) { uc_tailq_insert_head(&g_destinations, &dest->entry); @@ -268,16 +274,10 @@ void uc_log_add_destination(struct UCLogDestination *dest) //hold g_log_lock while calling this. static inline void uc_log_remove_dest_unlocked(struct UCLogDestination *dest) { - struct UCLogDestination *it; - int exists = 0; + int exists; //check that it's not already removed - UC_TAILQ_FOREACH_CONTAINER(it, entry, &g_destinations) { - if (it == dest) { - exists = 1; - break; - } - } + exists = uc_log_dest_exists_unlocked(dest); if (exists) { uc_tailq_remove(&dest->entry); From f6351aacbb673a8e5c3705824cb52e2741c5b27c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sat, 19 Apr 2014 00:37:55 +0200 Subject: [PATCH 18/55] fix indentation --- src/logging.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/logging.c b/src/logging.c index f0d44ab..c4ea46c 100644 --- a/src/logging.c +++ b/src/logging.c @@ -159,10 +159,10 @@ struct UCLogDestination *uc_log_new_stderr(int log_level, int log_location) return NULL; } - dest->dest_type = UC_LDEST_STDERR; - dest->type.file.file = stderr; - dest->log_level = log_level;; - dest->log_location = log_location; + dest->dest_type = UC_LDEST_STDERR; + dest->type.file.file = stderr; + dest->log_level = log_level;; + dest->log_location = log_location; return dest; } From bc27ed462bbd30a7d947cb55313750f3cdf8f9b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 22 Apr 2014 23:16:57 +0200 Subject: [PATCH 19/55] Keep track of bytes written to a file --- src/logging.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/logging.c b/src/logging.c index c4ea46c..4e54a96 100644 --- a/src/logging.c +++ b/src/logging.c @@ -34,6 +34,7 @@ struct UCLogDestination { struct { FILE* file; char *file_name; //NULL for stderr destinaton + size_t size; //keeps track of no of bytes written } file; } type; }; @@ -161,6 +162,7 @@ struct UCLogDestination *uc_log_new_stderr(int log_level, int log_location) dest->dest_type = UC_LDEST_STDERR; dest->type.file.file = stderr; + dest->type.file.size = 0; dest->log_level = log_level;; dest->log_location = log_location; @@ -233,6 +235,7 @@ struct UCLogDestination *uc_log_new_file(const char *filename, int log_level, in dest->dest_type = UC_LDEST_FILE; dest->type.file.file = f; dest->type.file.file_name = name; + dest->type.file.size = 0; dest->log_level = log_level;; dest->log_location = log_location; @@ -387,6 +390,7 @@ int uc_log_reopen_files(void) if (dest->dest_type == UC_LDEST_FILE) { rc = uc_log_reopen_file(dest); + dest->type.file.size = 0; } } @@ -407,6 +411,7 @@ static inline void uc_vlog_file(const struct UCLogArgs *args, const char *fmt, v char time_buf[48]; time_t now; struct tm t; + int rc; if (dest->type.file.file == NULL) return; @@ -425,20 +430,25 @@ static inline void uc_vlog_file(const struct UCLogArgs *args, const char *fmt, v time_buf[sizeof time_buf -1] = 0; if (dest->log_location) { - fprintf(dest->type.file.file, "[%-7s] %s %s [%s] : ", + rc = fprintf(dest->type.file.file, "[%-7s] %s %s [%s] : ", uc_ll_2_str(args->log_level), time_buf, args->location, args->module->short_name); } else { - fprintf(dest->type.file.file, "[%-7s] %s [%s]: ", + rc = fprintf(dest->type.file.file, "[%-7s] %s [%s]: ", uc_ll_2_str(args->log_level), time_buf, args->module->short_name); } } + if (rc >= 0) { + dest->type.file.size += rc; + rc = vfprintf(dest->type.file.file, fmt, ap); + } - vfprintf(dest->type.file.file, fmt, ap); - - fflush(dest->type.file.file); //strictly not needed for stderr - // though stderr could be redirected to a file + if (rc >= 0) { + dest->type.file.size += rc; + rc = fflush(dest->type.file.file); //strictly not needed for stderr + // though stderr could be redirected to a file + } } static inline void uc_vlog_syslog(const struct UCLogArgs *args, const char *fmt, va_list ap) From 0e35ecbc29a60be435dda22a947d5df8ce8f6f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 23 Apr 2014 02:04:08 +0200 Subject: [PATCH 20/55] Initial attempt of log rotation based on file sizes --- include/ucore/logging.h | 38 ++++++++++++++ src/logging.c | 114 +++++++++++++++++++++++++++++++++++----- test/logging.c | 11 +++- 3 files changed, 149 insertions(+), 14 deletions(-) diff --git a/include/ucore/logging.h b/include/ucore/logging.h index 7dd4f7d..0d7f72a 100644 --- a/include/ucore/logging.h +++ b/include/ucore/logging.h @@ -132,6 +132,33 @@ struct UCLogModules { struct UCLogDestination; +enum UC_LOG_ROTATE_POLICY { + /** Don't rotate. Default setting*/ + UC_LOG_ROTATE_NONE, + /** Create a new log file every 'size' bytes */ + UC_LOG_ROTATE_SIZE +}; + +/** Log rotate settings that can be set on a UC_LDEST_FILE destination + * The default is to not rotate log files. + * The current log file wil always be the specified file name, + * For UC_LOG_ROTATE_SIZE the current file will be renamed when it exceeds + * the specified max_size with a .number suffix (e.g .0 , .1 , .2 and so on), + * up to num_files are kept and a new log file is created. + */ +struct UCLogRotateSettings { + /** Policy */ + enum UC_LOG_ROTATE_POLICY policy; + /** For UC_LOG_ROTATE_SIZE policy */ + struct { + /** Max size of an individual log file */ + size_t max_size; + /** Max number of log files to keep. + * Is forced to be at least 1*/ + unsigned int num_files; + } size_settings; +}; + /* Returns a string representation of the log level. * @@ -204,6 +231,17 @@ void uc_log_destination_set_loglevel(struct UCLogDestination *dest, enum UC_LOG_ * @param log_location 1=log the locaton, 0=don't log the location */ void uc_log_destination_set_log_location(struct UCLogDestination *dest, int log_location); + +/** Sets the log rotation settings. + * Does nothing if the destination is not a UC_LDEST_FILE, or the policy is invalid. + * The default is to not do log rotation + * + * @param dest log destination to change + * @param settings new policy to set + */ +void uc_log_destination_set_rotate_policy(struct UCLogDestination *dest, + const struct UCLogRotateSettings *settings); + /** Remove and free a destination. * This frees the memory allocated to the destination. For * UC_LDEST_FILE the log file is closed. diff --git a/src/logging.c b/src/logging.c index 4e54a96..0712125 100644 --- a/src/logging.c +++ b/src/logging.c @@ -1,7 +1,9 @@ #include +#include #include #include #include +#include #include #include #include @@ -10,6 +12,10 @@ #include "ucore/logging.h" #include "ucore/utils.h" +/** Max suffixes we'll try to apply to a log file when rotating before + * giving up + */ +#define UC_MAX_RENAME_CNT (128) //used to realise per destination settings struct UCLogModule_setting { @@ -33,8 +39,11 @@ struct UCLogDestination { //for stderr and files struct { FILE* file; - char *file_name; //NULL for stderr destinaton + char *file_name; //NULL for stderr destinaton. If rotate policy is in place + //this is the base file name (e.g. witout a date or count) size_t size; //keeps track of no of bytes written + struct UCLogRotateSettings rotate; + unsigned rotate_count; //current num_file } file; } type; }; @@ -239,11 +248,14 @@ struct UCLogDestination *uc_log_new_file(const char *filename, int log_level, in dest->log_level = log_level;; dest->log_location = log_location; + dest->type.file.rotate.policy = UC_LOG_ROTATE_NONE; + dest->type.file.rotate_count = 0; + return dest; } //Check if a destination already exists (hold g_log_lock when calling this) -static int uc_log_dest_exists_unlocked(struct UCLogDestination *dest) +static int uc_log_dest_exists(struct UCLogDestination *dest) { struct UCLogDestination *it; @@ -265,7 +277,7 @@ void uc_log_add_destination(struct UCLogDestination *dest) pthread_mutex_lock(&g_log_lock); - exists = uc_log_dest_exists_unlocked(dest); + exists = uc_log_dest_exists(dest); //add if it isn't already in the list if (!exists) { uc_tailq_insert_head(&g_destinations, &dest->entry); @@ -275,12 +287,12 @@ void uc_log_add_destination(struct UCLogDestination *dest) } //hold g_log_lock while calling this. -static inline void uc_log_remove_dest_unlocked(struct UCLogDestination *dest) +static inline void uc_log_remove_dest(struct UCLogDestination *dest) { int exists; //check that it's not already removed - exists = uc_log_dest_exists_unlocked(dest); + exists = uc_log_dest_exists(dest); if (exists) { uc_tailq_remove(&dest->entry); @@ -294,7 +306,7 @@ void uc_log_remove_destination(struct UCLogDestination *dest) pthread_mutex_lock(&g_log_lock); - uc_log_remove_dest_unlocked(dest); + uc_log_remove_dest(dest); pthread_mutex_unlock(&g_log_lock); } @@ -307,7 +319,7 @@ void uc_log_delete_destination(struct UCLogDestination *dest) pthread_mutex_lock(&g_log_lock); //remove it, it's ok if the destination is already removed - uc_log_remove_dest_unlocked(dest); + uc_log_remove_dest(dest); //clean up, according to the type switch (dest->dest_type) { @@ -357,6 +369,30 @@ void uc_log_destination_set_log_location(struct UCLogDestination *dest, int log_ pthread_mutex_unlock(&g_log_lock); } +void uc_log_destination_set_rotate_policy(struct UCLogDestination *dest, + const struct UCLogRotateSettings *settings) +{ + + if (dest->dest_type != UC_LDEST_FILE) { + return; + } + + if (settings->policy != UC_LOG_ROTATE_NONE && settings->policy != UC_LOG_ROTATE_SIZE) { + return; + } + + pthread_mutex_lock(&g_log_lock); + + dest->type.file.rotate = *settings; + if (dest->type.file.rotate.size_settings.num_files == 0) { + dest->type.file.rotate.size_settings.num_files = 1; + } + + pthread_mutex_unlock(&g_log_lock); + +} + +//hold g_log_lock while calling this static int uc_log_reopen_file(struct UCLogDestination *dest) { int rc = 0; @@ -404,20 +440,18 @@ void uc_log_init(struct UCLogModules *user_modules) g_modules = *user_modules; } - -static inline void uc_vlog_file(const struct UCLogArgs *args, const char *fmt, va_list ap) +//hold g_log_lock while calling this +static inline void uc_vlog_file(const struct UCLogArgs *args, time_t tstamp, const char *fmt, va_list ap) { struct UCLogDestination *dest = args->dest; char time_buf[48]; - time_t now; struct tm t; int rc; if (dest->type.file.file == NULL) return; - now = time(NULL); - localtime_r(&now, &t); + localtime_r(&tstamp, &t); if (!args->raw) { snprintf(time_buf, sizeof time_buf, "%04d-%02d-%02d %02d:%02d:%02d", t.tm_year + 1900, @@ -451,6 +485,7 @@ static inline void uc_vlog_file(const struct UCLogArgs *args, const char *fmt, v } } +//hold g_log_lock while calling this static inline void uc_vlog_syslog(const struct UCLogArgs *args, const char *fmt, va_list ap) { struct UCLogDestination *dest = args->dest; @@ -562,6 +597,53 @@ void uc_log_destination_set_mask( pthread_mutex_unlock(&g_log_lock); } +//assumes the destination is a UC_LDEST_FILE +//hold g_log_lock while calling this +static int uc_log_file_rotate_size(struct UCLogDestination *dest) +{ + char new_filename[_POSIX_PATH_MAX * 2]; + int rc; + int rotate_count; + + if (dest->type.file.file_name == NULL) { + return 0; + } + + rotate_count = ++dest->type.file.rotate_count; + rotate_count %= dest->type.file.rotate.size_settings.num_files; + + snprintf(new_filename, sizeof new_filename, "%s.%d", + dest->type.file.file_name, + rotate_count); + + rc = rename(dest->type.file.file_name, new_filename); + if (rc != -1) { + dest->type.file.rotate_count = rotate_count; + } + + uc_log_reopen_file(dest); //try to reopen the log file regardless if renaming failed + + return rc; +} + +//assumes the destination is a UC_LDEST_FILE +//hold g_log_lock while calling this +static inline void uc_log_file_rotate_if_neeed(struct UCLogDestination *dest, time_t tstamp) +{ + struct UCLogRotateSettings *rotate = &dest->type.file.rotate; + + switch (rotate->policy) { + case UC_LOG_ROTATE_NONE: + //Nothing to do + break; + case UC_LOG_ROTATE_SIZE: + if (dest->type.file.size >= rotate->size_settings.max_size) { + uc_log_file_rotate_size(dest); + } + break; + } +} + void uc_logf(int log_level, int module, int raw, const char *location, const char *fmt, ...) { @@ -605,6 +687,7 @@ void uc_logf(int log_level, int module, int raw, .raw = raw }; + time_t tstamp; //log func will mess with the va_list, //so make a copy va_copy(apc, ap); @@ -614,8 +697,13 @@ void uc_logf(int log_level, int module, int raw, uc_vlog_syslog(&args, fmt, apc); break; case UC_LDEST_STDERR: + tstamp = time(NULL); + uc_vlog_file(&args, tstamp,fmt, apc); + break; case UC_LDEST_FILE: - uc_vlog_file(&args, fmt, apc); + tstamp = time(NULL); + uc_vlog_file(&args, tstamp, fmt, apc); + uc_log_file_rotate_if_neeed(dest, tstamp); break; } diff --git a/test/logging.c b/test/logging.c index 1e794e9..fe4be1c 100644 --- a/test/logging.c +++ b/test/logging.c @@ -36,14 +36,23 @@ struct UCLogModules modules = { int main(int argc, char *argv[]) { struct UCLogDestination *dest; + struct UCLogRotateSettings settings; + settings.policy = UC_LOG_ROTATE_SIZE; + settings.size_settings.max_size = 300; + settings.size_settings.num_files = 2; + uc_log_init(&modules); - dest = uc_log_new_file("test.log", UC_LL_INFO, 1); + dest = uc_log_new_file("test.log", UC_LL_DEBUG, 1); uc_log_add_destination(dest); + uc_log_destination_set_rotate_policy(dest, &settings); dest = uc_log_new_syslog("log.test", LOG_DAEMON, UC_LL_INFO, 0); uc_log_add_destination(dest); dest = uc_log_new_stderr(UC_LL_INFO, 0); uc_log_add_destination(dest); UC_LOGF( UC_LL_INFO, CC, "Test cc info %d\n", 2); + UC_LOGF( UC_LL_INFO, CC, "Test cc info %d\n", 3); + UC_LOGF( UC_LL_INFO, CC, "Test cc info %d\n", 4); + UC_LOGF( UC_LL_INFO, CC, "Test cc info %d\n", 5); UC_LOGF( UC_LL_WARNING, HO, "Test HO warning%d\n", 2); UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN info \n" ); UC_LOGF( UC_LL_WARNING, MAIN, "Test MAIN warning\n" ); From 8abf8068c3a07cbe84e1223bc7ffcc4596be09b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 23 Apr 2014 02:21:54 +0200 Subject: [PATCH 21/55] Fix raw loggin use of uninitialized value introduced in previous commit --- src/logging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging.c b/src/logging.c index 0712125..68843ef 100644 --- a/src/logging.c +++ b/src/logging.c @@ -446,7 +446,7 @@ static inline void uc_vlog_file(const struct UCLogArgs *args, time_t tstamp, con struct UCLogDestination *dest = args->dest; char time_buf[48]; struct tm t; - int rc; + int rc = 0; if (dest->type.file.file == NULL) return; From 93a195f0e844cda29df36713c175ac349e35a8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 23 Apr 2014 22:38:04 +0200 Subject: [PATCH 22/55] Fix size rotating, so filenames are in the order of newest to oldest --- src/logging.c | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/logging.c b/src/logging.c index 68843ef..76e88d5 100644 --- a/src/logging.c +++ b/src/logging.c @@ -43,7 +43,6 @@ struct UCLogDestination { //this is the base file name (e.g. witout a date or count) size_t size; //keeps track of no of bytes written struct UCLogRotateSettings rotate; - unsigned rotate_count; //current num_file } file; } type; }; @@ -249,7 +248,6 @@ struct UCLogDestination *uc_log_new_file(const char *filename, int log_level, in dest->log_location = log_location; dest->type.file.rotate.policy = UC_LOG_ROTATE_NONE; - dest->type.file.rotate_count = 0; return dest; } @@ -426,7 +424,9 @@ int uc_log_reopen_files(void) if (dest->dest_type == UC_LDEST_FILE) { rc = uc_log_reopen_file(dest); - dest->type.file.size = 0; + if (rc == 0) { + dest->type.file.size = 0; + } } } @@ -599,31 +599,38 @@ void uc_log_destination_set_mask( //assumes the destination is a UC_LDEST_FILE //hold g_log_lock while calling this -static int uc_log_file_rotate_size(struct UCLogDestination *dest) +static void uc_log_file_rotate_size(struct UCLogDestination *dest) { char new_filename[_POSIX_PATH_MAX * 2]; + char old_filename[_POSIX_PATH_MAX * 2]; + unsigned int i; int rc; - int rotate_count; if (dest->type.file.file_name == NULL) { - return 0; - } - - rotate_count = ++dest->type.file.rotate_count; - rotate_count %= dest->type.file.rotate.size_settings.num_files; - - snprintf(new_filename, sizeof new_filename, "%s.%d", - dest->type.file.file_name, - rotate_count); - - rc = rename(dest->type.file.file_name, new_filename); - if (rc != -1) { - dest->type.file.rotate_count = rotate_count; + return; } - uc_log_reopen_file(dest); //try to reopen the log file regardless if renaming failed + //rotate existing .num files + i = dest->type.file.rotate.size_settings.num_files -1; + while (i > 0) { + sprintf(new_filename, "%s.%d", dest->type.file.file_name, i); + sprintf(old_filename, "%s.%d", dest->type.file.file_name, i - 1); + rename(old_filename, new_filename); + i--; + } - return rc; + sprintf(new_filename, "%s.0", dest->type.file.file_name); + + //rename current file + rename(dest->type.file.file_name, new_filename); + + //re-open current file + rc = uc_log_reopen_file(dest); + if (rc == 0) { + dest->type.file.size = 0; + } + + return; } //assumes the destination is a UC_LDEST_FILE From f267b66bbe243c18f7e9df3f912292dbc43750d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 23 Apr 2014 22:40:37 +0200 Subject: [PATCH 23/55] Use snprintf over sprintf --- src/logging.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/logging.c b/src/logging.c index 76e88d5..100f831 100644 --- a/src/logging.c +++ b/src/logging.c @@ -613,15 +613,14 @@ static void uc_log_file_rotate_size(struct UCLogDestination *dest) //rotate existing .num files i = dest->type.file.rotate.size_settings.num_files -1; while (i > 0) { - sprintf(new_filename, "%s.%d", dest->type.file.file_name, i); - sprintf(old_filename, "%s.%d", dest->type.file.file_name, i - 1); + snprintf(new_filename, sizeof new_filename, "%s.%d", dest->type.file.file_name, i); + snprintf(old_filename, sizeof old_filename, "%s.%d", dest->type.file.file_name, i - 1); rename(old_filename, new_filename); i--; } - sprintf(new_filename, "%s.0", dest->type.file.file_name); - //rename current file + sprintf(new_filename, "%s.0", dest->type.file.file_name); rename(dest->type.file.file_name, new_filename); //re-open current file From 0014ca5c2e8bf93af99a3a1f619c81bbef39ca48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 25 Apr 2014 19:57:59 +0200 Subject: [PATCH 24/55] Move UC_LOG_DESTINATION enum to logging.c, it's not a public type --- include/ucore/logging.h | 16 +++------------- src/logging.c | 12 ++++++++++++ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/ucore/logging.h b/include/ucore/logging.h index 0d7f72a..3c19f7d 100644 --- a/include/ucore/logging.h +++ b/include/ucore/logging.h @@ -83,18 +83,6 @@ enum UC_LOG_LEVEL { UC_LL_NONE = 9, }; -/** A destination for the logging messages*/ -enum UC_LOG_DESTINATION { - /** Logs using the unix syslog system */ - UC_LDEST_SYSLOG, - - /** Prints log messages to stderr. */ - UC_LDEST_STDERR, - - /** Prints log messages to a file */ - UC_LDEST_FILE, -}; - /** A module of a program, that will perform logging. * This is used group logging from parts of a larger program, * and allow the log message to identigy which module the @@ -149,11 +137,13 @@ enum UC_LOG_ROTATE_POLICY { struct UCLogRotateSettings { /** Policy */ enum UC_LOG_ROTATE_POLICY policy; + /** For UC_LOG_ROTATE_SIZE policy */ struct { /** Max size of an individual log file */ size_t max_size; - /** Max number of log files to keep. + /** Max number of extra log files to keep in addition + * to the current log file. * Is forced to be at least 1*/ unsigned int num_files; } size_settings; diff --git a/src/logging.c b/src/logging.c index 100f831..567696a 100644 --- a/src/logging.c +++ b/src/logging.c @@ -12,6 +12,18 @@ #include "ucore/logging.h" #include "ucore/utils.h" +/** A destination for the logging messages*/ +enum UC_LOG_DESTINATION { + /** Logs using the unix syslog system */ + UC_LDEST_SYSLOG, + + /** Prints log messages to stderr. */ + UC_LDEST_STDERR, + + /** Prints log messages to a file */ + UC_LDEST_FILE, +}; + /** Max suffixes we'll try to apply to a log file when rotating before * giving up */ From fe7c152631ea184e6690764ad54c1b304ba08402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 7 May 2014 22:48:56 +0200 Subject: [PATCH 25/55] Use nonblocking pipes --- src/iomux_waker.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/iomux_waker.c b/src/iomux_waker.c index a7c517b..972b8ab 100644 --- a/src/iomux_waker.c +++ b/src/iomux_waker.c @@ -3,6 +3,7 @@ #include #include #include "ucore/iomux_waker.h" +#include "ucore/fd_utils.h" static void uc_waker_pipe_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event) { @@ -64,6 +65,10 @@ int uc_iomux_waker_init(struct IOMux *mux, struct IOMuxWaker *wk, uc_waker_cb cb wk->mux = mux; wk->wake_cb = cb; wk->signaller.fd = pfds[1]; + rc = uc_set_nonblocking(pfds[0]); + assert(rc == 0); + rc = uc_set_nonblocking(pfds[1]); + assert(rc == 0); if (uc_install_wake_handler(wk, pfds[0]) == 0) { return 0; From b3b1179c5a23afbda00877966cdb7bc36a4c6b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 25 May 2014 23:07:08 +0200 Subject: [PATCH 26/55] Use restrict on pointers where it makes sense. (requires C99 support, which we already assume) --- include/ucore/dstr.h | 16 ++++++++-------- include/ucore/mbuf.h | 2 +- include/ucore/string.h | 12 ++++++------ include/ucore/strvec.h | 6 +++--- include/ucore/val_str.h | 2 +- src/bcd.c | 4 ++-- src/dstr.c | 14 +++++++------- src/hex.c | 6 +++--- src/mbuf.c | 2 +- src/strlcpy.c | 2 +- src/strvec.c | 6 +++--- src/val_str.c | 2 +- 12 files changed, 37 insertions(+), 37 deletions(-) diff --git a/include/ucore/dstr.h b/include/ucore/dstr.h index 083de2f..e71c397 100644 --- a/include/ucore/dstr.h +++ b/include/ucore/dstr.h @@ -47,7 +47,7 @@ void uc_dstr_destroy(struct DStr *str); * * @return 0 if success, != 0 if allocation fails */ -int uc_dstr_copy(struct DStr *dest, const struct DStr *src); +int uc_dstr_copy(struct DStr *restrict dest, const struct DStr *restrict src); /** * @return the available/unused tail bytes in the string. @@ -95,7 +95,7 @@ char *uc_dstr_put(struct DStr *str, size_t len); * @param is_x ctype.h compatible function to use as a filter. * @return number of chars appended */ -size_t uc_dstr_put_str_filter(struct DStr *str, const char *s, int (*is_x)(int c)); +size_t uc_dstr_put_str_filter(struct DStr *str, const char *restrict s, int (*is_x)(int c)); /* Append a string of the give size. * (The nul terminator is not appended) @@ -104,14 +104,14 @@ size_t uc_dstr_put_str_filter(struct DStr *str, const char *s, int (*is_x)(int c * @param len bytes to append (not including the nul terminator) * @return 0 on success (!= 0 if an allocation fail) */ -int uc_dstr_put_str_sz(struct DStr *str, const char *s, size_t len); +int uc_dstr_put_str_sz(struct DStr *str, const char *restrict s, size_t len); /* Append a string. * (The nul terminator is not appended) * * @return 0 on success (!= 0 if an allocation fail) */ -int uc_dstr_put_str(struct DStr *str, const char *s); +int uc_dstr_put_str(struct DStr *str, const char *restrict s); /* Append a single char. * @@ -122,7 +122,7 @@ int uc_dstr_put_char(struct DStr *str, char c); /* Make the DStr take ownership of the given dynamically allocated string. * Any existing string in the DStr is freed. */ -void uc_dstr_own(struct DStr *str, char *s); +void uc_dstr_own(struct DStr *str, char *restrict s); /** Release the managed string. * The caller is now responsible for managing/free'ing the returned string. @@ -133,7 +133,7 @@ void uc_dstr_own(struct DStr *str, char *s); char *uc_dstr_steal(struct DStr *str); /** Swap the A and B DStr */ -void uc_str_swap(struct DStr *a, struct DStr *b); +void uc_str_swap(struct DStr *restrict a, struct DStr *restrict b); /** Replace all occurences in the DStr * (This may be used to replace any embedded nul bytes too) @@ -149,10 +149,10 @@ size_t uc_dstr_replace(struct DStr *str, char f, char r); void uc_dstr_trim(struct DStr *str); /** Append formatted string (just as sprintf)*/ -int uc_dstr_sprintf(struct DStr *str, const char *fmt, ...) __attribute__((format(printf,2,3))); +int uc_dstr_sprintf(struct DStr *str, const char *restrict fmt, ...) __attribute__((format(printf,2,3))); /** va_list variant */ -int uc_dstr_vsprintf(struct DStr *str, const char *fmt, va_list ap_)__attribute__((format(printf,2,0))); +int uc_dstr_vsprintf(struct DStr *str, const char *restrict fmt, va_list ap_)__attribute__((format(printf,2,0))); #ifdef __cplusplus } diff --git a/include/ucore/mbuf.h b/include/ucore/mbuf.h index c73cd36..73dc17e 100644 --- a/include/ucore/mbuf.h +++ b/include/ucore/mbuf.h @@ -125,7 +125,7 @@ struct MBuf *uc_mbuf_copy_data(struct MBuf *mbuf); * @param headroom the headroom in the buffer * @param flags The appropriate UC_MBUF_FLAGS */ -void uc_mbuf_init(struct MBuf *mbuf, uint8_t *buf, uint32_t len, uint32_t headroom, uint32_t flags); +void uc_mbuf_init(struct MBuf *mbuf, uint8_t *restrict buf, uint32_t len, uint32_t headroom, uint32_t flags); /** Zero out all the data in this mbuf, including the headroom * diff --git a/include/ucore/string.h b/include/ucore/string.h index 7914f01..f1269fb 100644 --- a/include/ucore/string.h +++ b/include/ucore/string.h @@ -18,7 +18,7 @@ extern "C" { * @param out where to store result. Must hold at least len * 2 + 1 * @return returns one past the end of the converted data */ -char* uc_hex_encode(const uint8_t *in, size_t len, char *out); +char* uc_hex_encode(const uint8_t *restrict in, size_t len, char *restrict out); /** Decode hex. Will stop at the first non-convertible hex-digit * spaces(' ','\t,'\r','\n') in input are skipped @@ -32,11 +32,11 @@ char* uc_hex_encode(const uint8_t *in, size_t len, char *out); * @param out where to store result. Must hold at least maxlen/2 + 1 * @return returns one past the end of the converted data */ -uint8_t* uc_hex_decode(const char *in, size_t maxlen,uint8_t *out); +uint8_t* uc_hex_decode(const char *restrict in, size_t maxlen,uint8_t *restrict out); /** As uc_hex_encode , but inserts the @delim string between each converted * byte (each 2 hex chars) */ -char* uc_hex_encode_delim(const uint8_t *in, size_t inlen, char *out, int outlen, const char *delim); +char* uc_hex_encode_delim(const uint8_t *restrict in, size_t inlen, char *restrict out, int outlen, const char *restrict delim); /** * Convert the string to lowercase, calls tolower() on each char. @@ -67,7 +67,7 @@ void uc_str_toupper(char *s); * if the number of ASCII digits is odd. This would usually be 0x0 or 0xf. * @return the number of bytes written to bcdout */ -size_t uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler); +size_t uc_ascii2bcd(const char *restrict ascii, unsigned char *restrict bcdout, unsigned char filler); /** Convert the BCD digits to ascii. * The resulting ascii string is 0 terminated. @@ -77,7 +77,7 @@ size_t uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char fill * @param asciiout buffer to place ASCII in, must be UC_ASCII_LEN(bcdlen)+1 big * @return the number of characters written to bcdout (this will always be UC_ASCII_LEN(bcdlen) */ -size_t uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout); +size_t uc_bcd2ascii(const unsigned char *restrict bcd, size_t bcdlen, char *restrict asciiout); /** uc_sprintb for converting the values into ascii bit representation * e.g. 0x3 -> "00000011". The result must be able to hold the max number @@ -111,7 +111,7 @@ char * uc_human_bytesz_bin(uint64_t bytes, char *result, size_t result_len); * is normally the size of the dst buffer) * return strlen(src) which may be larger than the no. of bytes copied. */ -size_t uc_strlcpy(char *dst, const char *src, size_t max); +size_t uc_strlcpy(char *restrict dst, const char *restrict src, size_t max); #ifdef __cplusplus } diff --git a/include/ucore/strvec.h b/include/ucore/strvec.h index c854161..f4be722 100644 --- a/include/ucore/strvec.h +++ b/include/ucore/strvec.h @@ -52,7 +52,7 @@ int uc_strv_check_expand(struct UCStrv *strv); * @param str String to append, the string will be copied. * @return 0 on success, otherwise failure **/ -int uc_strv_append(struct UCStrv *strv, const char *str); +int uc_strv_append(struct UCStrv *strv, const char *restrict str); /** * Append a string to the strvec, nocopy variang. @@ -63,7 +63,7 @@ int uc_strv_append(struct UCStrv *strv, const char *str); * @param str the string to append * @return 0 on success, otherwise failure **/ -int uc_strv_append_nocopy(struct UCStrv *strv, char *str); +int uc_strv_append_nocopy(struct UCStrv *strv, char *restrict str); /** * Append a NULL pointer to the UCStrv, (cnt is not increased, @@ -98,7 +98,7 @@ void uc_strv_destroy(struct UCStrv *strv); * 0 to just append the same pointer in b to a * @return 0 on success, != 0 if appending/allocation fails */ -int uc_strv_append_all(struct UCStrv *a, struct UCStrv *b, int copy); +int uc_strv_append_all(struct UCStrv *restrict a, struct UCStrv *restrict b, int copy); #ifdef __cplusplus } diff --git a/include/ucore/val_str.h b/include/ucore/val_str.h index 9e180b5..9ee6cae 100644 --- a/include/ucore/val_str.h +++ b/include/ucore/val_str.h @@ -48,6 +48,6 @@ const char *uc_val_2_str_bs(unsigned int val, * @param array array to search * @return the string associated with @val or null */ -const char *uc_str_2_str(const char *val, const struct UCStrStr *array); +const char *uc_str_2_str(const char *restrict val, const struct UCStrStr *array); #endif diff --git a/src/bcd.c b/src/bcd.c index 4cfb9ff..7590656 100644 --- a/src/bcd.c +++ b/src/bcd.c @@ -4,7 +4,7 @@ #include "ucore/string.h" size_t -uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler) +uc_ascii2bcd(const char *restrict ascii, unsigned char *restrict bcdout, unsigned char filler) { unsigned char *bcdp = bcdout; int shift = 0; @@ -36,7 +36,7 @@ uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler) static const char hex[] = "0123456789ABCDEF"; size_t -uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout) +uc_bcd2ascii(const unsigned char *restrict bcd, size_t bcdlen, char *restrict asciiout) { size_t i; size_t idx = 0; diff --git a/src/dstr.c b/src/dstr.c index a9ddf4d..99be0bc 100644 --- a/src/dstr.c +++ b/src/dstr.c @@ -106,7 +106,7 @@ char *uc_dstr_put(struct DStr *str, size_t len) return start; } -size_t uc_dstr_put_str_filter(struct DStr *str, const char *s, int (*is_x)(int c)) +size_t uc_dstr_put_str_filter(struct DStr *str, const char *restrict s, int (*is_x)(int c)) { size_t len = strlen(s); size_t i; @@ -128,7 +128,7 @@ size_t uc_dstr_put_str_filter(struct DStr *str, const char *s, int (*is_x)(int c return idx; } -int uc_dstr_put_str_sz(struct DStr *str, const char *s, size_t len) +int uc_dstr_put_str_sz(struct DStr *str, const char *restrict s, size_t len) { char *start = uc_dstr_put(str, len); @@ -140,7 +140,7 @@ int uc_dstr_put_str_sz(struct DStr *str, const char *s, size_t len) return 0; } -int uc_dstr_put_str(struct DStr *str, const char *s) +int uc_dstr_put_str(struct DStr *str, const char *restrict s) { size_t len = strlen(s); @@ -159,7 +159,7 @@ int uc_dstr_put_char(struct DStr *str, char c) return 0; } -void uc_dstr_own(struct DStr *str, char *s) +void uc_dstr_own(struct DStr *str, char *restrict s) { size_t len = strlen(s); @@ -181,7 +181,7 @@ char *uc_dstr_steal(struct DStr *str) return s; } -void uc_str_swap(struct DStr *a, struct DStr *b) +void uc_str_swap(struct DStr *restrict a, struct DStr *restrict b) { struct DStr tmp; @@ -236,7 +236,7 @@ void uc_dstr_trim(struct DStr *str) } } -int uc_dstr_sprintf(struct DStr *str, const char *fmt, ...) +int uc_dstr_sprintf(struct DStr *str, const char *restrict fmt, ...) { va_list ap; int rc; @@ -248,7 +248,7 @@ int uc_dstr_sprintf(struct DStr *str, const char *fmt, ...) return rc; } -int uc_dstr_vsprintf(struct DStr *str, const char *fmt, va_list ap_) +int uc_dstr_vsprintf(struct DStr *str, const char *restrict fmt, va_list ap_) { va_list ap; int rc; diff --git a/src/hex.c b/src/hex.c index b2a162d..1b01ad9 100644 --- a/src/hex.c +++ b/src/hex.c @@ -8,7 +8,7 @@ static const char hx_chars[] = "0123456789ABCDEF" ; char* -uc_hex_encode(const uint8_t *in, size_t len, char *out) +uc_hex_encode(const uint8_t *restrict in, size_t len, char *restrict out) { unsigned int i, t; @@ -28,7 +28,7 @@ uc_hex_encode(const uint8_t *in, size_t len, char *out) } char* -uc_hex_encode_delim(const uint8_t *in, size_t inlen, char *out, int outlen, const char *delim) +uc_hex_encode_delim(const uint8_t *restrict in, size_t inlen, char *restrict out, int outlen, const char *restrict delim) { size_t i; char *outp = out; @@ -76,7 +76,7 @@ static inline int char_to_bin(char c) } uint8_t* -uc_hex_decode(const char *in, size_t maxlen,uint8_t *out) +uc_hex_decode(const char *restrict in, size_t maxlen,uint8_t *restrict out) { size_t i, t; diff --git a/src/mbuf.c b/src/mbuf.c index 4dd52e1..b4ab023 100644 --- a/src/mbuf.c +++ b/src/mbuf.c @@ -40,7 +40,7 @@ uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size) return data; } -void uc_mbuf_init(struct MBuf *mbuf, uint8_t *buf, uint32_t len, uint32_t headroom, uint32_t flags) +void uc_mbuf_init(struct MBuf *mbuf, uint8_t *restrict buf, uint32_t len, uint32_t headroom, uint32_t flags) { mbuf->bufstart = buf; mbuf->p1 = mbuf->p2 = mbuf->p3 = mbuf->p4 = NULL; diff --git a/src/strlcpy.c b/src/strlcpy.c index dc67290..6f9682a 100644 --- a/src/strlcpy.c +++ b/src/strlcpy.c @@ -1,6 +1,6 @@ #include -size_t uc_strlcpy(char *dst, const char *src, size_t max) +size_t uc_strlcpy(char *restrict dst, const char *restrict src, size_t max) { size_t len = strlen(src); diff --git a/src/strvec.c b/src/strvec.c index 276a0be..1e9f00a 100644 --- a/src/strvec.c +++ b/src/strvec.c @@ -36,7 +36,7 @@ int uc_strv_check_expand(struct UCStrv *strv) return rc; } -int uc_strv_append(struct UCStrv *strv, const char *str) +int uc_strv_append(struct UCStrv *strv, const char *restrict str) { int rc; char *dup; @@ -57,7 +57,7 @@ int uc_strv_append(struct UCStrv *strv, const char *str) return 0; } -int uc_strv_append_nocopy(struct UCStrv *strv, char *str) +int uc_strv_append_nocopy(struct UCStrv *strv, char *restrict str) { int rc; rc = uc_strv_check_expand(strv); @@ -105,7 +105,7 @@ void uc_strv_destroy(struct UCStrv *strv) strv->strings = NULL; } -int uc_strv_append_all(struct UCStrv *a, struct UCStrv *b, int copy) +int uc_strv_append_all(struct UCStrv *restrict a, struct UCStrv *restrict b, int copy) { size_t i; int rc; diff --git a/src/val_str.c b/src/val_str.c index 4ff0fe0..ea92321 100644 --- a/src/val_str.c +++ b/src/val_str.c @@ -47,7 +47,7 @@ const char *uc_val_2_str_bs(unsigned int val, return found; } -const char *uc_str_2_str(const char *val, const struct UCStrStr *array) +const char *uc_str_2_str(const char *restrict val, const struct UCStrStr *array) { const char *found = NULL; From 2c264a76b4df914aa97734a69db8da41c8723f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 18 Jun 2014 15:57:51 +0200 Subject: [PATCH 27/55] Add init method to dstr for initializing directyl from a string Change the api so _put_ functions that copy in data are named "_append_" instead. --- include/ucore/dstr.h | 20 ++++++++++++++++---- src/dstr.c | 27 ++++++++++++++++++++------- test/test_dstr.c | 37 ++++++++++++++++++++++++++++--------- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/include/ucore/dstr.h b/include/ucore/dstr.h index e71c397..2057fc6 100644 --- a/include/ucore/dstr.h +++ b/include/ucore/dstr.h @@ -35,6 +35,18 @@ struct DStr { */ void uc_dstr_init(struct DStr *str); +/** Initialize a DStr from an existing string + * + * @return 0 on success (!= 0 if an allocation fail) + */ +int uc_dstr_init_str(struct DStr *str, const char *init); + +/** Initialize a DStr from an existing string with a given length + * + * @return 0 on success (!= 0 if an allocation fail) + */ +int uc_dstr_init_str_sz(struct DStr *str, const char *init, size_t len); + /** Destroy/free the string. * (Frees str->str, not str itself) */ @@ -95,7 +107,7 @@ char *uc_dstr_put(struct DStr *str, size_t len); * @param is_x ctype.h compatible function to use as a filter. * @return number of chars appended */ -size_t uc_dstr_put_str_filter(struct DStr *str, const char *restrict s, int (*is_x)(int c)); +size_t uc_dstr_append_str_filter(struct DStr *str, const char *restrict s, int (*is_x)(int c)); /* Append a string of the give size. * (The nul terminator is not appended) @@ -104,20 +116,20 @@ size_t uc_dstr_put_str_filter(struct DStr *str, const char *restrict s, int (*is * @param len bytes to append (not including the nul terminator) * @return 0 on success (!= 0 if an allocation fail) */ -int uc_dstr_put_str_sz(struct DStr *str, const char *restrict s, size_t len); +int uc_dstr_append_str_sz(struct DStr *str, const char *restrict s, size_t len); /* Append a string. * (The nul terminator is not appended) * * @return 0 on success (!= 0 if an allocation fail) */ -int uc_dstr_put_str(struct DStr *str, const char *restrict s); +int uc_dstr_append_str(struct DStr *str, const char *restrict s); /* Append a single char. * * @return 0 on success (!= 0 if an allocation fail) */ -int uc_dstr_put_char(struct DStr *str, char c); +int uc_dstr_append_char(struct DStr *str, char c); /* Make the DStr take ownership of the given dynamically allocated string. * Any existing string in the DStr is freed. diff --git a/src/dstr.c b/src/dstr.c index 99be0bc..90e49bc 100644 --- a/src/dstr.c +++ b/src/dstr.c @@ -12,6 +12,18 @@ void uc_dstr_init(struct DStr *str) str->str = NULL; } +int uc_dstr_init_str(struct DStr *str, const char *init) +{ + uc_dstr_init(str); + return uc_dstr_append_str(str, init); +} + +int uc_dstr_init_str_sz(struct DStr *str, const char *init, size_t len) +{ + uc_dstr_init(str); + return uc_dstr_append_str_sz(str, init, len); +} + void uc_dstr_destroy(struct DStr *str) { #ifdef DEBUG @@ -106,7 +118,7 @@ char *uc_dstr_put(struct DStr *str, size_t len) return start; } -size_t uc_dstr_put_str_filter(struct DStr *str, const char *restrict s, int (*is_x)(int c)) +size_t uc_dstr_append_str_filter(struct DStr *str, const char *restrict s, int (*is_x)(int c)) { size_t len = strlen(s); size_t i; @@ -128,7 +140,7 @@ size_t uc_dstr_put_str_filter(struct DStr *str, const char *restrict s, int (*is return idx; } -int uc_dstr_put_str_sz(struct DStr *str, const char *restrict s, size_t len) +int uc_dstr_append_str_sz(struct DStr *str, const char *restrict s, size_t len) { char *start = uc_dstr_put(str, len); @@ -140,14 +152,14 @@ int uc_dstr_put_str_sz(struct DStr *str, const char *restrict s, size_t len) return 0; } -int uc_dstr_put_str(struct DStr *str, const char *restrict s) +int uc_dstr_append_str(struct DStr *str, const char *restrict s) { size_t len = strlen(s); - return uc_dstr_put_str_sz(str, s ,len); + return uc_dstr_append_str_sz(str, s ,len); } -int uc_dstr_put_char(struct DStr *str, char c) +int uc_dstr_append_char(struct DStr *str, char c) { char *start = uc_dstr_put(str, 1); @@ -212,11 +224,12 @@ size_t uc_dstr_replace(struct DStr *str, char f, char r) void uc_dstr_trim(struct DStr *str) { size_t spaces; + static const char whitespace[] = " \t\n\v\f\r"; uc_dstr_terminate(str); //spaces at the start - spaces = strspn(str->str, " \t\n\v\f\r"); + spaces = strspn(str->str, whitespace); if (spaces > 0) { memmove(str->str, str->str + spaces, str->len - spaces); str->len -= spaces; @@ -226,7 +239,7 @@ void uc_dstr_trim(struct DStr *str) if (str->len > 0) { size_t idx = str->len - 1; do { - if (strchr(" \t\n\v\f\r", str->str[idx]) == NULL) { + if (strchr(whitespace, str->str[idx]) == NULL) { break; } else { str->len--; diff --git a/test/test_dstr.c b/test/test_dstr.c index 8637b89..38d24cf 100644 --- a/test/test_dstr.c +++ b/test/test_dstr.c @@ -12,17 +12,17 @@ START_TEST (test_dstr_basics) char *s; uc_dstr_init(&str); - rc = uc_dstr_put_str(&str, "Hello"); + rc = uc_dstr_append_str(&str, "Hello"); ck_assert_int_eq(rc, 0); ck_assert_int_eq(str.len, 5); ck_assert_str_eq(uc_dstr_str(&str), "Hello"); - rc = uc_dstr_put_char(&str, '!'); + rc = uc_dstr_append_char(&str, '!'); ck_assert_int_eq(rc, 0); ck_assert_int_eq(str.len, 6); ck_assert_str_eq(uc_dstr_str(&str), "Hello!"); - rc = uc_dstr_put_str_sz(&str, " World 12345678", 13); + rc = uc_dstr_append_str_sz(&str, " World 12345678", 13); ck_assert_int_eq(rc, 0); ck_assert_int_eq(str.len, 19); ck_assert_str_eq(uc_dstr_str(&str), "Hello! World 123456"); @@ -48,6 +48,24 @@ START_TEST (test_dstr_basics) uc_dstr_destroy(&str); END_TEST +START_TEST (test_dstr_init) + struct DStr str; + int rc; + + rc = uc_dstr_init_str(&str, "Hello"); + ck_assert_int_eq(rc, 0); + ck_assert_int_eq(str.len, 5); + ck_assert_str_eq(uc_dstr_str(&str), "Hello"); + + uc_dstr_destroy(&str); + + rc = uc_dstr_init_str_sz(&str, "Hello", 2); + ck_assert_int_eq(rc, 0); + ck_assert_int_eq(str.len, 2); + ck_assert_str_eq(uc_dstr_str(&str), "He"); + +END_TEST + START_TEST (test_dstr_own_steal) struct DStr str; char *s; @@ -69,14 +87,14 @@ END_TEST START_TEST (test_dstr_trim) struct DStr str = UC_DSTR_STATIC_INIT; - uc_dstr_put_str(&str, " \t \nHello !\r\n"); + uc_dstr_append_str(&str, " \t \nHello !\r\n"); uc_dstr_trim(&str); ck_assert_str_eq(uc_dstr_str(&str), "Hello !"); uc_dstr_destroy(&str); uc_dstr_init(&str); - uc_dstr_put_str(&str, " "); + uc_dstr_append_str(&str, " "); uc_dstr_trim(&str); ck_assert_str_eq(uc_dstr_str(&str), ""); @@ -96,7 +114,7 @@ START_TEST (test_dstr_replace) size_t rc; uc_dstr_init(&str); - uc_dstr_put_str(&str, "-1-2-3-4-5-"); + uc_dstr_append_str(&str, "-1-2-3-4-5-"); rc = uc_dstr_replace(&str, '-',' '); ck_assert_int_eq(rc, 6); @@ -114,8 +132,8 @@ START_TEST (test_dstr_filter) size_t rc; uc_dstr_init(&str); - uc_dstr_put_str(&str, "AB:"); - rc = uc_dstr_put_str_filter(&str, "1:2,3 4 ", isdigit); + uc_dstr_append_str(&str, "AB:"); + rc = uc_dstr_append_str_filter(&str, "1:2,3 4 ", isdigit); ck_assert_int_eq(rc, 4); ck_assert_str_eq(uc_dstr_str(&str), "AB:1234"); @@ -147,7 +165,7 @@ START_TEST (test_dstr_copy) size_t rc; uc_dstr_init(&str); - rc = uc_dstr_put_str(&str, "123"); + rc = uc_dstr_append_str(&str, "123"); ck_assert_int_eq(rc, 0); rc = uc_dstr_copy(©, &str); @@ -173,6 +191,7 @@ Suite *dstr_suite(void) Suite *s = suite_create("dstr"); TCase *tc = tcase_create("dstr tests"); tcase_add_test(tc, test_dstr_basics); + tcase_add_test(tc, test_dstr_init); tcase_add_test(tc, test_dstr_own_steal); tcase_add_test(tc, test_dstr_trim); tcase_add_test(tc, test_dstr_replace); From 2d1e7efc3ed86b8794714c36f3ff8a7895c56281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 22 Jun 2014 23:11:12 +0200 Subject: [PATCH 28/55] Add iomux_from_timers() function to recover an IOMux from the associated UCTimers --- include/ucore/iomux.h | 5 +++++ src/iomux_impl.c | 5 +++++ src/iomux_impl.h | 2 +- test/udp_heartbeat.c | 5 +++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/ucore/iomux.h b/include/ucore/iomux.h index f5604fb..414ce21 100644 --- a/include/ucore/iomux.h +++ b/include/ucore/iomux.h @@ -132,6 +132,11 @@ int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd, unsigned int what */ struct UCTimers *iomux_get_timers(struct IOMux *mux); +/** Given an UCTimers associated with an IOMux, return the associated IOMux. + * (the UCTimers must previously been obtained from iomux_get_timers directly, + * or indirectly by the UCTimers provieded in a timer callback handler. + */ +struct IOMux *iomux_from_timers(struct UCTimers *timers); #ifdef __cplusplus } #endif diff --git a/src/iomux_impl.c b/src/iomux_impl.c index a1e52c2..bbb16bc 100644 --- a/src/iomux_impl.c +++ b/src/iomux_impl.c @@ -168,3 +168,8 @@ struct UCTimers *iomux_get_timers(struct IOMux *mux) return &mux->timers; } +struct IOMux *iomux_from_timers(struct UCTimers *timers) +{ + return (struct IOMux*)timers; //timers is the 1. member of IOMux +} + diff --git a/src/iomux_impl.h b/src/iomux_impl.h index 794c738..ea51873 100644 --- a/src/iomux_impl.h +++ b/src/iomux_impl.h @@ -29,7 +29,7 @@ struct IOMuxOps { }; struct IOMux { - /* TImer instance */ + /* TImer instance - must be the 1. member*/ struct UCTimers timers; /** diff --git a/test/udp_heartbeat.c b/test/udp_heartbeat.c index f33255f..3e73385 100644 --- a/test/udp_heartbeat.c +++ b/test/udp_heartbeat.c @@ -1,5 +1,6 @@ #define DEBUG #include +#include #include #include #include @@ -76,6 +77,7 @@ void peer_timer_cb(struct UCTimers *timers, struct UCTimer *timer) struct HBPeer *peer = UC_CONTAINER_OF(timer, struct HBPeer, timer); struct HBContext *ctx = timer->cookie_ptr; time_t now; + struct IOMux *mux; uc_timers_add(timers, timer, PEER_HB_MISS , 0); now = time(NULL); @@ -85,6 +87,9 @@ void peer_timer_cb(struct UCTimers *timers, struct UCTimer *timer) } peer_send(ctx, peer); + //jsut a small test of iomux_from_timers + mux = iomux_from_timers(timers); + assert(mux == ctx->mux); } void peer_add_addr(struct HBContext *ctx, const struct sockaddr_in *addr) From b680671d2abbd0f64da7067eefbcaa5fe9ec05c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 22 Jun 2014 23:11:54 +0200 Subject: [PATCH 29/55] Remove a TRACF() --- src/iomux_impl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/iomux_impl.c b/src/iomux_impl.c index bbb16bc..b21f072 100644 --- a/src/iomux_impl.c +++ b/src/iomux_impl.c @@ -96,7 +96,6 @@ int iomux_run(struct IOMux *mux) struct timeval *timeoutp; if (iomux_run_timers(mux, &timeout)) { - TRACEF("NULL\n"); timeoutp = &timeout; } else { timeoutp = NULL; From 930c90b6743bdf72a303ad5b3e1a34f0ce60cdb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 23 Jun 2014 02:09:56 +0200 Subject: [PATCH 30/55] Fix uninitialized return value in iomux_update_events --- src/iomux_impl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/iomux_impl.c b/src/iomux_impl.c index b21f072..6f60744 100644 --- a/src/iomux_impl.c +++ b/src/iomux_impl.c @@ -142,16 +142,14 @@ int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd) int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd, unsigned int what) { - int rc; + int rc = 0; assert(mux != NULL); assert(fd != NULL); assert(fd->callback != NULL); assert(fd->fd >= 0); if (fd->what != what) { - mux->ops.update_events_impl(mux, fd); - } else { - rc = 0; + rc = mux->ops.update_events_impl(mux, fd); } return rc; From 06ecc68ca79fec5380dccab69237f6049cd82cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 23 Jun 2014 02:14:20 +0200 Subject: [PATCH 31/55] Fix header guard in buffer.h --- include/ucore/buffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ucore/buffer.h b/include/ucore/buffer.h index aab45a1..8f81600 100644 --- a/include/ucore/buffer.h +++ b/include/ucore/buffer.h @@ -1,5 +1,5 @@ #ifndef UC_BUFFER_H_ -#define uc_BUFFER_H_ +#define UC_BUFFER_H_ #include From 723ca5dcfb59096bc9baa8084ebf8ceabb50a9d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 23 Jun 2014 02:15:26 +0200 Subject: [PATCH 32/55] Fix header guard in read_file.h --- include/ucore/read_file.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ucore/read_file.h b/include/ucore/read_file.h index 26e4987..e105b45 100644 --- a/include/ucore/read_file.h +++ b/include/ucore/read_file.h @@ -1,5 +1,5 @@ #ifndef UC_READ_FILE_H_ -#define UC_READ_FILE_H_y +#define UC_READ_FILE_H_ #include From d28288f048670805fd1b980507731e6d0339bcf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 23 Jun 2014 02:24:27 +0200 Subject: [PATCH 33/55] Get rid of clang warnings for UC_INLINE --- include/ucore/mbuf.h | 10 ++++++++-- include/ucore/pack.h | 11 +++++++++-- include/ucore/tailq.h | 10 ++++++++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/include/ucore/mbuf.h b/include/ucore/mbuf.h index 73dc17e..3972798 100644 --- a/include/ucore/mbuf.h +++ b/include/ucore/mbuf.h @@ -4,10 +4,16 @@ #include #include "tailq.h" +#ifndef UC_INLINE #ifdef __GNUC__ -# define UC_INLINE inline __attribute__((always_inline)) +# ifdef __clang__ +# define UC_INLINE inline __attribute__((always_inline)) +# else +# define UC_INLINE inline __attribute__((always_inline,flatten)) +# endif #else -# define UC_INLINE inline +# define UC_INLINE inline +#endif #endif enum UC_MBUF_FLAGS { diff --git a/include/ucore/pack.h b/include/ucore/pack.h index 658ed44..9160e01 100644 --- a/include/ucore/pack.h +++ b/include/ucore/pack.h @@ -2,10 +2,17 @@ #define UC_PACK_H_ #include + +#ifndef UC_INLINE #ifdef __GNUC__ -# define UC_INLINE inline __attribute__((always_inline)) +# ifdef __clang__ +# define UC_INLINE inline __attribute__((always_inline)) +# else +# define UC_INLINE inline __attribute__((always_inline,flatten)) +# endif #else -# define UC_INLINE inline +# define UC_INLINE inline +#endif #endif /** Functions for serializing/de-serializing integers to and from diff --git a/include/ucore/tailq.h b/include/ucore/tailq.h index 010fb8a..a4ebd6f 100644 --- a/include/ucore/tailq.h +++ b/include/ucore/tailq.h @@ -1,10 +1,16 @@ #ifndef UC_TAILQ_H_ #define UC_TAILQ_H_ +#ifndef UC_INLINE #ifdef __GNUC__ -#define UC_INLINE inline __attribute__((always_inline,flatten)) +# ifdef __clang__ +# define UC_INLINE inline __attribute__((always_inline)) +# else +# define UC_INLINE inline __attribute__((always_inline,flatten)) +# endif #else -#define UC_INLINE inline +# define UC_INLINE inline +#endif #endif /** * Doubly Linked List. From 06be01a708133d0af5f809e2359f7d6c749be8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 25 Jun 2014 16:48:42 +0200 Subject: [PATCH 34/55] pthread implementation of a ticket lock --- include/ucore/ticket_lock.h | 43 ++++++++++++++++++++++++++++++++ src/ticket_lock.c | 49 +++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 include/ucore/ticket_lock.h create mode 100644 src/ticket_lock.c diff --git a/include/ucore/ticket_lock.h b/include/ucore/ticket_lock.h new file mode 100644 index 0000000..abaf3f1 --- /dev/null +++ b/include/ucore/ticket_lock.h @@ -0,0 +1,43 @@ +#ifndef UC_TICKET_LOCK_H_ +#define UC_TICKET_LOCK_H_ + +#include + +/** An fair alternative to a bare pthread_mutex_t to prevent starvation*/ +struct UCTicketLock { + pthread_cond_t cond; + pthread_mutex_t mutex; + unsigned long queue_head, queue_tail; +}; + +/** Static initializer for an UCTicketLock. Use as e.g + * + * struct UCTicketLock my_lock = UC_TICKET_LOCK_INITIALIZER; + */ +#define UC_TICKET_LOCK_INITIALIZER { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,0, 0} + +/** Initialize a UCTicketLock. + * The default attributes for the pthread mutex and condition variable is used. + * + * @return 0 on success, errno value on failure +*/ +int uc_ticket_lock_init(struct UCTicketLock *lock); + +/** Initialize a UCTicketLock with attributes + * + * @param mattr attribute used for the mutex, or NULL + * @param cattr attribute used for the condition variable, or NULL + * + * @return 0 on success, errno value on failure +*/ +int uc_ticket_lock_init_ex(struct UCTicketLock *lock, pthread_mutexattr_t *mattr, pthread_condattr_t *cattr); + +/** Acquire the lock + */ +void uc_ticket_lock(struct UCTicketLock *lock); + +/** Release the lock + */ +void uc_ticket_unlock(struct UCTicketLock *lock); + +#endif diff --git a/src/ticket_lock.c b/src/ticket_lock.c new file mode 100644 index 0000000..b6b03f9 --- /dev/null +++ b/src/ticket_lock.c @@ -0,0 +1,49 @@ +#include +#include "ucore/ticket_lock.h" + +int uc_ticket_lock_init(struct UCTicketLock *lock) +{ + return uc_ticket_lock_init_ex(lock, NULL, NULL); +} + +int uc_ticket_lock_init_ex(struct UCTicketLock *lock, pthread_mutexattr_t *mattr, pthread_condattr_t *cattr) +{ + int rc; + lock->queue_head = 0; + lock->queue_tail = 0; + + rc = pthread_mutex_init(&lock->mutex, mattr); + assert(rc == 0); + if (rc != 0) { + return rc; + } + + rc = pthread_cond_init(&lock->cond, cattr); + if (rc != 0) { + pthread_mutex_destroy(&lock->mutex); + } + assert(rc == 0); + + return rc; +} + +void uc_ticket_lock(struct UCTicketLock *lock) +{ + unsigned long queue_me; + + pthread_mutex_lock(&lock->mutex); + queue_me = lock->queue_tail++; + while (queue_me != lock->queue_head) + { + pthread_cond_wait(&lock->cond, &lock->mutex); + } + pthread_mutex_unlock(&lock->mutex); +} + +void uc_ticket_unlock(struct UCTicketLock *lock) +{ + pthread_mutex_lock(&lock->mutex); + lock->queue_head++; + pthread_cond_broadcast(&lock->cond); + pthread_mutex_unlock(&lock->mutex); +} From 0a6ce86779bd86b81420b89f552548aedd1c1e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 25 Jun 2014 17:03:14 +0200 Subject: [PATCH 35/55] More comments on the ticket lock code --- include/ucore/ticket_lock.h | 4 +++- src/ticket_lock.c | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/ucore/ticket_lock.h b/include/ucore/ticket_lock.h index abaf3f1..f68c0a2 100644 --- a/include/ucore/ticket_lock.h +++ b/include/ucore/ticket_lock.h @@ -3,7 +3,9 @@ #include -/** An fair alternative to a bare pthread_mutex_t to prevent starvation*/ +/** An fair alternative to a bare pthread_mutex_t to prevent starvation. + * The members of UCTicketLock must never be accessed directly. + */ struct UCTicketLock { pthread_cond_t cond; pthread_mutex_t mutex; diff --git a/src/ticket_lock.c b/src/ticket_lock.c index b6b03f9..a5d5bfa 100644 --- a/src/ticket_lock.c +++ b/src/ticket_lock.c @@ -1,6 +1,13 @@ #include #include "ucore/ticket_lock.h" +//pthread implementation of http://en.wikipedia.org/wiki/Ticket_lock +//The underlying phtread mutex is not held while the lock is acquired. +//This will allow other threads to enqueue itself. +// +//The condition variable is needed to wake up threads waiting to acquire +//the lock instead of letting the system block on the pthread mutex while waiting. + int uc_ticket_lock_init(struct UCTicketLock *lock) { return uc_ticket_lock_init_ex(lock, NULL, NULL); From 32218b3dc72b880302263eb2f949d497393c2f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 25 Jun 2014 19:49:14 +0200 Subject: [PATCH 36/55] Add test for ticket locks --- test/test_runner.c | 4 ++- test/test_ticket_lock.c | 63 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 test/test_ticket_lock.c diff --git a/test/test_runner.c b/test/test_runner.c index fab9686..da30362 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -30,6 +30,7 @@ extern Suite *htable_suite(void); extern Suite *heapsort_suite(void); extern Suite *dstr_suite(void); extern Suite *val_str_suite(void); +extern Suite *ticket_lock_suite(void); static suite_func suites[] = { bitvec_suite, @@ -54,7 +55,8 @@ static suite_func suites[] = { threadqueue_suite, heapsort_suite, dstr_suite, - val_str_suite + val_str_suite, + ticket_lock_suite }; int diff --git a/test/test_ticket_lock.c b/test/test_ticket_lock.c new file mode 100644 index 0000000..9e53f82 --- /dev/null +++ b/test/test_ticket_lock.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include + +//this is intended more as an example +//verifying multithreaded locks requires a more formal approach + +static int g_counter; +static struct UCTicketLock lock; +struct ThreadArg { + int rounds; + pthread_t tid; +}; +static void *update_thread(void *arg) +{ + int i; + struct ThreadArg *targ = arg; + for (i = 0; i < targ->rounds; i++) { + uc_ticket_lock(&lock); + g_counter++; + uc_ticket_unlock(&lock); + } + + return NULL; +} + +#define NR_THREADS 5 + +START_TEST(test_ticket_lock1) + struct ThreadArg threads[NR_THREADS]; + int i; + printf("TICKET SUITE\n"); + + for (i = 0; i < NR_THREADS; i++) { + int rc; + threads[i].rounds = NR_THREADS - i; + rc = pthread_create(&threads[i].tid, NULL, update_thread, &threads[i]); + ck_assert_int_eq(0, rc); + } + + for (i = 0; i < NR_THREADS; i++) { + int rc; + + rc = pthread_join(threads[i].tid, NULL); + ck_assert_int_eq(0, rc); + } + + //should be sum of integers from 1 .. NR_THREADS + ck_assert_int_eq((NR_THREADS * (NR_THREADS + 1)) / 2, g_counter); + + +END_TEST + +Suite *ticket_lock_suite(void) +{ + Suite *s = suite_create("ticket_lock"); + TCase *tc = tcase_create("ticket_lock tests"); + tcase_add_test(tc, test_ticket_lock1); + suite_add_tcase(s, tc); + + return s; +} From 777a745428218d45b08e13c4190155c31a778cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 23 Jun 2014 22:58:27 +0200 Subject: [PATCH 37/55] Test heapsorting 1 element --- test/test_heapsort.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/test_heapsort.c b/test/test_heapsort.c index 9635e56..95c51ae 100644 --- a/test/test_heapsort.c +++ b/test/test_heapsort.c @@ -83,7 +83,7 @@ START_TEST (test_heapsort_even) {"2", 2}, }; - struct Stuff ordered[] = { + const struct Stuff ordered[] = { {"1", 1}, {"2", 2}, {"3", 3}, @@ -97,7 +97,7 @@ START_TEST (test_heapsort_even) fail_if(cmp_stuff_array(unordered, ordered, ARRAY_SIZE(unordered)) != 0); END_TEST -START_TEST (test_heapsort_zero) +START_TEST (test_heapsort_zero_one) struct Stuff unordered[] = { {"1", 1}, {"7", 7}, @@ -107,7 +107,7 @@ START_TEST (test_heapsort_zero) {"2", 2}, }; - struct Stuff same[] = { + const struct Stuff same[] = { {"1", 1}, {"7", 7}, {"3", 3}, @@ -123,6 +123,10 @@ START_TEST (test_heapsort_zero) uc_heapsort(unordered, ARRAY_SIZE(unordered), 0, cmp_stuff, swap_stuff, NULL); fail_if(cmp_stuff_array(unordered, same, ARRAY_SIZE(unordered)) != 0); + + uc_heapsort(unordered, 1, sizeof(struct Stuff), + cmp_stuff, swap_stuff, NULL); + fail_if(cmp_stuff_array(unordered, same, ARRAY_SIZE(unordered)) != 0); END_TEST Suite *heapsort_suite(void) @@ -131,7 +135,7 @@ Suite *heapsort_suite(void) TCase *tc = tcase_create("heapsort tests"); tcase_add_test(tc, test_heapsort_odd); tcase_add_test(tc, test_heapsort_even); - tcase_add_test(tc, test_heapsort_zero); + tcase_add_test(tc, test_heapsort_zero_one); suite_add_tcase(s, tc); From c949961e77f4068df61826079509eac85651a747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 25 Jun 2014 19:53:46 +0200 Subject: [PATCH 38/55] Add a sched_yeild in tocket lock test.. --- test/test_ticket_lock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_ticket_lock.c b/test/test_ticket_lock.c index 9e53f82..1bc857a 100644 --- a/test/test_ticket_lock.c +++ b/test/test_ticket_lock.c @@ -18,6 +18,7 @@ static void *update_thread(void *arg) struct ThreadArg *targ = arg; for (i = 0; i < targ->rounds; i++) { uc_ticket_lock(&lock); + sched_yield(); g_counter++; uc_ticket_unlock(&lock); } From f7c27648dcedfd4e3a336a0207bce2c5400fc8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 11 Jul 2014 16:27:36 +0200 Subject: [PATCH 39/55] Print error if no test cases are run --- test/test_runner.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_runner.c b/test/test_runner.c index da30362..c5cedb8 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -81,6 +81,7 @@ main (int argc, char *argv[]) } + int number_run; int number_failed = 0; size_t i; @@ -106,9 +107,12 @@ main (int argc, char *argv[]) srunner_run(sr, NULL, test_case, CK_VERBOSE); #endif } + number_run = srunner_ntests_run(sr); number_failed = srunner_ntests_failed (sr); srunner_free (sr); + if (!number_run) + puts("ERROR: no tests were run"); if (number_failed) printf("ERROR: %d tests failed\n", number_failed); From 225943aef70735fb28ad62561cced6b1e47d042e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 26 Aug 2014 21:38:09 +0200 Subject: [PATCH 40/55] Improve doxygen documentation. --- Doxyfile | 14 +++--- include/ucore/atomic.h | 3 +- include/ucore/bitvec.h | 17 ++++--- include/ucore/dbuf.h | 21 +++++---- include/ucore/dstr.h | 9 ++-- include/ucore/heapsort.h | 10 ++-- include/ucore/htable.h | 3 +- include/ucore/iomux_waker.h | 7 ++- include/ucore/logging.h | 3 +- include/ucore/mbuf.h | 63 ++++++++++++++----------- include/ucore/mersenne_twister.h | 2 +- include/ucore/pack.h | 3 +- include/ucore/rate_limit.h | 3 +- include/ucore/salloc.h | 3 +- include/ucore/saturating_math.h | 3 +- include/ucore/threadqueue.h | 81 ++++++++++++++++---------------- include/ucore/val_str.h | 6 +++ 17 files changed, 143 insertions(+), 108 deletions(-) diff --git a/Doxyfile b/Doxyfile index 2f3d864..fc825f1 100644 --- a/Doxyfile +++ b/Doxyfile @@ -61,7 +61,7 @@ OUTPUT_DIRECTORY = doc # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. -CREATE_SUBDIRS = YES +CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this @@ -106,7 +106,7 @@ ABBREVIATE_BRIEF = # Doxygen will generate a detailed section even if there is only a brief # description. -ALWAYS_DETAILED_SEC = NO +ALWAYS_DETAILED_SEC = YES # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those @@ -119,7 +119,7 @@ INLINE_INHERITED_MEMB = NO # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. -FULL_PATH_NAMES = NO +FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is @@ -128,7 +128,7 @@ FULL_PATH_NAMES = NO # If left blank the directory from which doxygen is run is used as the # path to strip. -STRIP_FROM_PATH = +STRIP_FROM_PATH = include # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells @@ -137,7 +137,7 @@ STRIP_FROM_PATH = # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = include # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system @@ -790,7 +790,7 @@ INLINE_SOURCES = NO # doxygen to hide any special comment blocks from generated source code # fragments. Normal C, C++ and Fortran comments will always remain visible. -STRIP_CODE_COMMENTS = YES +STRIP_CODE_COMMENTS = NO # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented @@ -1130,7 +1130,7 @@ GENERATE_TREEVIEW = YES # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. -ENUM_VALUES_PER_LINE = 4 +ENUM_VALUES_PER_LINE = 1 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree diff --git a/include/ucore/atomic.h b/include/ucore/atomic.h index bc105b9..84e34d5 100644 --- a/include/ucore/atomic.h +++ b/include/ucore/atomic.h @@ -1,7 +1,8 @@ #ifndef UC_ATOMIC_H_ #define UC_ATOMIC_H_ -/** Atomic functions (macros). The ptr argument must be a pointer to +/** @file + * Atomic functions (macros). The ptr argument must be a pointer to * an integer type. * For gcc, see http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/_005f_005fsync-Builtins.html */ diff --git a/include/ucore/bitvec.h b/include/ucore/bitvec.h index 06085b8..a3e224b 100644 --- a/include/ucore/bitvec.h +++ b/include/ucore/bitvec.h @@ -13,19 +13,22 @@ typedef unsigned long uc_bv_integer; struct UCBitVec { //storage for the bits uc_bv_integer *vec; - //length in bytes of the above vec. + //number of elements int the above vec. size_t vec_len; }; /** - * Evaluates the length required for a bitvec to store nbit bits. + * Evaluates the number of uc_bv_integer elements required for a bitvec to store nbit bits. */ #define UC_BV_LEN(nbits) ((nbits/(sizeof(uc_bv_integer)*CHAR_BIT)) + (nbits % (sizeof(uc_bv_integer)*CHAR_BIT) == 0 ? 0 : 1)) -/** - * Use as : +/** Initialize a bitvec with predefined backing array. + * The backing array element type must be uc_bv_integer + * Use as + * @code * uc_bv_integer v[10]; * struct UCBitVec v = BITVEC_STATIC_INIT(v); + * @endcode */ #define UC_BV_STATIC_INIT(vec_data)\ {\ @@ -47,13 +50,13 @@ void uc_bv_free(struct UCBitVec *v); //Note that accessing a bit beyond the nbits originally initialized //for the given bitvec is undedefined -/** Sets bit no. b */ +/** Sets bit number b */ void uc_bv_set_bit(struct UCBitVec *v,int b); -/** Clears bit no. b*/ +/** Clears bit number b*/ void uc_bv_clr_bit(struct UCBitVec *v,int b); -/** Gets the current value (0 or 1) of bit no. b*/ +/** Gets the current value (0 or 1) of bit number @b*/ int uc_bv_get_bit(const struct UCBitVec *v,int b); /** Sets all bits to zero */ diff --git a/include/ucore/dbuf.h b/include/ucore/dbuf.h index 4dc497c..8b39d30 100644 --- a/include/ucore/dbuf.h +++ b/include/ucore/dbuf.h @@ -6,37 +6,38 @@ extern "C" { #endif -/** +/** @file * dbuf is a generic buffer that will grow automatically. - * call buf_ensure() to reserve space, and don't write more data - * than you told buf_ensure() to reserve. + * call uc_buf_ensure() to reserve space, and don't write more data + * than you told uc_buf_ensure() to reserve. * * You write data to buf->end * When finished writing data * you call dbuf_added/( with the no. of bytes you've added. * - * You read data from buf->start, the buffer has dbuf_len() bytes of data - * When you've read and processed the data, call dbuf_take() + * You read data from buf->start, the buffer has uc_dbuf_len() bytes of data + * When you've read and processed the data, call uc_dbuf_take() * to indicate you're done with the data. * * typically(but add error checking) * @code * DBuf buf; - * dbuf_init(&buf,4096); + * uc_dbuf_init(&buf,4096); * for(;;) { - * dbuf_ensure(buf,4096); + * uc_dbuf_ensure(buf,4096); * size_t len = fread(buf,4096,1,f); - * dbuf_added(&buf,len); + * uc_dbuf_added(&buf,len); * char *end; - * while((end = memchr(buf.start,'\n',dbuf_len(&dbuf))) != NULL) { //look for a newline + * while((end = memchr(buf.start,'\n',uc_dbuf_len(&dbuf))) != NULL) { //look for a newline * ++end; * int linelen = end - buf.start; * process_line(buf.start,linelen); - * dbuf_take(&dbuf,linelen); + * uc_dbuf_take(&dbuf,linelen); * } * } * @endcode */ + typedef struct DBuf DBuf; struct DBuf { /** Start of user data */ diff --git a/include/ucore/dstr.h b/include/ucore/dstr.h index 2057fc6..1ee79ee 100644 --- a/include/ucore/dstr.h +++ b/include/ucore/dstr.h @@ -8,7 +8,7 @@ extern "C" { #endif -/** A managed C-string, using dynalically allocated memory for the string. +/** A managed C-string, using dynamically allocated memory for the string. * * The .str member might not always be nul terminated, * Normally, use uc_dstr_str() to retreive the managed string @@ -52,8 +52,11 @@ int uc_dstr_init_str_sz(struct DStr *str, const char *init, size_t len); */ void uc_dstr_destroy(struct DStr *str); -/** Copy a DStr - * +/** Copy a DStr. + * The @dest string should not be an initialized string since it will be + * initialized by uc_dstr_copy, and would cause a memory leak if it's already + * initialized. + * * @param dest destination string to copy to, must not contain an existing string * @param src DStr to copy * diff --git a/include/ucore/heapsort.h b/include/ucore/heapsort.h index fcaf426..fc18ead 100644 --- a/include/ucore/heapsort.h +++ b/include/ucore/heapsort.h @@ -6,13 +6,17 @@ #ifdef __cplusplus extern "C" { #endif -///compare function. Needs only to return < 0 if -//a is less tan b +/** Compare function. Needs only to return < 0 if +* a is less than b +*/ typedef int (*uc_hs_cmp)(const void *a, const void *b, void *cookie); -//swap function, must swap around element a and b +/** Swap function, Must swap around element a and b + */ typedef void (*uc_hs_swp)(void *a, void *b); /** Sort an array. + * As the name implies this sorts using the heapsort algorithm. + * * @param base start of array * @param count number of elements in array * @param width size of each element diff --git a/include/ucore/htable.h b/include/ucore/htable.h index 1702c5f..46e4168 100644 --- a/include/ucore/htable.h +++ b/include/ucore/htable.h @@ -3,7 +3,8 @@ #include -/** Building block for hash table. +/** @file + * Building block for hash table. * The hash table is stored using a chained list of buckets. * Nodes with different hash value can be stored in the same bucket. * diff --git a/include/ucore/iomux_waker.h b/include/ucore/iomux_waker.h index bf382e2..fa76048 100644 --- a/include/ucore/iomux_waker.h +++ b/include/ucore/iomux_waker.h @@ -15,16 +15,19 @@ struct IOMuxSignaller { int fd; }; -/** These are primitives to wake up an IOMux. +/** @file + * These are primitives to wake up an IOMux. * An IOMux event loop can be woken up from e.g. an unix signal handler * or another thread. The IOMuxWaker itself is not thread safe, it's members - * must not be accessed from anything other than the loop it's connected to. + * except for the signaller must not be accessed from anything other than the + * IOMux it's connected to. * Only uc_iomux_waker_signal() can be called from another thread/signal handler * than the IOMux it's connected to. * * Note that several signals to wake up a loop can get merged, the callback * handler can be called only once for several signals. */ + struct IOMuxWaker { //private fields struct IOMuxFD read_fd; diff --git a/include/ucore/logging.h b/include/ucore/logging.h index 3c19f7d..37234dd 100644 --- a/include/ucore/logging.h +++ b/include/ucore/logging.h @@ -2,7 +2,8 @@ #define UC_LOGGING_H_ #include "utils.h" -/** Logging functions. +/** @file + * Application logging framework. * All logging functions except uc_log_init are thread safe, * so logging can be performed from any thread after the logging * system have been initialized. diff --git a/include/ucore/mbuf.h b/include/ucore/mbuf.h index 3972798..27cc959 100644 --- a/include/ucore/mbuf.h +++ b/include/ucore/mbuf.h @@ -16,6 +16,41 @@ #endif #endif +/** @file + * mbuf - A managed message/memory buffer. + * + * Concept: + @verbatim + <--------- allocated -----------> + <--- len --> + +--------------------------------+ + |Headroom| Data |Tailroom | + +--------------------------------+ + ^ ^ ^ + | | | + | | tail + | head + bufstart + + @endverbatim + * + * Initially when empty, head == tail, and the length is 0. + * Data is added to the tail. + * + * If head == bufstart, there is no headroom + * if tail points one past the allocated space, there is no + * tailroom (the buffer is full) + * + * Conventions: + * push - prepend data to the buffer (in the head room part) + * (move head to the left) + * pull - remove data from the beginning of the message. + * (move head to the right) + * put - Add data to the buffer. + * (move tail to the right) + */ + +/** Flags used internally */ enum UC_MBUF_FLAGS { UC_MBUF_FL_MALLOC = 0x0001, //MBuf and MBuf->bufstart are seperatly malloc'd UC_MBUF_FL_MALLOC_BUF = 0x0001, //MBuf is not malloc'd. MBuf->bufstart is malloc'd @@ -51,34 +86,6 @@ struct MBuf { uint8_t inline_data[0]; }; -/** - * Concept: - * <--------- allocated -----------> - * <--- len --> - * +--------------------------------+ - * |Headroom| Data |Tailroom | - * +--------------------------------+ - * ^ ^ ^ - * | | | - * | | tail - * | head - * bufstart - * - * Initially when empty, head == tail, and the length is 0. - * Data is added to the tail. - * - * If head == bufstart, there is no headroom - * if tail points one past the allocated space, there is no - * tailroom (the buffer is full) - * - * Conventions: - * push - prepend data to the buffer (in the head room part) - * (move head to the left) - * pull - remove data from the beginning of the message. - * (move head to the right) - * put - Add data to the buffer. - * (move tail to the right) - */ /** Allocate an mbuf with a length and headroom, * the buffer will have the flag UC_MBUF_FL_MALLOC diff --git a/include/ucore/mersenne_twister.h b/include/ucore/mersenne_twister.h index b2604e1..748d097 100644 --- a/include/ucore/mersenne_twister.h +++ b/include/ucore/mersenne_twister.h @@ -5,8 +5,8 @@ extern "C" { #endif -/** Context used for the PRNG*/ #define MT_RAND_N 624 +/** Context used for the PRNG*/ typedef struct { unsigned int x[MT_RAND_N]; int i; diff --git a/include/ucore/pack.h b/include/ucore/pack.h index 9160e01..6553b7e 100644 --- a/include/ucore/pack.h +++ b/include/ucore/pack.h @@ -15,7 +15,8 @@ #endif #endif -/** Functions for serializing/de-serializing integers to and from +/** @file + * Functions for serializing/de-serializing integers to and from * byte arrays. * These functions are independant of the host endian. Only * thing to care about is the endian format of the data in diff --git a/include/ucore/rate_limit.h b/include/ucore/rate_limit.h index 367aae9..fdcb656 100644 --- a/include/ucore/rate_limit.h +++ b/include/ucore/rate_limit.h @@ -1,7 +1,8 @@ #ifndef UC_RATE_LIMIT_H_ #define UC_RATE_LIMIT_H_ -/** This is a rate limiter, based on the token bucket principle. +/** @file + * This is a rate limiter, based on the token bucket principle. * We have X amount of tickets(=our rate) per Y amount of time, * * The allowed tickets increases with X per Y amount of time. diff --git a/include/ucore/salloc.h b/include/ucore/salloc.h index d9f5d44..ca336d3 100644 --- a/include/ucore/salloc.h +++ b/include/ucore/salloc.h @@ -6,7 +6,8 @@ #ifdef __cplusplus extern "C" { #endif -/** Sequntial memory allocator +/** @file + * Sequntial memory allocator * * Allocates bigger chunks of memory at a time, to save the amount of malloc call, * and enables you to free all that memory in one sweep. diff --git a/include/ucore/saturating_math.h b/include/ucore/saturating_math.h index 4ef5ff0..6b9228f 100644 --- a/include/ucore/saturating_math.h +++ b/include/ucore/saturating_math.h @@ -2,7 +2,8 @@ #define UC_SATMATH_H_ #include -/** Implementation of saturated operation on uintxx_t. +/** @file + * Implementation of saturated operation on uintxx_t. * * Operations are clamped between 0 and UINTxx_MAX instead of * wrapping around. diff --git a/include/ucore/threadqueue.h b/include/ucore/threadqueue.h index dd189d1..eacf9ab 100644 --- a/include/ucore/threadqueue.h +++ b/include/ucore/threadqueue.h @@ -12,7 +12,47 @@ extern "C" { * * Little API for waitable queues, typically used for passing messages * between threads. + * + * The uc_thread_queue_ functions only deal with struct uc_threadmsg + * structs. + * In order for the message passing to be useful, more data needs to be + * associated with a message, it's up to the application to manage this. + * One way is to e.g. add the struct uc_threadmsg as the first member + * of a larger struct, and recover the larger struct after getting a + * struct uc_threadmsg out of the queue. e.g. + * + * @code + * struct my_msg { + * struct uc_threadmsg tmsg; + * int foo; + * char bar[32]; + * }; + * + * struct my_msg *msg = malloc(sizeof *msg); + * msg->tmsg.msgtype = MSGTYP1; + * ... + * uc_thread_queue_add(queue, &msg->tmsg); + * + * The receiver end does e.g. + * + * struct uc_threadmsg *tmsg; + * uc_thread_queue_get(queue, NULL, &tmsg); + * switch(tmsg->msgtype) { + * case MYMSG1; { + * struct my_msg *msg = (struct my_msg*)tmsg; + * ... + * free(msg); + * break + * ... + * } + * } + * + * @endcode + * + * As such, a struct uc_threadmsg must live as long as it resides in a thread queue, + * and must be removed from the queue before the struct uc_threadmsg is destroyed/deallocated. * + * * @author Nils O. SelĂ„sdal */ @@ -55,45 +95,6 @@ typedef void (*uc_thread_queue_walk_func) (struct uc_threadmsg *msg, void *cooki * the variables in this struct. * You have been warned. * - * The uc_thread_queue_ functions only deal with struct uc_threadmsg - * structs. - * In order for the message passing to be useful, more data needs to be - * associated with a message, it's up to the application to manage this. - * One way is to e.g. add the struct uc_threadmsg as the first member - * of a larger struct, and recover the larger struct after getting a - * struct uc_threadmsg out of the queue. e.g. - * - * @code - * struct my_msg { - * struct uc_threadmsg tmsg; - * int foo; - * char bar[32]; - * }; - * - * struct my_msg *msg = malloc(sizeof *msg); - * msg->tmsg.msgtype = MSGTYP1; - * ... - * uc_thread_queue_add(queue, &msg->tmsg); - * - * The receiver end does e.g. - * - * struct uc_threadmsg *tmsg; - * uc_thread_queue_get(queue, NULL, &tmsg); - * switch(tmsg->msgtype) { - * case MYMSG1; { - * struct my_msg *msg = (struct my_msg*)tmsg; - * ... - * free(msg); - * break - * ... - * } - * } - * - * @endcode - * - * - * - * */ struct uc_threadqueue { /** @@ -137,7 +138,7 @@ struct uc_threadqueue { * thread_queue_init initializes a new threadqueue. A new queue must always * be initialized before it is used. * A max number of elements the queue will hold must be given. - * Adding more elements than a queue will hold will e.g. cause + * Adding more elements than a queue will hold will cause * uc_thread_queue_add to block until space becomes available. * * @param queue Pointer to the queue that should be initialized diff --git a/include/ucore/val_str.h b/include/ucore/val_str.h index 9ee6cae..a724439 100644 --- a/include/ucore/val_str.h +++ b/include/ucore/val_str.h @@ -3,11 +3,17 @@ #include +/** @file + * Utility functions to map integers to strings and strings to strings. + */ + +/** Mapping from an unsigned int to a string*/ struct UCValStr { unsigned int val; const char *str; }; +/** Mapping from a string to another string*/ struct UCStrStr { const char *val; const char *str; From 44ecb1ea7a9110f1f12fa4808e3b7ccd9c2b89f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 26 Aug 2014 20:12:22 +0200 Subject: [PATCH 41/55] Fix confusing if vec_len is bytes or number of elements --- src/bitvec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitvec.c b/src/bitvec.c index edb6cc3..8286d36 100644 --- a/src/bitvec.c +++ b/src/bitvec.c @@ -1,4 +1,5 @@ #include +#include #include #include #include "ucore/bitvec.h" @@ -68,6 +69,7 @@ void uc_bv_set_bits_from_array(struct UCBitVec *v,char *array,size_t array_len) for (i = 0; i < array_len; i++) { size_t idx = (size_t)bit_index(array_len); + if (unlikely(idx >= v->vec_len)) break; From db0d62c639492ca4a557aa4568b0f664343300fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 1 Sep 2014 22:19:54 +0200 Subject: [PATCH 42/55] Add ATOMIC_GET --- include/ucore/atomic.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/ucore/atomic.h b/include/ucore/atomic.h index 84e34d5..bb9194d 100644 --- a/include/ucore/atomic.h +++ b/include/ucore/atomic.h @@ -34,6 +34,11 @@ */ #define UC_ATOMIC_INC(ptr) UC_ATOMIC_ADD((ptr), 1) +/** + * Atomically get the value of *ptr + * @return value of *ptr + */ +#define UC_ATOMIC_GET(ptr) UC_ATOMIC_ADD((ptr), 0) /** * Atomic Compare-And-Swap. If *ptr is oldval, write newwal to *ptr. From e45be1a3625f1c7518d05d7f4064ee33db91f99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 1 Sep 2014 22:20:10 +0200 Subject: [PATCH 43/55] eait for max 32 epoll events. 54 is too much --- src/iomux_epoll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iomux_epoll.c b/src/iomux_epoll.c index 586b5f0..0b023ef 100644 --- a/src/iomux_epoll.c +++ b/src/iomux_epoll.c @@ -12,7 +12,7 @@ ///we do not use edge triggered mode //number of events we wait for in one go -#define EPOLL_WAIT_EVENTS (64) +#define EPOLL_WAIT_EVENTS (32) struct IOMuxEpoll { //number of file descriptors we're watching From ba79566ce9043b30301189cf6205c5e7082ccace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 2 Sep 2014 23:17:14 +0200 Subject: [PATCH 44/55] Better atomic support for gcc and clang --- include/ucore/atomic.h | 92 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 10 deletions(-) diff --git a/include/ucore/atomic.h b/include/ucore/atomic.h index bb9194d..ca5495b 100644 --- a/include/ucore/atomic.h +++ b/include/ucore/atomic.h @@ -3,59 +3,131 @@ /** @file * Atomic functions (macros). The ptr argument must be a pointer to - * an integer type. + * an UC_ATOMIC(integer type) * For gcc, see http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/_005f_005fsync-Builtins.html */ +#ifdef DOXYGEN -#ifdef __GNUC__ +/** + * Define an atomic type. + * e.g UC_ATOMIC(int) foo; + */ +#define UC_ATOMIC(type) /** * Atomically subtract val from *ptr * @return *ptr before the subtraction */ -#define UC_ATOMIC_SUB(ptr, val) __sync_fetch_and_add((ptr), -(val)) +#define UC_ATOMIC_SUB(ptr, val) /** * Atomically add val to *ptr * @return *ptr before the addition */ -#define UC_ATOMIC_ADD(ptr, val) __sync_fetch_and_add((ptr), (val)) - +#define UC_ATOMIC_ADD(ptr, val) /** * Atomically decrement *ptr * @return *ptr before the decrement */ -#define UC_ATOMIC_DEC(ptr) UC_ATOMIC_SUB((ptr), 1) +#define UC_ATOMIC_DEC(ptr) /** * Atomically increment *ptr * @return *ptr before the increment */ -#define UC_ATOMIC_INC(ptr) UC_ATOMIC_ADD((ptr), 1) +#define UC_ATOMIC_INC(ptr) /** * Atomically get the value of *ptr * @return value of *ptr */ -#define UC_ATOMIC_GET(ptr) UC_ATOMIC_ADD((ptr), 0) +#define UC_ATOMIC_GET(ptr) /** * Atomic Compare-And-Swap. If *ptr is oldval, write newwal to *ptr. * @return *ptr that was before the operation. */ -#define UC_ATOMIC_CAS(ptr, oldval, newval) __sync_val_compare_and_swap((ptr), (oldval), (newval)) +#define UC_ATOMIC_CAS(ptr, oldval, newval) /** Issue a full (hardware) memory barrier. * preventing the cpu to move load/stores across * the barrier. (This implies a compiler barrier as well) * */ -#define UC_MEM_BARRIER() __sync_synchronize() +#define UC_MEM_BARRIER() /** Issue a full compiler/software only memory barrier * preventing compiler optimization to move load/stores across * the barrier. * */ +#define UC_COMPILER_BARRIER() + +/* clang with atomic extensions */ +#elif __clang__ + +/* clang defines 0 to be memory_order_relaxed and 5 to be memory_order_seq_cst */ +#define UC_ORDER_RELAXED 0 +#define UC_ORDER_CST 5 + +#define UC_ATOMIC(type) _Atomic(type) + +#define UC_ATOMIC_SUB(ptr, val) __c11_atomic_fetch_sub((ptr), (val), UC_ORDER_CST) + +#define UC_ATOMIC_ADD(ptr, val) __c11_atomic_fetch_add((ptr), (val), UC_ORDER_CST) + +#define UC_ATOMIC_DEC(ptr) UC_ATOMIC_SUB((ptr), 1) + +#define UC_ATOMIC_INC(ptr) UC_ATOMIC_ADD((ptr), 1) + +#define UC_ATOMIC_GET(ptr) __c11_atomic_load((ptr), UC_ORDER_CST) + +#define UC_ATOMIC_CAS(ptr, oldval, newval) __atomic_compare_exchange((ptr), (oldval), (newval),0, UC_ORDER_CST, UC_ORDER_CST) + +#define UC_MEM_BARRIER() __c11_atomic_thread_fence(UC_ORDER_CST) + +#define UC_COMPILER_BARRIER() __asm__ __volatile__("": : :"memory") + +/* gcc 4.7 or later */ +#elif __GNUC_ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) + +#define UC_ATOMIC(type) type + +#define UC_ATOMIC_SUB(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) + +#define UC_ATOMIC_ADD(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) + +#define UC_ATOMIC_DEC(ptr) UC_ATOMIC_SUB((ptr), 1) + +#define UC_ATOMIC_INC(ptr) UC_ATOMIC_ADD((ptr), 1) + +#define UC_ATOMIC_GET(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) + +#define UC_ATOMIC_CAS(ptr, oldval, newval) __atomic_compare_exchange((ptr), (oldval), (newval),0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) + +#define UC_MEM_BARRIER() __atomic_thread_fence(__ATOMIC_SEQ_CST) + +#define UC_COMPILER_BARRIER() __asm__ __volatile__("": : :"memory") + + +/* Earlier gcc versions */ +#elif __GNUC__ + +#define UC_ATOMIC(type) type + +#define UC_ATOMIC_SUB(ptr, val) __sync_fetch_and_sub((ptr), (val)) + +#define UC_ATOMIC_ADD(ptr, val) __sync_fetch_and_add((ptr), (val)) + +#define UC_ATOMIC_DEC(ptr) UC_ATOMIC_SUB((ptr), 1) + +#define UC_ATOMIC_INC(ptr) UC_ATOMIC_ADD((ptr), 1) + +#define UC_ATOMIC_GET(ptr) UC_ATOMIC_ADD((ptr), 0) + +#define UC_ATOMIC_CAS(ptr, oldval, newval) __sync_val_compare_and_swap((ptr), (oldval), (newval)) + +#define UC_MEM_BARRIER() __sync_synchronize() + #define UC_COMPILER_BARRIER() __asm__ __volatile__("": : :"memory") #else From 8763059c65b8e32493c777a7a3f170c214a7f2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 2 Sep 2014 23:17:41 +0200 Subject: [PATCH 45/55] Atomic example, used to inspect assembly code.. --- test/atomic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 test/atomic.c diff --git a/test/atomic.c b/test/atomic.c new file mode 100644 index 0000000..6232ae0 --- /dev/null +++ b/test/atomic.c @@ -0,0 +1,50 @@ +#include "ucore/atomic.h" +UC_ATOMIC(unsigned int) i; + + +unsigned int get_i(void) +{ + return UC_ATOMIC_GET(&i); +} + +unsigned int inc_i(void) +{ + return UC_ATOMIC_INC(&i); +} + +unsigned int dec_i(void) +{ + return UC_ATOMIC_DEC(&i); +} + +unsigned int sub_i(unsigned int v) +{ + return UC_ATOMIC_SUB(&i, v); +} + +unsigned int add_i(unsigned int v) +{ + return UC_ATOMIC_ADD(&i, v); +} + +unsigned int get_i_membar() +{ + unsigned int r; + UC_MEM_BARRIER(); + r = i; + UC_MEM_BARRIER(); + + return r; +} + +unsigned int get_i_compbar() +{ + unsigned int r; + UC_COMPILER_BARRIER(); + r = i; + UC_COMPILER_BARRIER(); + + return r; +} + + From e18317d507e6e537ba3f03873e284197b86b9cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sat, 6 Sep 2014 04:03:20 +0200 Subject: [PATCH 46/55] fix UC_ROUND_UP() --- include/ucore/utils.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/ucore/utils.h b/include/ucore/utils.h index 70e5ca9..4a3e199 100644 --- a/include/ucore/utils.h +++ b/include/ucore/utils.h @@ -95,20 +95,24 @@ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \ #define UC_DIV_ROUND_UP(x, y) (((x) + ((y) - 1))/(y)) /** - * Round x down to nearest multiple of y + * Round x up to nearest multiple of y + * e.g. UC_ROUND_UP(30,48) == 48 + * e.g. UC_ROUND_UP(49,48) == 96 * * @param x numerator, must be positive * @param y denominator - * @return x rounded to nearest multiple of y + * @return x rounded up to nearest multiple of y */ -#define UC_ROUND_UP(x, y) (((x) / (y)) * (y)) +#define UC_ROUND_UP(x, y) (UC_DIV_ROUND_UP(x, y) * (y)) /** * Round x down to nearest multiple of y + * e.g. UC_ROUND_UP(30,48) == 0 + * e.g. UC_ROUND_UP(49,48) == 48 * * @param x numerator, must be positive * @param y denominator - * @return x rounded to nearest multiple of y + * @return x rounded down nearest multiple of y */ #define UC_ROUND_DOWN(x, y) ((x) / (y) * (y)) From d75d0ee48cfe84a31f67730771dc73b98eb51279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sat, 6 Sep 2014 04:05:54 +0200 Subject: [PATCH 47/55] ( ) around macro arguments.. --- include/ucore/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ucore/utils.h b/include/ucore/utils.h index 4a3e199..44511ff 100644 --- a/include/ucore/utils.h +++ b/include/ucore/utils.h @@ -103,7 +103,7 @@ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \ * @param y denominator * @return x rounded up to nearest multiple of y */ -#define UC_ROUND_UP(x, y) (UC_DIV_ROUND_UP(x, y) * (y)) +#define UC_ROUND_UP(x, y) (UC_DIV_ROUND_UP((x), (y)) * (y)) /** * Round x down to nearest multiple of y From 267451f37fe18c3ea4e454ae2f9e06affb1c9f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 8 Sep 2014 22:24:08 +0200 Subject: [PATCH 48/55] Fix RATE_LIMIT_INITIALIZER --- include/ucore/rate_limit.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ucore/rate_limit.h b/include/ucore/rate_limit.h index fdcb656..f3b4038 100644 --- a/include/ucore/rate_limit.h +++ b/include/ucore/rate_limit.h @@ -71,8 +71,8 @@ struct RateLimit { * @param tickets number of tickets (bucket depth) * @param period per this period */ -#define UC_RATELIMIT_INITIALIZER(tickets)\ -{ tickets, period, 0, -period} +#define UC_RATELIMIT_INITIALIZER(tickets, period)\ +{ (tickets,) (period), 0, -(period)} From 52feeb66446ce18bc48761152224a39e072254f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 10 Sep 2014 23:55:33 +0200 Subject: [PATCH 49/55] Add a few more UCStrVal functions --- include/ucore/val_str.h | 25 +++++++++++++++++++++++-- src/val_str.c | 31 +++++++++++++++++++++++++++++++ test/test_val_str.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/include/ucore/val_str.h b/include/ucore/val_str.h index a724439..ad126d1 100644 --- a/include/ucore/val_str.h +++ b/include/ucore/val_str.h @@ -24,7 +24,7 @@ struct UCStrStr { #define UC_VS_TERMINATOR {-1, NULL} #define UC_SS_TERMINATOR {NULL, NULL} -/** find @val in @array. +/** Find @val in @array. * the last .str in @array must be a null pointer. * (does a linear search) * @@ -34,6 +34,17 @@ struct UCStrStr { */ const char *uc_val_2_str(unsigned int val, const struct UCValStr *array); + +/** Find @val in @array. + * the last .str in @array must be a null pointer. + * (does a linear search) + * + * @param val value to find + * @param array array to search + * @return The found struct UCValStr, which will be the last senitel + * in the array if no match was found + */ +const struct UCValStr *uc_val_2_str_vs(unsigned int val, const struct UCValStr *array); /** Find @val in @array. * @array must be sorted on val and must not be empty * (does a binary search) @@ -46,7 +57,7 @@ const char *uc_val_2_str_bs(unsigned int val, const struct UCValStr *array, size_t array_len); -/** find @val in @array. +/** Find @val in @array. * the last .val in @array must be a null pointer. * (does a linear search) * @@ -56,4 +67,14 @@ const char *uc_val_2_str_bs(unsigned int val, */ const char *uc_str_2_str(const char *restrict val, const struct UCStrStr *array); +/** Find @val in @array, case insensitive + * the last .val in @array must be a null pointer. + * (does a linear search) + * + * @param val value to find, using strcasecmp + * @param array array to search + * @return the string associated with @val or null + */ +const char *uc_str_2_str_ci(const char *restrict val, const struct UCStrStr *array); + #endif diff --git a/src/val_str.c b/src/val_str.c index ea92321..a0faf3e 100644 --- a/src/val_str.c +++ b/src/val_str.c @@ -19,6 +19,21 @@ const char *uc_val_2_str(unsigned int val, const struct UCValStr *array) return found; } +const struct UCValStr *uc_val_2_str_vs(unsigned int val, const struct UCValStr *array) +{ + const struct UCValStr *found = NULL; + + while (array->str) { + if (array->val == val) { + found = array; + break; + } + array++; + } + + return found; +} + const char *uc_val_2_str_bs(unsigned int val, const struct UCValStr *array, size_t array_len) @@ -62,3 +77,19 @@ const char *uc_str_2_str(const char *restrict val, const struct UCStrStr *array) return found; } +const char *uc_str_2_str_ci(const char *restrict val, const struct UCStrStr *array) +{ + const char *found = NULL; + + while (array->val) { + if (strcasecmp(val, array->val) == 0) { + found = array->str; + break; + } + array++; + } + + return found; +} + + diff --git a/test/test_val_str.c b/test/test_val_str.c index fb104bd..d62cbdc 100644 --- a/test/test_val_str.c +++ b/test/test_val_str.c @@ -16,6 +16,20 @@ START_TEST (test_val_str_search) fail_if(uc_val_2_str(10, vals) != NULL); END_TEST +START_TEST (test_val_str_vs_search) + struct UCValStr vals[] = { + UC_VS_ENTRY(1), + UC_VS_ENTRY(5), + UC_VS_ENTRY(0), + UC_VS_TERMINATOR + }; + ck_assert_str_eq(uc_val_2_str_vs(0 , vals)->str , "0"); + ck_assert_str_eq(uc_val_2_str_vs(1 , vals)->str , "1"); + ck_assert_str_eq(uc_val_2_str_vs(5 , vals)->str , "5"); + + fail_if(uc_val_2_str(10, vals) != NULL); +END_TEST + START_TEST (test_val_str_bsearch_odd) struct UCValStr vals[] = { UC_VS_ENTRY(1), @@ -70,15 +84,30 @@ START_TEST (test_str_str_search) fail_if(uc_str_2_str("10", vals) != NULL); END_TEST +START_TEST (test_str_str_ci_search) + struct UCStrStr vals[] = { + {"A", "1"}, + {"az","2"}, + {"C", "3"}, + UC_SS_TERMINATOR + }; + ck_assert_str_eq(uc_str_2_str_ci("a" , vals) , "1"); + ck_assert_str_eq(uc_str_2_str_ci("aZ" , vals) ,"2"); + ck_assert_str_eq(uc_str_2_str_ci("C" , vals) , "3"); + + fail_if(uc_str_2_str_ci("aza", vals) != NULL); +END_TEST Suite *val_str_suite(void) { Suite *s = suite_create("valstr"); TCase *tc = tcase_create("valstr tests"); tcase_add_test(tc, test_val_str_search); + tcase_add_test(tc, test_val_str_vs_search); tcase_add_test(tc, test_val_str_bsearch_odd); tcase_add_test(tc, test_val_str_bsearch_even); tcase_add_test(tc, test_str_str_search); + tcase_add_test(tc, test_str_str_ci_search); suite_add_tcase(s, tc); From b783d67f6ddbfb0c21467e656037f0e97e099511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 10 Sep 2014 23:58:15 +0200 Subject: [PATCH 50/55] Remove unused include --- src/val_str.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/val_str.c b/src/val_str.c index a0faf3e..59c34f3 100644 --- a/src/val_str.c +++ b/src/val_str.c @@ -1,8 +1,6 @@ #include #include #include "ucore/val_str.h" -#include "ucore/saturating_math.h" - const char *uc_val_2_str(unsigned int val, const struct UCValStr *array) { From 37a0411fbad71524034b5392459a6809b97daf2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 11 Sep 2014 21:40:22 +0200 Subject: [PATCH 51/55] Initialize the ticket lock --- test/test_ticket_lock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_ticket_lock.c b/test/test_ticket_lock.c index 1bc857a..e8b895e 100644 --- a/test/test_ticket_lock.c +++ b/test/test_ticket_lock.c @@ -31,7 +31,9 @@ static void *update_thread(void *arg) START_TEST(test_ticket_lock1) struct ThreadArg threads[NR_THREADS]; int i; - printf("TICKET SUITE\n"); + int lrc; + lrc = uc_ticket_lock_init(&lock); + ck_assert_int_eq(lrc, 0); for (i = 0; i < NR_THREADS; i++) { int rc; From c3e46ce788771e9f8848c91e76417b5fa8db65ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 11 Sep 2014 21:41:14 +0200 Subject: [PATCH 52/55] Add uc_restart_counter concept --- include/ucore/restart_counter.h | 81 +++++++++++++++++ src/restart_counter.c | 100 +++++++++++++++++++++ test/test_restart_file.c | 154 ++++++++++++++++++++++++++++++++ test/test_runner.c | 4 +- 4 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 include/ucore/restart_counter.h create mode 100644 src/restart_counter.c create mode 100644 test/test_restart_file.c diff --git a/include/ucore/restart_counter.h b/include/ucore/restart_counter.h new file mode 100644 index 0000000..806251e --- /dev/null +++ b/include/ucore/restart_counter.h @@ -0,0 +1,81 @@ +#ifndef UC_RESTART_COUNTER_H_ +#define UC_RESTART_COUNTER_H_ +/** @file + * Simple support for keeping track of number of restarts. + * + * Certain protocols desire support for comminicating the number + * of times an entity has restarted. + * The counter might also serve as a seed for sequence number generation + * to minimize recycling a recently used sequence number. + * + * The number of times a process has been restarted is simply kept + * track of via a counter in a restart state ile in ascii representation. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct UCRestartCounter { + unsigned int counter; + int fd; +}; + +typedef enum { + UC_RC_OK, + /** accessing the file failed, inspect errno + * for more info */ + UC_RC_ERR_FILE_ACCESS_ERROR, + /* The file existed and is opened but + * no valid number could be read from the file. + * This is a transient error, + * the now new counter is initialized to 0, and + * written to the file */ + UC_RC_ERR_FILE_CONTENT_ERROR, + /* UC_RC_FL_LOCK_FILE was specified but the file + * is already locked by some other process */ + UC_RC_ERR_FILE_LOCKED, + /** unspecified error. Inspect errno. */ + UC_RC_ERR_UNSPECIFIED, + /** Given by uc_restart_counter_close if the + * file never was opened */ + UC_RC_ERR_NOT_OPENED, +} UCRCResult; + +/** Lock the restart state file and keep it open. + * e.g. to prevent several processes from being started + * and using the same restart state file.*/ +#define UC_RC_FL_LOCK_FILE ( 1 << 0) + +/** Read and update the current restart counter. + * This is typically called once at program startup. + * + * @param counter the counter to initialize + * @param filename the filename to use to keep track of the state + * @param flags one of UC_RC_FL_XX + */ +UCRCResult uc_restart_counter_init( + struct UCRestartCounter *counter, + const char *filename, + unsigned int flags); + +/** Close the current restart counter file if it was opened with the + * UC_RC_FL_LOCK_FILE flag. + * + * @counter counter file to close. (uc_restart_counter can still be called + * after * the file is closed) + * @return UC_RC_OK or if the file was not kept open with UC_RC_ERR_FILE_LOCKED + */ +UCRCResult uc_restart_counter_close(struct UCRestartCounter *counter); + +/** Get the current restart counter. + * In case uc_restart_counter_init failed, this will return 0. + */ +unsigned int uc_restart_counter_get(const struct UCRestartCounter *counter); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/restart_counter.c b/src/restart_counter.c new file mode 100644 index 0000000..958ade5 --- /dev/null +++ b/src/restart_counter.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include "ucore/restart_counter.h" + +static UCRCResult uc_restart_counter_lock(int fd) +{ + int rc = lockf(fd, F_TLOCK, 0); + + if (rc == -1 && (errno == EACCES || errno == EAGAIN)) { + return UC_RC_ERR_FILE_LOCKED; + } else if (rc == -1) { + return UC_RC_ERR_UNSPECIFIED; + } + + return UC_RC_OK; +} + +UCRCResult uc_restart_counter_init( + struct UCRestartCounter *counter, + const char *filename, + unsigned int flags) +{ + int fd; + UCRCResult rc = UC_RC_OK; + char buf[64]; + ssize_t n; + + counter->counter = 0; + counter->fd = -1; + + fd = open(filename, O_CREAT|O_RDWR, 0600); + + if (fd == -1) { + return UC_RC_ERR_FILE_ACCESS_ERROR; + } + if (flags & UC_RC_FL_LOCK_FILE) { + rc = uc_restart_counter_lock(fd); + if (rc != UC_RC_OK) { + close(fd); + return rc; + } + counter->fd = fd; + } + + buf[0] = 0; + n = read(fd, buf, sizeof buf - 1); + if (n > 0) { + buf[n] = 0; + if (sscanf(buf, "%u", &counter->counter) == 1) { + counter->counter++; + rc = UC_RC_OK; + } else { + rc = UC_RC_ERR_FILE_CONTENT_ERROR; + } + + + if (lseek(fd, 0, SEEK_SET) != 0 || + ftruncate(fd,0) != 0) { + rc = UC_RC_ERR_UNSPECIFIED; + } + + + } else if (n < 0) { + rc = UC_RC_ERR_FILE_ACCESS_ERROR; + } //if n is 0, we act as we created the file for the 1. time + + snprintf(buf, sizeof buf, "%u\n", counter->counter); + n = strlen(buf); + if (write(fd, buf, n) != n) { + rc = UC_RC_ERR_UNSPECIFIED; + } + + if ((flags & UC_RC_FL_LOCK_FILE) == 0) { + close(fd); + } + + return rc; +} + +UCRCResult uc_restart_counter_close(struct UCRestartCounter *counter) +{ + if (counter->fd < 0) { + return UC_RC_ERR_NOT_OPENED; + } + + close(counter->fd); //also releases the lock + counter->fd = -1; + + return UC_RC_OK; +} + +unsigned int uc_restart_counter_get(const struct UCRestartCounter *counter) +{ + return counter->counter; +} diff --git a/test/test_restart_file.c b/test/test_restart_file.c new file mode 100644 index 0000000..14792b6 --- /dev/null +++ b/test/test_restart_file.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ucore/restart_counter.h" + +#define FILE_NAME "restart_counter_test" +//Note that these tests are comewhat fragile as they depend on the +//file sizes that are created, which depends on the (relative)paths of this file. +//for cleaning the created log files.. +static void logging_rm_files(void) +{ + remove(FILE_NAME); +} + + +START_TEST (test_restart_counter) + + UCRCResult rc; + struct UCRestartCounter cnt; + + rc = uc_restart_counter_init(&cnt, FILE_NAME, 0); + fail_if(rc != UC_RC_OK); + ck_assert_uint_eq(0, uc_restart_counter_get(&cnt)); + + rc = uc_restart_counter_init(&cnt, FILE_NAME, 0); + fail_if(rc != UC_RC_OK); + + ck_assert_uint_eq(1, uc_restart_counter_get(&cnt)); + +END_TEST + +START_TEST (test_restart_counter_existing) + + UCRCResult rc; + struct UCRestartCounter cnt; + + FILE *f = fopen(FILE_NAME, "w"); + fail_if(f == NULL); + fputs("99999\n", f); + fclose(f); + + + rc = uc_restart_counter_init(&cnt, FILE_NAME, 0); + fail_if(rc != UC_RC_OK); + ck_assert_uint_eq(100000, uc_restart_counter_get(&cnt)); + +END_TEST + +START_TEST (test_restart_counter_inaccessible_file) + + UCRCResult rc; + struct UCRestartCounter cnt; + + rc = uc_restart_counter_init(&cnt, "/should/not/exist/abc", 0); + fail_if(rc != UC_RC_ERR_FILE_ACCESS_ERROR); + +END_TEST +START_TEST (test_restart_counter_garble) + + UCRCResult rc; + struct UCRestartCounter cnt; + FILE *f = fopen(FILE_NAME, "w"); + fail_if(f == NULL); + fputs("Q123456789\n\n\n", f); + fclose(f); + + rc = uc_restart_counter_init(&cnt, FILE_NAME, 0); + fail_if(rc != UC_RC_ERR_FILE_CONTENT_ERROR); + ck_assert_uint_eq(0, uc_restart_counter_get(&cnt)); + + rc = uc_restart_counter_init(&cnt, FILE_NAME, 0); + fail_if(rc != UC_RC_OK, "%d", rc); + ck_assert_uint_eq(1, uc_restart_counter_get(&cnt)); + +END_TEST + +START_TEST (test_restart_counter_full_filesystem) + + UCRCResult rc; + struct UCRestartCounter cnt; + + rc = uc_restart_counter_init(&cnt, "/dev/full", 0); + fail_if(rc != UC_RC_ERR_UNSPECIFIED); + +END_TEST + +START_TEST (test_restart_counter_lock_file) + + UCRCResult rc; + struct UCRestartCounter cnt; + sem_t *sem; + sem = mmap(NULL, 2 * sysconf(_SC_PAGESIZE), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,-1,0); + fail_if(sem == NULL); + + fail_if(sem_init(&sem[0], 1 , 0) != 0); + fail_if(sem_init(&sem[1], 1 , 0) != 0); + + rc = uc_restart_counter_init(&cnt, FILE_NAME, UC_RC_FL_LOCK_FILE); + fail_if(rc != UC_RC_OK); + ck_assert_uint_eq(0, uc_restart_counter_get(&cnt)); + rc = uc_restart_counter_close(&cnt); + fail_if(rc != UC_RC_OK); + rc = uc_restart_counter_close(&cnt); + fail_if(rc != UC_RC_ERR_NOT_OPENED); + + pid_t pid = fork(); + fail_if(pid < 0); + + if (pid > 0) { + sem_wait(&sem[0]); + rc = uc_restart_counter_init(&cnt, FILE_NAME, UC_RC_FL_LOCK_FILE); + sem_post(&sem[1]); + printf("rc = %d\n", rc); + fail_if(rc != UC_RC_ERR_FILE_LOCKED); + ck_assert_uint_eq(0, uc_restart_counter_get(&cnt)); + } else { + uc_restart_counter_init(&cnt, FILE_NAME, UC_RC_FL_LOCK_FILE); + sem_post(&sem[0]); + sem_wait(&sem[1]); + _exit(0); + } + +END_TEST + + +Suite *restart_counter_suite(void) +{ + Suite *s = suite_create("restart_counter"); + TCase *tc1 = tcase_create("restart_counter"); + + tcase_add_test(tc1, test_restart_counter); + tcase_add_test(tc1, test_restart_counter_existing); + tcase_add_test(tc1, test_restart_counter_inaccessible_file); + tcase_add_test(tc1, test_restart_counter_garble); + if (access("/dev/full", R_OK) == 0) { + tcase_add_test(tc1, test_restart_counter_full_filesystem); + } else { + puts("Cannot access /dev/full. Not testing test_logfile_full_filesystem"); + } + + tcase_add_test(tc1, test_restart_counter_lock_file); + tcase_add_checked_fixture(tc1, logging_rm_files, logging_rm_files); + + suite_add_tcase(s, tc1); + + return s; +} + diff --git a/test/test_runner.c b/test/test_runner.c index c5cedb8..33b1ad4 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -31,6 +31,7 @@ extern Suite *heapsort_suite(void); extern Suite *dstr_suite(void); extern Suite *val_str_suite(void); extern Suite *ticket_lock_suite(void); +extern Suite *restart_counter_suite(void); static suite_func suites[] = { bitvec_suite, @@ -56,7 +57,8 @@ static suite_func suites[] = { heapsort_suite, dstr_suite, val_str_suite, - ticket_lock_suite + ticket_lock_suite, + restart_counter_suite }; int From 1f83ec6741dfe4721f390e3ced717705ee6a75be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 11 Sep 2014 21:42:57 +0200 Subject: [PATCH 53/55] Link with libm and librt, required for older glibc. No harm on newer --- test/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SConscript b/test/SConscript index 911dc9d..30a17fa 100644 --- a/test/SConscript +++ b/test/SConscript @@ -4,7 +4,7 @@ Import('env', 'build_type', 'prefix', 'lib_suffix', 'version_info', 'test_xml') test_env = env.Clone() test_env.Append(LIBPATH = ['#build/src']); -test_env.Append(LIBS = ['ucore' + lib_suffix, 'check']) +test_env.Append(LIBS = ['ucore' + lib_suffix, 'check','m','rt']) system = platform.system() From 0588af093a14b73343195e27ca4c666a6c4ca8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 11 Sep 2014 21:55:57 +0200 Subject: [PATCH 54/55] Fic includes to use "" instead of <> --- test/backtrace.c | 2 +- test/iomux_test.c | 2 +- test/iomux_test2.c | 2 +- test/iomux_test3.c | 2 +- test/iomux_wake.c | 4 ++-- test/logging.c | 4 ++-- test/ortp-send-simple.c | 6 +++--- test/phi.c | 2 +- test/salloc_vg.c | 2 +- test/seq.c | 2 +- test/tailq_example.c | 4 ++-- test/test_bcd.c | 2 +- test/test_bitvec.c | 2 +- test/test_buffer.c | 2 +- test/test_clock.c | 2 +- test/test_containerof.c | 2 +- test/test_dbuf.c | 2 +- test/test_dstr.c | 4 ++-- test/test_heapsort.c | 4 ++-- test/test_hex.c | 2 +- test/test_htable.c | 4 ++-- test/test_human_bytesz.c | 2 +- test/test_logging.c | 2 +- test/test_mbuf.c | 2 +- test/test_pack.c | 2 +- test/test_ratelimit.c | 2 +- test/test_read_file.c | 2 +- test/test_sat_math.c | 2 +- test/test_seq.c | 2 +- test/test_sprintb.c | 2 +- test/test_strv.c | 2 +- test/test_threadqueue.c | 2 +- test/test_ticket_lock.c | 2 +- test/test_timers.c | 6 +++--- test/test_val_str.c | 2 +- test/threadqueue.c | 2 +- test/threadqueue_signal.c | 2 +- test/timers.c | 4 ++-- test/udp_heartbeat.c | 12 ++++++------ 39 files changed, 55 insertions(+), 55 deletions(-) diff --git a/test/backtrace.c b/test/backtrace.c index c68eecd..6e09012 100644 --- a/test/backtrace.c +++ b/test/backtrace.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/backtrace.h" //note , compiling this without -rdynamic does not //translate addresses to function names. Use the addr2line in that case diff --git a/test/iomux_test.c b/test/iomux_test.c index 1c39a8c..d9f53d0 100644 --- a/test/iomux_test.c +++ b/test/iomux_test.c @@ -1,6 +1,6 @@ #include #include -#include +#include "ucore/iomux.h" extern struct IOMuxFD s_fd; diff --git a/test/iomux_test2.c b/test/iomux_test2.c index a94afe1..22aae17 100644 --- a/test/iomux_test2.c +++ b/test/iomux_test2.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include "ucore/iomux.h" extern struct IOMuxFD s_fd; diff --git a/test/iomux_test3.c b/test/iomux_test3.c index 3008480..86c0fa0 100644 --- a/test/iomux_test3.c +++ b/test/iomux_test3.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include "ucore/iomux.h" #define BUFLEN (4098*66) diff --git a/test/iomux_wake.c b/test/iomux_wake.c index 31c7535..8c2d3d3 100644 --- a/test/iomux_wake.c +++ b/test/iomux_wake.c @@ -3,8 +3,8 @@ #include #include #include -#include -#include +#include "ucore/iomux.h" +#include "ucore/iomux_waker.h" pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static int counter = 0; diff --git a/test/logging.c b/test/logging.c index fe4be1c..a083807 100644 --- a/test/logging.c +++ b/test/logging.c @@ -1,5 +1,5 @@ -#include -#include +#include "ucore/logging.h" +#include "ucore/utils.h" #include enum { MAIN, diff --git a/test/ortp-send-simple.c b/test/ortp-send-simple.c index 681a038..1fc9079 100644 --- a/test/ortp-send-simple.c +++ b/test/ortp-send-simple.c @@ -3,9 +3,9 @@ #include #include #include -#include -#include -#include +#include "ucore/iomux.h" +#include "ucore/utils.h" +#include "ucore/string.h" struct IOMux *mux; diff --git a/test/phi.c b/test/phi.c index 648a18d..e7c4c1b 100644 --- a/test/phi.c +++ b/test/phi.c @@ -1,6 +1,6 @@ #include #include -#include +#include "ucore/math.h" int main(int argc, char *argv[]) { diff --git a/test/salloc_vg.c b/test/salloc_vg.c index ebd2b28..aca96cd 100644 --- a/test/salloc_vg.c +++ b/test/salloc_vg.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/salloc.h" // Intended to be run under valgrind. Should show no errors diff --git a/test/seq.c b/test/seq.c index 5750ef0..e63375b 100644 --- a/test/seq.c +++ b/test/seq.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/seq.h" void check_before(uint32_t a, uint32_t b) diff --git a/test/tailq_example.c b/test/tailq_example.c index e91609f..9da4ffd 100644 --- a/test/tailq_example.c +++ b/test/tailq_example.c @@ -1,8 +1,8 @@ #include #include #include -#include -#include +#include "ucore/tailq.h" +#include "ucore/utils.h" struct Block { char text[64]; diff --git a/test/test_bcd.c b/test/test_bcd.c index 96dc6fb..96c24ba 100644 --- a/test/test_bcd.c +++ b/test/test_bcd.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/string.h" START_TEST (test_2bcd_1234567890) diff --git a/test/test_bitvec.c b/test/test_bitvec.c index d1a0a6b..df461e5 100644 --- a/test/test_bitvec.c +++ b/test/test_bitvec.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/bitvec.h" START_TEST (test_bitvec_1) diff --git a/test/test_buffer.c b/test/test_buffer.c index 63a58e1..fceaeb0 100644 --- a/test/test_buffer.c +++ b/test/test_buffer.c @@ -1,6 +1,6 @@ #include #include -#include +#include "ucore/buffer.h" START_TEST (test_new_gbuf) diff --git a/test/test_clock.c b/test/test_clock.c index 407d0f1..2d06d54 100644 --- a/test/test_clock.c +++ b/test/test_clock.c @@ -1,6 +1,6 @@ #include #include -#include +#include "ucore/clock.h" START_TEST (test_settable_clock) diff --git a/test/test_containerof.c b/test/test_containerof.c index b0cc868..351bd50 100644 --- a/test/test_containerof.c +++ b/test/test_containerof.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/utils.h" struct Inner { diff --git a/test/test_dbuf.c b/test/test_dbuf.c index 923b781..d0b6bc1 100644 --- a/test/test_dbuf.c +++ b/test/test_dbuf.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include "ucore/dbuf.h" START_TEST (test_dbuf) diff --git a/test/test_dstr.c b/test/test_dstr.c index 38d24cf..ff9cc33 100644 --- a/test/test_dstr.c +++ b/test/test_dstr.c @@ -1,8 +1,8 @@ #include #include #include -#include -#include +#include "ucore/dstr.h" +#include "ucore/utils.h" START_TEST (test_dstr_basics) diff --git a/test/test_heapsort.c b/test/test_heapsort.c index 95c51ae..0f23e10 100644 --- a/test/test_heapsort.c +++ b/test/test_heapsort.c @@ -1,6 +1,6 @@ #include -#include -#include +#include "ucore/utils.h" +#include "ucore/heapsort.h" struct Stuff { char text[11]; diff --git a/test/test_hex.c b/test/test_hex.c index 1c6fa2a..1e60b6c 100644 --- a/test/test_hex.c +++ b/test/test_hex.c @@ -1,6 +1,6 @@ #include #include -#include +#include "ucore/string.h" START_TEST (test_uc_hex_encode_1) diff --git a/test/test_htable.c b/test/test_htable.c index 61a6889..c5a5add 100644 --- a/test/test_htable.c +++ b/test/test_htable.c @@ -1,7 +1,7 @@ #include #include -#include -#include +#include "ucore/htable.h" +#include "ucore/utils.h" struct MyString { char str[32]; diff --git a/test/test_human_bytesz.c b/test/test_human_bytesz.c index 9a1d760..832155b 100644 --- a/test/test_human_bytesz.c +++ b/test/test_human_bytesz.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/string.h" START_TEST (test_human_bytesz_bytes) diff --git a/test/test_logging.c b/test/test_logging.c index f91150a..14a2ffc 100644 --- a/test/test_logging.c +++ b/test/test_logging.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include "ucore/logging.h" #define FILE_NAME "logfile_test.log" #define SUBDIR "log_subdir" diff --git a/test/test_mbuf.c b/test/test_mbuf.c index 4a3e5b3..598779a 100644 --- a/test/test_mbuf.c +++ b/test/test_mbuf.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include "ucore/mbuf.h" START_TEST (test_mbuf_new) diff --git a/test/test_pack.c b/test/test_pack.c index 1115370..02336ab 100644 --- a/test/test_pack.c +++ b/test/test_pack.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/pack.h" START_TEST (test_pack16_le_1) diff --git a/test/test_ratelimit.c b/test/test_ratelimit.c index 0b09753..0fb4f2c 100644 --- a/test/test_ratelimit.c +++ b/test/test_ratelimit.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/rate_limit.h" START_TEST (test_ratelimit_1) diff --git a/test/test_read_file.c b/test/test_read_file.c index dcd8d68..bcb9347 100644 --- a/test/test_read_file.c +++ b/test/test_read_file.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include "ucore/read_file.h" START_TEST (test_read_file_non_existing_file) diff --git a/test/test_sat_math.c b/test/test_sat_math.c index 1fcaa67..da55529 100644 --- a/test/test_sat_math.c +++ b/test/test_sat_math.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/saturating_math.h" START_TEST (test_sat_uc_addu8) diff --git a/test/test_seq.c b/test/test_seq.c index 054a6c7..8fc068e 100644 --- a/test/test_seq.c +++ b/test/test_seq.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/seq.h" START_TEST (test_uc_seq_lt) diff --git a/test/test_sprintb.c b/test/test_sprintb.c index 0a1f782..c6fef06 100644 --- a/test/test_sprintb.c +++ b/test/test_sprintb.c @@ -1,6 +1,6 @@ #include #include -#include +#include "ucore/string.h" //Note these tests assume // char 8 bit diff --git a/test/test_strv.c b/test/test_strv.c index 3d172da..b9100b4 100644 --- a/test/test_strv.c +++ b/test/test_strv.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include "ucore/strvec.h" START_TEST (test_strv_append) diff --git a/test/test_threadqueue.c b/test/test_threadqueue.c index 2cd7d6d..b08792c 100644 --- a/test/test_threadqueue.c +++ b/test/test_threadqueue.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include "ucore/threadqueue.h" struct thr_msg { struct uc_threadmsg msg; diff --git a/test/test_ticket_lock.c b/test/test_ticket_lock.c index e8b895e..6287e5c 100644 --- a/test/test_ticket_lock.c +++ b/test/test_ticket_lock.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include "ucore/ticket_lock.h" //this is intended more as an example //verifying multithreaded locks requires a more formal approach diff --git a/test/test_timers.c b/test/test_timers.c index b6cdf5f..36e5f31 100644 --- a/test/test_timers.c +++ b/test/test_timers.c @@ -1,7 +1,7 @@ #include -#include -#include -#include +#include "ucore/timers.h" +#include "ucore/timers.h" +#include "ucore/clock.h" struct TimerTest { int cnt; diff --git a/test/test_val_str.c b/test/test_val_str.c index d62cbdc..4474482 100644 --- a/test/test_val_str.c +++ b/test/test_val_str.c @@ -1,5 +1,5 @@ #include -#include +#include "ucore/val_str.h" START_TEST (test_val_str_search) diff --git a/test/threadqueue.c b/test/threadqueue.c index 15a41bf..85b322d 100644 --- a/test/threadqueue.c +++ b/test/threadqueue.c @@ -1,6 +1,6 @@ #include #include -#include +#include "ucore/threadqueue.h" struct uc_threadqueue queue; diff --git a/test/threadqueue_signal.c b/test/threadqueue_signal.c index b956521..169b7ae 100644 --- a/test/threadqueue_signal.c +++ b/test/threadqueue_signal.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include "ucore/threadqueue.h" struct uc_threadqueue queue; diff --git a/test/timers.c b/test/timers.c index 9ff5af9..e2a1bbe 100644 --- a/test/timers.c +++ b/test/timers.c @@ -1,8 +1,8 @@ #include #include #include -#include -#include +#include "ucore/timers.h" +#include "ucore/utils.h" struct MyStruct { diff --git a/test/udp_heartbeat.c b/test/udp_heartbeat.c index 3e73385..66bb717 100644 --- a/test/udp_heartbeat.c +++ b/test/udp_heartbeat.c @@ -13,12 +13,12 @@ #include #include #include -#include -#include -#include -#include -#include -#include +#include "ucore/logging.h" +#include "ucore/logging.h" +#include "ucore/iomux.h" +#include "ucore/utils.h" +#include "ucore/pack.h" +#include "ucore/tailq.h" #define HB_MAGIX 0xBEA7BEA7 From 1ec9cb38cb51b9a11e5a1a01617efbf9e578d62d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 11 Sep 2014 23:09:41 +0200 Subject: [PATCH 55/55] Open restart file in 0644 mode, fsync the file, don't write to file if seek/truncate failed --- src/restart_counter.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/restart_counter.c b/src/restart_counter.c index 958ade5..b785844 100644 --- a/src/restart_counter.c +++ b/src/restart_counter.c @@ -33,7 +33,7 @@ UCRCResult uc_restart_counter_init( counter->counter = 0; counter->fd = -1; - fd = open(filename, O_CREAT|O_RDWR, 0600); + fd = open(filename, O_CREAT|O_RDWR, 0644); if (fd == -1) { return UC_RC_ERR_FILE_ACCESS_ERROR; @@ -62,6 +62,7 @@ UCRCResult uc_restart_counter_init( if (lseek(fd, 0, SEEK_SET) != 0 || ftruncate(fd,0) != 0) { rc = UC_RC_ERR_UNSPECIFIED; + goto done; } @@ -75,6 +76,9 @@ UCRCResult uc_restart_counter_init( rc = UC_RC_ERR_UNSPECIFIED; } + fsync(fd); + +done: if ((flags & UC_RC_FL_LOCK_FILE) == 0) { close(fd); }