common/inc/c_pal/thandle_ll.h (511 lines of code) (raw):

// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #ifndef THANDLE_LL_H #define THANDLE_LL_H #include <stdlib.h> #include <stdint.h> #include <stddef.h> #include "macro_utils/macro_utils.h" #include "c_logging/logger.h" #include "c_pal/interlocked.h" #include "c_pal/containing_record.h" #include "umock_c/umock_c_prod.h" /*the incomplete unassignable type*/ #define THANDLE(T) MU_C2(CONST_P2_CONST_,T) #define THANDLE_MACRO(T) \ typedef const T* const volatile THANDLE(T); #define THANDLE_MAX_NAME_CHAR 32 /*maximum number of characters in a captured THANDLE type name*/ /*THANDLE carries a name field on debug builds only. Can be inspected with INSPECT function here in a debug environment.*/ #if defined(_DEBUG) || defined(DEBUG) #define THANDLE_DEBUG_EXTRA_FIELDS_NAME char, name[THANDLE_MAX_NAME_CHAR], /*destination is intended to be the field "name" from above*/ #define THANDLE_DEBUG_COPY_NAME(T, destination) (void)snprintf(destination, THANDLE_MAX_NAME_CHAR, "%s", MU_TOSTRING(T)); #else #define THANDLE_DEBUG_EXTRA_FIELDS_NAME /*well - nothing*/ #define THANDLE_DEBUG_COPY_NAME(T, destination) /*well - nothing*/ #endif #define THANDLE_EXTRA_FIELDS(type) \ THANDLE_DEBUG_EXTRA_FIELDS_NAME \ volatile_atomic int32_t, refCount, \ THANDLE_LL_FREE_FUNCTION_POINTER_T, free_function, \ void(*dispose)(type*) , \ /*thandle_ll_malloc field in the structure below is the name of the function that allocates memory (has the same signature as malloc from stdlib*/ /*thandle_ll_malloc can come from 3 sources from lowest to highest priority: 1. globally: malloc/malloc_flex/free as found at the time of the macro expansion. 2. at type definition time: when the user uses THANDLE_LL_TYPE_DEFINE_WITH_MALLOC_FUNCTIONS 3. at instance creation time: when the user decides to use at instance level of THANDLE specific allocation function by calling THANDLE_LL_MALLOC_WITH_MALLOC_FUNCTIONS / THANDLE_MALLOC_FLEX_WITH_MALLOC_FUNCTIONS / THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS */ typedef void* (*THANDLE_LL_MALLOC_FUNCTION_POINTER_T)(size_t); typedef void* (*THANDLE_LL_MALLOC_FLEX_FUNCTION_POINTER_T)(size_t, size_t, size_t); typedef void (*THANDLE_LL_FREE_FUNCTION_POINTER_T)(void*); /*given a previous type T, THANDLE_LL_TYPE_STRUCT_TYPE(_TAG) introduces a name for a structure that captures 3 pointers(malloc, malloc_flex, free) for the type T*/ #define THANDLE_LL_TYPE_STRUCT_TYPE_TAG(T) MU_C3(THANDLE_LL_TYPE_STRUCT_TYPE_, T, _TAG) #define THANDLE_LL_TYPE_STRUCT_TYPE(T) MU_C2(THANDLE_LL_TYPE_STRUCT_TYPE_, T) #define THANDLE_LL_TYPE_STRUCT_TYPE_DEFINE(T) \ typedef struct THANDLE_LL_TYPE_STRUCT_TYPE_TAG(T) \ { \ THANDLE_LL_MALLOC_FUNCTION_POINTER_T thandle_ll_malloc; \ THANDLE_LL_MALLOC_FLEX_FUNCTION_POINTER_T thandle_ll_malloc_flex; \ THANDLE_LL_FREE_FUNCTION_POINTER_T thandle_ll_free; \ /*TO DO: move here THANDLE_DEBUG_EXTRA_FIELDS_NAME*/ \ }THANDLE_LL_TYPE_STRUCT_TYPE(T); \ /*given a previous type T, this is the name of the type that has T wrapped*/ #define THANDLE_WRAPPER_TYPE_NAME(T) MU_C2(T, _WRAPPER) /*given a previous type T, THANDLE_MALLOC introduces a new name that mimics "malloc for T"*/ /*the new name is used to define the name of a static function that allocates memory*/ #define THANDLE_MALLOC(C) MU_C2(THANDLE_MALLOC_, C) /*given a previous type T, THANDLE_LL_MALLOC_WITH_MALLOC_FUNCTIONS introduces a new name that mimics "malloc for T" but uses the specified malloc/free functions*/ /*the new name is used to define the name of a static function that allocates memory using specified malloc functions*/ #define THANDLE_MALLOC_WITH_MALLOC_FUNCTIONS(C) MU_C2(THANDLE_LL_MALLOC_WITH_MALLOC_FUNCTIONS_, C) /*captures THANDLE_LL_TYPE_DEFINE_WITH_MALLOC_FUNCTIONS' malloc_function, malloc_flex_function, malloc_free_function parameters for type T*/ #define THANDLE_LL_TYPE_STRUCT_VAR(T) MU_C2(THANDLE_LL_TYPE_FROM_MACRO_, T) #define THANDLE_LL_TYPE_STRUCT_VAR_DEFINE(T, malloc_function, malloc_flex_function, malloc_free_function) static const THANDLE_LL_TYPE_STRUCT_TYPE(T) THANDLE_LL_TYPE_STRUCT_VAR(T) = {malloc_function, malloc_flex_function, malloc_free_function}; /*given a previous type T, THANDLE_INSPECT introduces a new name that if a function that returns the THANDLE_WRAPPER_TYPE_NAME(T) - useful in debugging. The function has no side-effects.*/ #define THANDLE_INSPECT(T) MU_C2(T,_INSPECT) /*given a previous type T, THANDLE_MALLOC_FLEX introduces a new name that mimics "malloc for T, where T is a flex type"*/ /*the new name is used to define the name of a static function that allocates memory*/ #define THANDLE_MALLOC_FLEX(T) MU_C2(T,_MALLOC_WITH_EXTRA_SIZE) /*given a previous type T, THANDLE_CREATE_FROM_CONTENT introduces a new name for the function that makes of copy of T and returns a THANDLE to the caller*/ #define THANDLE_CREATE_FROM_CONTENT(T) MU_C2(T,_CREATE_FROM_CONTENT) /*given a previous type T (usually a struct with a flexible array member), THANDLE_CREATE_FROM_CONTENT_FLEX introduces a new name for the function that makes of copy of T and returns a THANDLE to the caller*/ #define THANDLE_CREATE_FROM_CONTENT_FLEX(T) MU_C2(T,_CREATE_FROM_CONTENT_FLEX) /*given a previous type T (usually a struct with a flexible array member), THANDLE_GET_SIZEOF introduces a new name for a user function that returns the sizeof of T */ #define THANDLE_GET_SIZEOF(T) MU_C2(T,_GET_SIZE_OF) /*given a previous type T, THANDLE_FREE introduces a new name that mimics "free for T"*/ /*the new name is used to define the name of a static function that frees the memory allocated by THANDLE_MALLOC/THANDLE_MALLOC_FLEX*/ #define THANDLE_FREE(T) MU_C2(T,_FREE) /*given a previous type T, THANDLE_DEC_REF introduces a new name that mimics "dec_ref for T"*/ /*the new name is used to define the name of a static function that decrements the ref count of T and if 0, releases it*/ #define THANDLE_DEC_REF(T) MU_C2(T,_DEC_REF) /*given a previous type T, THANDLE_INC_REF introduces a new name that mimics "inc_ref for T"*/ /*the new name is used to define the name of a static function that increments the ref count of T*/ #define THANDLE_INC_REF(T) MU_C2(T,_INC_REF) /*given a previous type T, THANDLE_ASSIGN introduces a new name for a function that does T1=T2 (with inc/dec refs)*/ #define THANDLE_ASSIGN(T) MU_C2(T,_ASSIGN) /*given a previous type T, THANDLE_ASSIGN_FUNCTION_TYPE introduces the name of the type of the function that does THANDLE_ASSIGN*/ #define THANDLE_ASSIGN_FUNCTION_TYPE(T) MU_C2(THANDLE_ASSIGN_TYPE_, T) /*given a previous type T, THANDLE_ASSIGN_FUNCTION_TYPE_DECLARE(T) introduces the type of the function that does THANDLE_ASSIGN*/ #define THANDLE_ASSIGN_FUNCTION_TYPE_DECLARE(T) typedef void (* THANDLE_ASSIGN_FUNCTION_TYPE(T))(THANDLE(T) * t1, THANDLE(T) t2); /*given a previous type T, THANDLE_INITIALIZE introduces a new name for a function that does T1=T2 (with inc ref, and considers T1 as uninitialized memory)*/ #define THANDLE_INITIALIZE(T) MU_C2(T,_INITIALIZE) /*given a previous type T, THANDLE_INITIALIZE_FUNCTION_TYPE introduces the name of the type of the function that does THANDLE_INITIALIZE*/ #define THANDLE_INITIALIZE_FUNCTION_TYPE(T) MU_C2(THANDLE_INITIALIZE_TYPE_, T) /*given a previous type T, THANDLE_INITIALIZE_FUNCTION_TYPE_DECLARE(T) introduces the type of the function that does THANDLE_INITIALIZE*/ #define THANDLE_INITIALIZE_FUNCTION_TYPE_DECLARE(T) typedef void (* THANDLE_INITIALIZE_FUNCTION_TYPE(T))(THANDLE(T) * t1, THANDLE(T) t2); /*given a previous type T (and its THANDLE(T)), THANDLE_MOVE introduces a new name for a function that moves a handle to another handle. Move does not increment the ref count, and NULLs the source*/ #define THANDLE_MOVE(T) MU_C2(T,_MOVE) /*given a previous type T, THANDLE_MOVE_FUNCTION_TYPE introduces the name of the type of the function that does THANDLE_MOVE*/ #define THANDLE_MOVE_FUNCTION_TYPE(T) MU_C2(THANDLE_MOVE_TYPE_, T) /*given a previous type T, THANDLE_MOVE_FUNCTION_TYPE_DECLARE(T) introduces the type of the function that does THANDLE_MOVE*/ #define THANDLE_MOVE_FUNCTION_TYPE_DECLARE(T) typedef void (* THANDLE_MOVE_FUNCTION_TYPE(T))(THANDLE(T) * t1, THANDLE(T) *t2); /*given a previous type T (and its THANDLE(T)), THANDLE_INITIALIZE_MOVE introduces a new name for a function that moves a handle to another handle. INITIALIZE_MOVE does not increment the ref count, and NULLs the source. INITIALIZE_MOVE assumes that destination is not initialized and thus it does not decrement the destination ref count */ #define THANDLE_INITIALIZE_MOVE(T) MU_C2(T,_INITIALIZE_MOVE) /*given a previous type T, THANDLE_INITIALIZE_MOVE_FUNCTION_TYPE introduces the name of the type of the function that does THANDLE_INITIALIZE_MOVE*/ #define THANDLE_INITIALIZE_MOVE_FUNCTION_TYPE(T) MU_C2(THANDLE_INITIALIZE_MOVE_TYPE_, T) /*given a previous type T, THANDLE_INITIALIZE_MOVE_FUNCTION_TYPE_DECLARE(T) introduces the type of the function that does THANDLE_INITIALIZE_MOVE*/ #define THANDLE_INITIALIZE_MOVE_FUNCTION_TYPE_DECLARE(T) typedef void (* THANDLE_INITIALIZE_MOVE_FUNCTION_TYPE(T))(THANDLE(T) * t1, THANDLE(T) *t2); /*given a previous type T (and its THANDLE(T)), THANDLE_GET_T introduces a new name for a function that returns the T* from under the THANDLE(T)*/ #define THANDLE_GET_T(T) MU_C2(T,_GET_T) /*THANDLE_MALLOC_WITH_MALLOC_FUNCTIONS returns a new T* using malloc_function (if not NULL) or THANDLE_LL_TYPE_STRUCT_VAR.malloc (if not NULL) or malloc*/ #define THANDLE_LL_MALLOC_WITH_MALLOC_FUNCTIONS_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static T* THANDLE_MALLOC_WITH_MALLOC_FUNCTIONS(C)(void(*dispose)(T*), THANDLE_LL_MALLOC_FUNCTION_POINTER_T malloc_function, THANDLE_LL_FREE_FUNCTION_POINTER_T free_function) \ { \ T* result; \ THANDLE_LL_MALLOC_FUNCTION_POINTER_T malloc_function_used; \ THANDLE_LL_FREE_FUNCTION_POINTER_T free_function_used; \ if(malloc_function != NULL) \ { \ /*Codes_SRS_THANDLE_02_039: [ If malloc_function is not NULL then malloc_function and free_function shall be used to allocate/free memory. ]*/ \ malloc_function_used = malloc_function; \ free_function_used = free_function; \ } \ else if(THANDLE_LL_TYPE_STRUCT_VAR(T).thandle_ll_malloc!=NULL) \ { \ /*Codes_SRS_THANDLE_02_040: [ If malloc_function from THANDLE_LL_TYPE_DEFINE_WITH_MALLOC_FUNCTIONS is not NULL then THANDLE_LL_TYPE_DEFINE_WITH_MALLOC_FUNCTIONS's malloc_function and free_function shall be used to allocate/free memory. ]*/ \ malloc_function_used = THANDLE_LL_TYPE_STRUCT_VAR(T).thandle_ll_malloc; \ free_function_used = THANDLE_LL_TYPE_STRUCT_VAR(T).thandle_ll_free; \ } \ else \ { \ /*Codes_SRS_THANDLE_02_042: [ If no function can be found to allocate/free memory then THANDLE_MALLOC_WITH_MALLOC_FUNCTIONS shall use malloc and free. ]*/ \ malloc_function_used = malloc; \ free_function_used = free; \ } \ \ /*Codes_SRS_THANDLE_02_043: [ THANDLE_MALLOC_WITH_MALLOC_FUNCTIONS shall allocate memory. ]*/ \ THANDLE_WRAPPER_TYPE_NAME(T)* handle_impl = (THANDLE_WRAPPER_TYPE_NAME(T)*)malloc_function_used(sizeof(THANDLE_WRAPPER_TYPE_NAME(T))); \ if (handle_impl == NULL) \ { \ /*Codes_SRS_THANDLE_02_045: [ If allocating memory fails then THANDLE_MALLOC_WITH_MALLOC_FUNCTIONS shall fail and return NULL. ]*/ \ LogError("error in malloc_function_used=%p(sizeof(THANDLE_WRAPPER_TYPE_NAME(" MU_TOSTRING(T) "))=%zu)", \ malloc_function_used, sizeof(THANDLE_WRAPPER_TYPE_NAME(T))); \ result = NULL; \ } \ else \ { \ /*Codes_SRS_THANDLE_02_044: [ THANDLE_MALLOC_WITH_MALLOC_FUNCTIONS shall initialize the reference count to 1, store dispose and free_function and return a T* ]*/ \ THANDLE_DEBUG_COPY_NAME(T, handle_impl->name); \ handle_impl->dispose = dispose; \ handle_impl->free_function = free_function_used; \ (void)interlocked_exchange(&handle_impl->refCount,1); \ result = &(handle_impl->data); \ } \ return result; \ } \ MU_UNSUPPRESS_WARNING(4505) \ /*given a previous type T, this introduces THANDLE_MALLOC macro to create its wrapper, initialize refCount to 1, and remember the dispose function*/ #define THANDLE_LL_MALLOC_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static T* THANDLE_MALLOC(C)(void(*dispose)(T*)) \ { \ return THANDLE_MALLOC_WITH_MALLOC_FUNCTIONS(C)(dispose, NULL, NULL); \ } \ MU_UNSUPPRESS_WARNING(4505) \ /*this is only useful during debugging: from a THANDLE(T) it returns THANDLE_WRAPPER_TYPE_NAME(T) - which can be viewed in debugger - useful for seeing refCount. Example: write REAL_BSDL_LOG_STRUCTURE_INSPECT(temp) in the Visual Studio watch window, where REAL_BSDL_LOG_STRUCTURE is a previously THANDLE'd type */ #define THANDLE_LL_INSPECT_MACRO(C, T) \ const THANDLE_WRAPPER_TYPE_NAME(T)* const THANDLE_INSPECT(C)(THANDLE(T) t) \ { \ return CONTAINING_RECORD(t, THANDLE_WRAPPER_TYPE_NAME(T), data); \ } \ #define THANDLE_MALLOC_FLEX_WITH_MALLOC_FUNCTIONS(C) MU_C2(THANDLE_LL_MALLOC_WITH_EXTRA_SIZE_MACRO_WITH_MALLOC_FUNCTIONS_, C) /*THANDLE_MALLOC_FLEX_WITH_MALLOC_FUNCTIONS returns a new T* with flex semantics using malloc_flex_function (if not NULL) or THANDLE_LL_TYPE_STRUCT_VAR.malloc_flex (if not NULL) or malloc_flex*/ #define THANDLE_LL_MALLOC_WITH_EXTRA_SIZE_WITH_MALLOC_FUNCTIONS_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static T* THANDLE_MALLOC_FLEX_WITH_MALLOC_FUNCTIONS(C)(void(*dispose)(T*), size_t nmemb, size_t size, THANDLE_LL_MALLOC_FLEX_FUNCTION_POINTER_T malloc_flex_function, THANDLE_LL_FREE_FUNCTION_POINTER_T free_function) \ { \ T* result; \ THANDLE_LL_MALLOC_FLEX_FUNCTION_POINTER_T malloc_flex_function_used; \ THANDLE_LL_FREE_FUNCTION_POINTER_T free_function_used; \ if(malloc_flex_function != NULL) \ { \ /*Codes_SRS_THANDLE_02_046: [ If malloc_flex_function is not NULL then malloc_flex_function and free_function shall be used to allocate memory. ]*/ \ malloc_flex_function_used = malloc_flex_function; \ free_function_used = free_function; \ } \ else if(THANDLE_LL_TYPE_STRUCT_VAR(T).thandle_ll_malloc_flex!=NULL) \ { \ /*Codes_SRS_THANDLE_02_047: [ If malloc_flex_function from THANDLE_LL_TYPE_DEFINE_WITH_MALLOC_FUNCTIONS is not NULL then THANDLE_LL_TYPE_DEFINE_WITH_MALLOC_FUNCTIONS's malloc_flex_function and free_function shall be used to allocate/free memory. ]*/ \ malloc_flex_function_used = THANDLE_LL_TYPE_STRUCT_VAR(T).thandle_ll_malloc_flex; \ free_function_used = THANDLE_LL_TYPE_STRUCT_VAR(T).thandle_ll_free; \ } \ else \ { \ /*Codes_SRS_THANDLE_02_049: [ If no function can be found to allocate/free memory then THANDLE_MALLOC_FLEX_WITH_MALLOC_FUNCTIONS shall use malloc_flex and free. ]*/ \ malloc_flex_function_used = malloc_flex; \ free_function_used = free; \ } \ \ /*Codes_SRS_THANDLE_02_050: [ THANDLE_MALLOC_FLEX_WITH_MALLOC_FUNCTIONS shall allocate memory for the THANDLE and an additional (nmemb * size) bytes. ]*/ \ THANDLE_WRAPPER_TYPE_NAME(T)* handle_impl = malloc_flex_function_used(sizeof(THANDLE_WRAPPER_TYPE_NAME(T)), nmemb, size); \ if (handle_impl == NULL) \ { \ /*Codes_SRS_THANDLE_02_052: [ If allocating memory fails then THANDLE_MALLOC_FLEX_WITH_MALLOC_FUNCTIONS shall fail and return NULL. ]*/ \ LogError("error in malloc_flex_function_used=%p(sizeof(THANDLE_WRAPPER_TYPE_NAME(" MU_TOSTRING(T) "))=%zu)", \ malloc_flex_function_used, sizeof(THANDLE_WRAPPER_TYPE_NAME(T))); \ result = NULL; \ } \ else \ { \ /*Codes_SRS_THANDLE_02_051: [ THANDLE_MALLOC_FLEX_WITH_MALLOC_FUNCTIONS shall initialize the reference count to 1, store dispose and free_function succeed and return a non-NULL T*. ]*/ \ THANDLE_DEBUG_COPY_NAME(T, handle_impl->name); \ handle_impl->dispose = dispose; \ handle_impl->free_function = free_function_used; \ (void)interlocked_exchange(&handle_impl->refCount,1); \ result = &(handle_impl->data); \ } \ return result; \ } \ MU_UNSUPPRESS_WARNING(4505) \ #define THANDLE_LL_MALLOC_WITH_EXTRA_SIZE_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static T* THANDLE_MALLOC_FLEX(C)(void(*dispose)(T*), size_t nmemb, size_t size) \ { \ return THANDLE_MALLOC_FLEX_WITH_MALLOC_FUNCTIONS(C)(dispose, nmemb, size, NULL, NULL); \ } \ MU_UNSUPPRESS_WARNING(4505) \ #define THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS(C) MU_C2(THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS_, C) /*THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS returns a new T* from some content using malloc_flex_function (if not NULL) or THANDLE_LL_TYPE_STRUCT_VAR.malloc_flex (if not NULL) or malloc_flex*/ #define THANDLE_LL_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static T* THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS(C)(const T* source, void(*dispose)(T*), int(*copy)(T* destination, const T* source), size_t(*get_sizeof)(const T* source), THANDLE_LL_MALLOC_FLEX_FUNCTION_POINTER_T malloc_flex_function, THANDLE_LL_FREE_FUNCTION_POINTER_T free_function) \ { \ T* result; \ if ( \ /*Codes_SRS_THANDLE_02_053: [ If source is NULL then THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall fail and return NULL. ]*/ \ (source == NULL) || \ /*Codes_SRS_THANDLE_02_054: [ If get_sizeof is NULL then THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall fail and return NULL. ]*/ \ (get_sizeof == NULL) \ ) \ { \ LogError("invalid arguments const T* source=%p, void(*dispose)(T*)=%p, int(*copy)(T* destination, const T* source)=%p, size_t(*get_sizeof)(const T* source)=%p, THANDLE_LL_MALLOC_FLEX_FUNCTION_POINTER_T malloc_flex_function=%p, THANDLE_LL_FREE_FUNCTION_POINTER_T free_function=%p", \ source, dispose, copy, get_sizeof, malloc_flex_function, free_function); \ result = NULL; \ } \ else \ { \ THANDLE_LL_MALLOC_FLEX_FUNCTION_POINTER_T malloc_flex_function_used; \ THANDLE_LL_FREE_FUNCTION_POINTER_T free_function_used; \ if(malloc_flex_function != NULL) \ { \ /*Codes_SRS_THANDLE_02_056: [ If malloc_flex_function is not NULL then malloc_flex_function and free_function shall be used to allocate memory. ]*/ \ malloc_flex_function_used = malloc_flex_function; \ free_function_used = free_function; \ } \ else if(THANDLE_LL_TYPE_STRUCT_VAR(T).thandle_ll_malloc_flex!=NULL) \ { \ /*Codes_SRS_THANDLE_02_057: [ If malloc_flex_function from THANDLE_LL_TYPE_DEFINE_WITH_MALLOC_FUNCTIONS is not NULL then THANDLE_LL_TYPE_DEFINE_WITH_MALLOC_FUNCTIONS's malloc_flex_function and free_function shall be used to allocate/free memory. ]*/ \ malloc_flex_function_used = THANDLE_LL_TYPE_STRUCT_VAR(T).thandle_ll_malloc_flex; \ free_function_used = THANDLE_LL_TYPE_STRUCT_VAR(T).thandle_ll_free; \ } \ else \ { \ /*Codes_SRS_THANDLE_02_059: [ If no function can be found to allocate/free memory then THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall use malloc_flex and free. ]*/ \ malloc_flex_function_used = malloc_flex; \ free_function_used = free; \ } \ /*Codes_SRS_THANDLE_02_064: [ THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall call get_sizeof to get the needed size to store T ]*/ \ size_t sizeof_source = get_sizeof(source); \ /*Codes_SRS_THANDLE_02_060: [ THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall allocate memory. ]*/ \ THANDLE_WRAPPER_TYPE_NAME(T)* handle_impl = (THANDLE_WRAPPER_TYPE_NAME(T)*)malloc_flex_function_used(sizeof(THANDLE_WRAPPER_TYPE_NAME(T)) - sizeof(T), 1, sizeof_source); \ if (handle_impl == NULL) \ { \ /*Codes_SRS_THANDLE_02_063: [ If there are any failures then THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall fail and return NULL. ]*/ \ LogError("error in malloc_flex_function_used=%p(sizeof(THANDLE_WRAPPER_TYPE_NAME(T))=%zu - sizeof(T)=%zu, 1, sizeof_source=%zu)", \ malloc_flex_function_used, sizeof(THANDLE_WRAPPER_TYPE_NAME(T)), sizeof(T), sizeof_source); \ result = NULL; \ } \ else \ { \ if (copy==NULL) \ { \ /*Codes_SRS_THANDLE_02_055: [ If copy is NULL then THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall memcpy the content of source in allocated memory. ]*/ \ THANDLE_DEBUG_COPY_NAME(T, handle_impl->name); \ (void)memcpy(&(handle_impl->data), source, sizeof_source); \ handle_impl->dispose = dispose; \ handle_impl->free_function = free_function_used; \ /*Codes_SRS_THANDLE_02_062: [ THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall initialize the ref count to 1, succeed and return a non-NULL value. ]*/ \ (void)interlocked_exchange(&handle_impl->refCount,1); \ result = &(handle_impl->data); \ } \ else \ { \ /*Codes_SRS_THANDLE_02_061: [ If copy is not NULL then THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall call copy to copy source into allocated memory. ]*/ \ if (copy(&handle_impl->data, source) != 0) \ { \ /*Codes_SRS_THANDLE_02_063: [ If there are any failures then THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall fail and return NULL. ]*/ \ LogError("failure in copy(&handle_impl->data=%p, source=%p)", &handle_impl->data, source); \ free_function_used(handle_impl); \ result = NULL; \ } \ else \ { \ handle_impl->dispose = dispose; \ handle_impl->free_function = free_function_used; \ /*Codes_SRS_THANDLE_02_062: [ THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS shall initialize the ref count to 1, succeed and return a non-NULL value. ]*/ \ (void)interlocked_exchange(&handle_impl->refCount,1); \ result = &(handle_impl->data); \ } \ } \ } \ } \ return result; \ } \ MU_UNSUPPRESS_WARNING(4505) \ #define THANDLE_LL_CREATE_FROM_CONTENT_FLEX_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static T* THANDLE_CREATE_FROM_CONTENT_FLEX(C)(const T* source, void(*dispose)(T*), int(*copy)(T* destination, const T* source), size_t(*get_sizeof)(const T* source)) \ { \ return THANDLE_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS(C)(source, dispose, copy, get_sizeof, NULL, NULL); \ } \ MU_UNSUPPRESS_WARNING(4505) \ #define THANDLE_LL_CREATE_FROM_CONTENT_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static size_t THANDLE_GET_SIZEOF(C)(const T* t) \ { \ return sizeof(*t); \ } \ static T* THANDLE_CREATE_FROM_CONTENT(C)(const T* source, void(*dispose)(T*), int(*copy)(T* destination, const T* source)) \ { \ /*Codes_SRS_THANDLE_02_032: [ THANDLE_CREATE_FROM_CONTENT_FLEX returns what THANDLE_CREATE_FROM_CONTENT_FLEX(T)(source, dispose, copy, THANDLE_GET_SIZEOF(T)); returns. ]*/ \ return THANDLE_CREATE_FROM_CONTENT_FLEX(C)(source, dispose, copy, THANDLE_GET_SIZEOF(C)); \ } \ MU_UNSUPPRESS_WARNING(4505) \ /*given a previous type T, this introduces THANDLE_FREE macro to free all used resources*/ #define THANDLE_LL_FREE_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static void THANDLE_FREE(C)(T* t) \ { \ /*Codes_SRS_THANDLE_02_016: [ If t is NULL then THANDLE_FREE shall return. ]*/ \ if (t == NULL) \ { \ LogError("invalid arg " MU_TOSTRING(T) "* t=%p", t); \ } \ else \ { \ /*Codes_SRS_THANDLE_02_017: [ THANDLE_FREE shall free the allocated memory by THANDLE_MALLOC. ]*/ \ THANDLE_WRAPPER_TYPE_NAME(T)* handle_impl = CONTAINING_RECORD(t, THANDLE_WRAPPER_TYPE_NAME(T), data); \ handle_impl->free_function(handle_impl); \ } \ } \ MU_UNSUPPRESS_WARNING(4505) \ /*given a previous type T, this introduces THANDLE_DEC_REF macro to decrement the reference count*/ #define THANDLE_LL_DEC_REF_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static void THANDLE_DEC_REF(C)(THANDLE(T) t) \ { \ THANDLE_WRAPPER_TYPE_NAME(T)* handle_impl = CONTAINING_RECORD(t, THANDLE_WRAPPER_TYPE_NAME(T), data); \ if (interlocked_decrement(&handle_impl->refCount) == 0) \ { \ if (handle_impl->dispose!=NULL) \ { \ handle_impl->dispose(&handle_impl->data); \ } \ handle_impl->free_function(handle_impl); \ } \ } \ MU_UNSUPPRESS_WARNING(4505) \ /*given a previous type T, this introduces THANDLE_INC_REF macro to increment the reference count*/ #define THANDLE_LL_INC_REF_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static void THANDLE_INC_REF(C)(THANDLE(T) t) \ { \ THANDLE_WRAPPER_TYPE_NAME(T)* handle_impl = CONTAINING_RECORD(t, THANDLE_WRAPPER_TYPE_NAME(T), data); \ (void)interlocked_increment(&handle_impl->refCount); \ } \ MU_UNSUPPRESS_WARNING(4505) \ /*given a previous type T, this introduces THANDLE_ASSIGN macro to assign a handle to another handle*/ #define THANDLE_LL_ASSIGN_MACRO(C, T) \ void THANDLE_ASSIGN(C)(THANDLE(T) * t1, THANDLE(T) t2) \ { \ /*Codes_SRS_THANDLE_02_006: [ If t1 is NULL then THANDLE_ASSIGN shall return. ]*/ \ if (t1 == NULL) \ { \ LogError("invalid argument THANDLE(" MU_TOSTRING(T) ") * t1=%p, THANDLE(" MU_TOSTRING(T) ") t2=%p", t1, t2 ); \ } \ else \ { \ if (*t1 == NULL) \ { \ if (t2 == NULL) \ { \ /*Codes_SRS_THANDLE_02_007: [ If *t1 is NULL and t2 is NULL then THANDLE_ASSIGN shall return. ]*/ \ /*so nothing to do, leave them as they are*/ \ } \ else \ { \ /*Codes_SRS_THANDLE_02_008: [ If *t1 is NULL and t2 is not NULL then THANDLE_ASSIGN shall increment the reference count of t2 and store t2 in *t1. ]*/ \ THANDLE_INC_REF(C)(t2); \ *(T const**)t1 = t2; \ } \ } \ else \ { \ if (t2 == NULL) \ { \ /*Codes_SRS_THANDLE_02_009: [ If *t1 is not NULL and t2 is NULL then THANDLE_ASSIGN shall decrement the reference count of *t1 and store NULL in *t1. ]*/ \ THANDLE_DEC_REF(C)(*t1); \ *(T const**)t1 = t2; \ } \ else \ { \ /*Codes_SRS_THANDLE_02_010: [ If *t1 is not NULL and t2 is not NULL then THANDLE_ASSIGN shall increment the reference count of t2, shall decrement the reference count of *t1 and store t2 in *t1. ]*/ \ THANDLE_INC_REF(C)(t2); \ THANDLE_DEC_REF(C)(*t1); \ *(T const**)t1 = t2; \ } \ } \ } \ } \ /*given a previous type T, this introduces THANDLE_INITIALIZE macro to initialize a handle value*/ #define THANDLE_LL_INITIALIZE_MACRO(C, T) \ void THANDLE_INITIALIZE(C)(THANDLE(T) * lvalue, THANDLE(T) rvalue) \ { \ /*Codes_SRS_THANDLE_02_011: [ If lvalue is NULL then THANDLE_INITIALIZE shall return. ]*/ \ if (lvalue == NULL) \ { \ LogError("invalid argument THANDLE(" MU_TOSTRING(T) ") * lvalue=%p, THANDLE(" MU_TOSTRING(T) ") rvalue=%p", lvalue, rvalue ); \ } \ else \ { \ if (rvalue == NULL) \ { \ /*Codes_SRS_THANDLE_02_018: [ If rvalue is NULL then THANDLE_INITIALIZE shall store NULL in *lvalue. ]*/ \ } \ else \ { \ /*Codes_SRS_THANDLE_02_012: [ THANDLE_INITIALIZE shall increment the reference count of rvalue and store it in *lvalue. ]*/ \ THANDLE_INC_REF(C)(rvalue); \ } \ *(T const**)lvalue = rvalue; \ } \ } \ /*if THANDLE(T) is previously defined, then this macro returns the T* from under the THANDLE(T) */ #define THANDLE_LL_GET_T_MACRO(C, T) \ MU_SUPPRESS_WARNING(4505) /*warning C4505: 'function': unreferenced function with internal linkage has been removed*/ \ static T* THANDLE_GET_T(C)(THANDLE(T) t) \ { \ /*Codes_SRS_THANDLE_02_023: [ If t is NULL then THANDLE_GET_T(T) shall return NULL. ]*/ \ /*Codes_SRS_THANDLE_02_024: [ THANDLE_GET_T(T) shall return the same pointer as THANDLE_MALLOC/THANDLE_MALLOC_FLEX returned at the handle creation time. ]*/ \ return (T*)t; \ } \ MU_UNSUPPRESS_WARNING(4505) \ /*given a previous type T, this introduces THANDLE_MOVE macro to move a handle (*t1=t2, *t2=NULL)*/ #define THANDLE_LL_MOVE_MACRO(C, T) \ void THANDLE_MOVE(C)(THANDLE(T) * t1, THANDLE(T) * t2) \ { \ if ( \ /*Codes_SRS_THANDLE_02_033: [ If t1 is NULL then THANDLE_MOVE shall return. ]*/ \ (t1 == NULL) || \ /*Codes_SRS_THANDLE_02_034: [ If t2 is NULL then THANDLE_MOVE shall return. ]*/ \ (t2 == NULL) \ ) \ { \ LogError("invalid argument THANDLE(" MU_TOSTRING(T) ") * t1=%p, THANDLE(" MU_TOSTRING(T) ") t2=%p", t1, t2 ); \ } \ else \ { \ if (*t1 == NULL) \ { \ if (*t2 == NULL) \ { \ /*so nothing to do, leave them as they are*/ \ /*Codes_SRS_THANDLE_02_035: [ If *t1 is NULL and *t2 is NULL then THANDLE_MOVE shall return. ]*/ \ } \ else \ { \ /*Codes_SRS_THANDLE_02_036: [ If *t1 is NULL and *t2 is not NULL then THANDLE_MOVE shall move *t2 under t1, set *t2 to NULL and return. ]*/ \ *(T const**)t1 = *t2; \ *(T const**)t2 = NULL; \ } \ } \ else \ { \ if (*t2 == NULL) \ { \ /*Codes_SRS_THANDLE_02_037: [ If *t1 is not NULL and *t2 is NULL then THANDLE_MOVE shall THANDLE_DEC_REF *t1, set *t1 to NULL and return. ]*/ \ THANDLE_DEC_REF(C)(*t1); \ *(T const**)t1 = NULL; \ } \ else \ { \ /*Codes_SRS_THANDLE_02_038: [ If *t1 is not NULL and *t2 is not NULL then THANDLE_MOVE shall THANDLE_DEC_REF *t1, set *t1 to *t2, set *t2 to NULL and return. ]*/ \ THANDLE_DEC_REF(C)(*t1); \ *(T const**)t1 = *t2; \ *(T const**)t2 = NULL; \ } \ } \ } \ } \ /*given a previous type T, this introduces THANDLE_INITIALIZE_MOVE_MACRO macro to move a handle (*t1=t2, *t2=NULL)*/ #define THANDLE_LL_INITIALIZE_MOVE_MACRO(C, T) \ void THANDLE_INITIALIZE_MOVE(C)(THANDLE(T) * t1, THANDLE(T) * t2) \ { \ if ( \ /*Codes_SRS_THANDLE_01_001: [ If t1 is NULL then THANDLE_INITIALIZE_MOVE shall return. ]*/ \ (t1 == NULL) || \ /*Codes_SRS_THANDLE_01_002: [ If t2 is NULL then THANDLE_INITIALIZE_MOVE shall return. ]*/ \ (t2 == NULL) \ ) \ { \ LogError("invalid argument THANDLE(" MU_TOSTRING(T) ") * t1=%p, THANDLE(" MU_TOSTRING(T) ") t2=%p", t1, t2 ); \ } \ else \ { \ if (*t2 == NULL) \ { \ /*Codes_SRS_THANDLE_01_003: [ If *t2 is NULL then THANDLE_INITIALIZE_MOVE shall set *t1 to NULL and return. ]*/ \ *(T const**)t1 = NULL; \ } \ else \ { \ /*Codes_SRS_THANDLE_01_004: [ If *t2 is not NULL then THANDLE_INITIALIZE_MOVE shall set *t1 to *t2, set *t2 to NULL and return. ]*/ \ *(T const**)t1 = *t2; \ *(T const**)t2 = NULL; \ } \ } \ } \ /*given a previous type T, this introduces a wrapper type that contains T (and other fields) and defines the functions of that type T*/ #define THANDLE_LL_TYPE_DEFINE_WITH_MALLOC_FUNCTIONS(C, T, malloc_function, malloc_flex_function, malloc_free_function) \ THANDLE_LL_TYPE_STRUCT_TYPE_DEFINE(T) \ THANDLE_LL_TYPE_STRUCT_VAR_DEFINE(T, malloc_function, malloc_flex_function, malloc_free_function) \ \ MU_DEFINE_STRUCT(THANDLE_WRAPPER_TYPE_NAME(T), THANDLE_EXTRA_FIELDS(T), T, data); \ \ THANDLE_LL_MALLOC_WITH_MALLOC_FUNCTIONS_MACRO(C, T) \ THANDLE_LL_MALLOC_MACRO(C, T) \ \ THANDLE_LL_MALLOC_WITH_EXTRA_SIZE_WITH_MALLOC_FUNCTIONS_MACRO(C, T) \ THANDLE_LL_MALLOC_WITH_EXTRA_SIZE_MACRO(C, T) \ \ THANDLE_LL_CREATE_FROM_CONTENT_FLEX_WITH_MALLOC_FUNCTIONS_MACRO(C, T) \ THANDLE_LL_CREATE_FROM_CONTENT_FLEX_MACRO(C, T) \ \ THANDLE_LL_CREATE_FROM_CONTENT_MACRO(C, T) \ \ THANDLE_LL_FREE_MACRO(C, T) \ THANDLE_LL_DEC_REF_MACRO(C, T) \ THANDLE_LL_INC_REF_MACRO(C, T) \ THANDLE_LL_ASSIGN_MACRO(C, T) \ THANDLE_LL_INITIALIZE_MACRO(C, T) \ THANDLE_LL_GET_T_MACRO(C, T) \ THANDLE_LL_INSPECT_MACRO(C, T) \ THANDLE_LL_MOVE_MACRO(C, T) \ THANDLE_LL_INITIALIZE_MOVE_MACRO(C, T) \ /*given a previous type T, this introduces a wrapper type that contains T (and other fields) and defines the functions of that type T*/ #define THANDLE_LL_TYPE_DEFINE(C,T) THANDLE_LL_TYPE_DEFINE_WITH_MALLOC_FUNCTIONS(C, T, NULL, NULL, NULL) /*macro to be used in headers*/ \ /*introduces an incomplete type based on a MU_DEFINE_STRUCT(T...) previously defined;*/ \ #define THANDLE_LL_TYPE_DECLARE(C,T) \ THANDLE_MACRO(T); \ THANDLE_ASSIGN_FUNCTION_TYPE_DECLARE(T); \ THANDLE_INITIALIZE_FUNCTION_TYPE_DECLARE(T); \ THANDLE_MOVE_FUNCTION_TYPE_DECLARE(T); \ THANDLE_INITIALIZE_MOVE_FUNCTION_TYPE_DECLARE(T); \ MOCKABLE_FUNCTION(, void, THANDLE_ASSIGN(C), THANDLE(T) *, t1, THANDLE(T), t2 ); \ MOCKABLE_FUNCTION(, void, THANDLE_INITIALIZE(C), THANDLE(T) *, t1, THANDLE(T), t2 ); \ MOCKABLE_FUNCTION(, void, THANDLE_MOVE(C), THANDLE(T) *, t1, THANDLE(T)*, t2 ); \ MOCKABLE_FUNCTION(, void, THANDLE_INITIALIZE_MOVE(C), THANDLE(T) *, t1, THANDLE(T)*, t2 ); \ #endif /*THANDLE_LL_H*/