diff --git a/common/devdoc/refcount_requirements.md b/common/devdoc/refcount_requirements.md index eb64f06..192937a 100644 --- a/common/devdoc/refcount_requirements.md +++ b/common/devdoc/refcount_requirements.md @@ -13,14 +13,25 @@ It wraps the structure that needs to be ref counted into another structure that #define REFCOUNT_TYPE_CREATE_WITH_EXTRA_SIZE(type, size) MU_C2(REFCOUNT_SHORT_TYPE(type), _Create_With_Extra_Size)(size) #define REFCOUNT_TYPE_DESTROY(type, var) MU_C2(REFCOUNT_SHORT_TYPE(type), _Destroy)(var) -#define DEFINE_REFCOUNT_TYPE(type) \ +#define INC_REF(type, var) interlocked_increment(&((REFCOUNT_TYPE(type)*)((unsigned char*)var - offsetof(REFCOUNT_TYPE(type), counted)))->count) +#define DEC_REF(type, var) interlocked_decrement(&((REFCOUNT_TYPE(type)*)((unsigned char*)var - offsetof(REFCOUNT_TYPE(type), counted)))->count) +#define INIT_REF(type, var) interlocked_exchange(&((REFCOUNT_TYPE(type)*)((unsigned char*)var - offsetof(REFCOUNT_TYPE(type), counted)))->count, 1) + +#define DEFINE_REFCOUNT_TYPE(type, malloc_func, free_func) \ ... ``` ### DEFINE_REFCOUNT_TYPE +```c +#define DEFINE_REFCOUNT_TYPE(type, malloc_func, free_func) \ +... +``` + **SRS_REFCOUNT_01_001: [** `DEFINE_REFCOUNT_TYPE` shall define the create/create_with_Extra_size/destroy functions for the type `type`. **]** +**SRS_REFCOUNT_01_010: [** Memory allocation/free shall be performed by using the functions `malloc_func` and `free_func`. **]** + ### REFCOUNT_TYPE_CREATE ```c diff --git a/common/inc/azure_c_pal/refcount.h b/common/inc/azure_c_pal/refcount.h index d85bbad..7aa02e5 100644 --- a/common/inc/azure_c_pal/refcount.h +++ b/common/inc/azure_c_pal/refcount.h @@ -55,10 +55,11 @@ MU_C2(REFCOUNT_, type) /* Codes_SRS_REFCOUNT_01_005: [ REFCOUNT_TYPE_CREATE_WITH_EXTRA_SIZE shall allocate memory for the type that is ref counted (type) plus extra memory enough to hold size bytes. ]*/ /* Codes_SRS_REFCOUNT_01_006: [ On success it shall return a non-NULL handle to the allocated ref counted type type. ]*/ /* Codes_SRS_REFCOUNT_01_007: [ If any error occurs, REFCOUNT_TYPE_CREATE_WITH_EXTRA_SIZE shall return NULL. ]*/ -#define DEFINE_CREATE_WITH_EXTRA_SIZE(type) \ +#define DEFINE_CREATE_WITH_EXTRA_SIZE(type, malloc_func) \ static type* REFCOUNT_TYPE_DECLARE_CREATE_WITH_EXTRA_SIZE(type)(size_t size) \ { \ - REFCOUNT_TYPE(type)* ref_counted = (REFCOUNT_TYPE(type)*)malloc(sizeof(REFCOUNT_TYPE(type)) + size); \ + /* Codes_SRS_REFCOUNT_01_010: [ Memory allocation/free shall be performed by using the functions malloc_func and free_func. ]*/ \ + REFCOUNT_TYPE(type)* ref_counted = (REFCOUNT_TYPE(type)*)malloc_func(sizeof(REFCOUNT_TYPE(type)) + size); \ type* result; \ if (ref_counted == NULL) \ { \ @@ -75,7 +76,7 @@ static type* REFCOUNT_TYPE_DECLARE_CREATE_WITH_EXTRA_SIZE(type)(size_t size) \ /* Codes_SRS_REFCOUNT_01_002: [ REFCOUNT_TYPE_CREATE shall allocate memory for the type that is ref counted. ]*/ /* Codes_SRS_REFCOUNT_01_003: [ On success it shall return a non-NULL handle to the allocated ref counted type type. ]*/ /* Codes_SRS_REFCOUNT_01_004: [ If any error occurs, REFCOUNT_TYPE_CREATE shall return NULL. ]*/ -#define DEFINE_CREATE(type) \ +#define DEFINE_CREATE(type, malloc_func) \ static type* REFCOUNT_TYPE_DECLARE_CREATE(type) (void) \ { \ return REFCOUNT_TYPE_DECLARE_CREATE_WITH_EXTRA_SIZE(type)(0); \ @@ -83,23 +84,24 @@ static type* REFCOUNT_TYPE_DECLARE_CREATE(type) (void) \ /* Codes_SRS_REFCOUNT_01_008: [ REFCOUNT_TYPE_DESTROY shall free the memory allocated by REFCOUNT_TYPE_CREATE or REFCOUNT_TYPE_CREATE_WITH_EXTRA_SIZE. ]*/ /* Codes_SRS_REFCOUNT_01_009: [ If counted_type is NULL, REFCOUNT_TYPE_DESTROY shall return. ]*/ -#define DEFINE_DESTROY(type) \ +#define DEFINE_DESTROY(type, free_func) \ static void REFCOUNT_TYPE_DECLARE_DESTROY(type)(type* counted_type) \ { \ void* ref_counted = (void*)((unsigned char*)counted_type - offsetof(REFCOUNT_TYPE(type), counted)); \ - free(ref_counted); \ + /* Codes_SRS_REFCOUNT_01_010: [ Memory allocation/free shall be performed by using the functions malloc_func and free_func. ]*/ \ + free_func(ref_counted); \ } /* Codes_SRS_REFCOUNT_01_001: [ DEFINE_REFCOUNT_TYPE shall define the create/create_with_Extra_size/destroy functions for the type type. ]*/ -#define DEFINE_REFCOUNT_TYPE(type) \ +#define DEFINE_REFCOUNT_TYPE(type, malloc_func, free_func) \ REFCOUNT_TYPE(type) \ { \ volatile_atomic int32_t count; \ type counted; \ }; \ -DEFINE_CREATE_WITH_EXTRA_SIZE(type) \ -DEFINE_CREATE(type) \ -DEFINE_DESTROY(type) \ +DEFINE_CREATE_WITH_EXTRA_SIZE(type, malloc_func) \ +DEFINE_CREATE(type, malloc_func) \ +DEFINE_DESTROY(type, free_func) \ /*assuming that CONSTBUFFER_ARRAY_HANDLE is a type introduced with DEFINE_REFCOUNT_TYPE(CONSTBUFFER_ARRAY_HANDLE_DATA); and "checkpointContent" is a variable of type CONSTBUFFER_ARRAY_HANDLE diff --git a/common/tests/refcount_ut/refcount_ut.c b/common/tests/refcount_ut/refcount_ut.c index ee8a098..3e6e8d3 100644 --- a/common/tests/refcount_ut/refcount_ut.c +++ b/common/tests/refcount_ut/refcount_ut.c @@ -32,6 +32,7 @@ void my_free(void* ptr) #include "azure_c_pal/interlocked.h" #include "azure_c_pal/gballoc_hl.h" #include "azure_c_pal/gballoc_hl_redirect.h" +#include "azure_c_pal/refcount.h" #undef ENABLE_MOCKS #include "real_gballoc_hl.h" @@ -46,6 +47,19 @@ static void on_umock_c_error(UMOCK_C_ERROR_CODE error_code) ASSERT_FAIL("umock_c reported error :%" PRI_MU_ENUM "", MU_ENUM_VALUE(UMOCK_C_ERROR_CODE, error_code)); } +typedef struct TEST_STRUCT_TAG +{ + int dummy; +} TEST_STRUCT; + +MOCK_FUNCTION_WITH_CODE(, void*, test_malloc, size_t, size) +MOCK_FUNCTION_END(my_malloc(size)) +MOCK_FUNCTION_WITH_CODE(, void, test_free, void*, ptr) + my_free(ptr); +MOCK_FUNCTION_END() + +DEFINE_REFCOUNT_TYPE(TEST_STRUCT, test_malloc, test_free); + BEGIN_TEST_SUITE(refcount_unittests) TEST_SUITE_INITIALIZE(TestClassInitialize) @@ -240,4 +254,50 @@ BEGIN_TEST_SUITE(refcount_unittests) ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); } + /* Tests_SRS_REFCOUNT_01_010: [ Memory allocation/free shall be performed by using the functions malloc_func and free_func. ]*/ \ + TEST_FUNCTION(the_specified_malloc_function_from_the_define_is_used) + { + ///arrange + STRICT_EXPECTED_CALL(test_malloc(IGNORED_ARG)); + STRICT_EXPECTED_CALL(interlocked_exchange(IGNORED_ARG, 1)); + + ///act + TEST_STRUCT* result = REFCOUNT_TYPE_CREATE(TEST_STRUCT); + + ///assert + ASSERT_IS_NOT_NULL(result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + } + + /* Tests_SRS_REFCOUNT_01_010: [ Memory allocation/free shall be performed by using the functions malloc_func and free_func. ]*/ \ + TEST_FUNCTION(the_specified_malloc_function_from_the_define_is_used_by_create_with_extra_size) + { + ///arrange + STRICT_EXPECTED_CALL(test_malloc(IGNORED_ARG)); + STRICT_EXPECTED_CALL(interlocked_exchange(IGNORED_ARG, 1)); + + ///act + TEST_STRUCT* result = REFCOUNT_TYPE_CREATE_WITH_EXTRA_SIZE(TEST_STRUCT, 1); + + ///assert + ASSERT_IS_NOT_NULL(result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + } + + /* Tests_SRS_REFCOUNT_01_010: [ Memory allocation/free shall be performed by using the functions malloc_func and free_func. ]*/ \ + TEST_FUNCTION(the_specified_free_function_from_the_define_is_used) + { + ///arrange + TEST_STRUCT* result = REFCOUNT_TYPE_CREATE(TEST_STRUCT); + umock_c_reset_all_calls(); + + STRICT_EXPECTED_CALL(test_free(IGNORED_ARG)); + + ///act + REFCOUNT_TYPE_DESTROY(TEST_STRUCT, result); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + } + END_TEST_SUITE(refcount_unittests) diff --git a/common/tests/refcount_ut/some_refcount_impl.c b/common/tests/refcount_ut/some_refcount_impl.c index 0528176..f5a5155 100644 --- a/common/tests/refcount_ut/some_refcount_impl.c +++ b/common/tests/refcount_ut/some_refcount_impl.c @@ -14,7 +14,8 @@ typedef struct pos_TAG } pos; /* Tests_SRS_REFCOUNT_01_001: [ DEFINE_REFCOUNT_TYPE shall define the create/create_with_Extra_size/destroy functions for the type type. ]*/ -DEFINE_REFCOUNT_TYPE(pos); +/* Tests_SRS_REFCOUNT_01_010: [ Memory allocation/free shall be performed by using the functions `malloc_func` and `free_func`. ]*/ \ +DEFINE_REFCOUNT_TYPE(pos, malloc, free); POS_HANDLE Pos_Create(int x) { diff --git a/win32/src/execution_engine_win32.c b/win32/src/execution_engine_win32.c index 0139797..b01b6a3 100644 --- a/win32/src/execution_engine_win32.c +++ b/win32/src/execution_engine_win32.c @@ -14,7 +14,7 @@ typedef struct EXECUTION_ENGINE_TAG PTP_POOL ptp_pool; }EXECUTION_ENGINE; -DEFINE_REFCOUNT_TYPE(EXECUTION_ENGINE); +DEFINE_REFCOUNT_TYPE(EXECUTION_ENGINE, malloc, free); EXECUTION_ENGINE_HANDLE execution_engine_create(void* execution_engine_parameters) {