Nigel Rantor / azure_c_shared_utility

Fork of azure_c_shared_utility by Azure IoT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers refcount.h Source File

refcount.h

00001 // Copyright (c) Microsoft. All rights reserved.
00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
00003 
00004 
00005 /*this header contains macros for ref_counting a variable. 
00006 
00007 There are no upper bound checks related to uint32_t overflow because we expect that bigger issues are in
00008 the system when more than 4 billion references exist to the same variable. In the case when such an overflow
00009 occurs, the object's ref count will reach zero (while still having 0xFFFFFFFF references) and likely the
00010 controlling code will take the decision to free the object's resources. Then, any of the 0xFFFFFFFF references
00011 will interact with deallocated memory / resources resulting in an undefined behavior.
00012 */
00013 
00014 #ifndef REFCOUNT_H
00015 #define REFCOUNT_H
00016 
00017 #ifdef __cplusplus
00018 #include <cstdlib>
00019 #include <cstdint>
00020 extern "C" 
00021 {
00022 #else
00023 #include <stdlib.h>
00024 #include <stdint.h>
00025 #endif
00026 
00027 #include "azure_c_shared_utility/gballoc.h"
00028 #include "azure_c_shared_utility/macro_utils.h"
00029 
00030 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ == 201112) && (__STDC_NO_ATOMICS__!=1)
00031 #define REFCOUNT_USE_STD_ATOMIC 1
00032 #endif
00033 
00034 #if defined(ARDUINO_ARCH_SAMD)
00035 #undef  REFCOUNT_USE_STD_ATOMIC
00036 #endif
00037 
00038 #if defined(FREERTOS_ARCH_ESP8266)
00039 #undef  REFCOUNT_USE_STD_ATOMIC  
00040 #define REFCOUNT_ATOMIC_DONTCARE 1
00041 #undef __GNUC__    
00042 #endif
00043 
00044 #define REFCOUNT_TYPE(type) \
00045 struct C2(C2(REFCOUNT_, type), _TAG)
00046 
00047 #define REFCOUNT_SHORT_TYPE(type) \
00048 C2(REFCOUNT_, type)
00049 
00050 #define REFCOUNT_TYPE_DECLARE_CREATE(type) C2(REFCOUNT_SHORT_TYPE(type), _Create)
00051 #define REFCOUNT_TYPE_CREATE(type) C2(REFCOUNT_SHORT_TYPE(type), _Create)()
00052 
00053 /*this introduces a new refcount'd type based on another type */
00054 /*and an initializer for that new type that also sets the ref count to 1. The type must not have a flexible array*/
00055 /*the newly allocated memory shall be free'd by free()*/
00056 /*and the ref counting is handled internally by the type in the _Create/ _Clone /_Destroy functions */
00057 
00058 #if defined(REFCOUNT_USE_STD_ATOMIC)
00059 #define COUNT_TYPE _Atomic uint32_t
00060 #elif defined(WIN32)
00061 #define COUNT_TYPE LONG
00062 #else
00063 #define COUNT_TYPE uint32_t
00064 #endif
00065 
00066 #define DEFINE_REFCOUNT_TYPE(type)                                                                   \
00067 REFCOUNT_TYPE(type)                                                                                  \
00068 {                                                                                                    \
00069     type counted;                                                                                    \
00070     COUNT_TYPE count;                                                                                  \
00071 };                                                                                                   \
00072 static type* REFCOUNT_TYPE_DECLARE_CREATE(type) (void)                                               \
00073 {                                                                                                    \
00074     REFCOUNT_TYPE(type)* result = (REFCOUNT_TYPE(type)*)malloc(sizeof(REFCOUNT_TYPE(type)));         \
00075     if (result != NULL)                                                                              \
00076     {                                                                                                \
00077         result->count = 1;                                                                           \
00078     }                                                                                                \
00079     return (type*)result;                                                                            \
00080 }                                                                                                    \
00081 
00082 /*the following macros increment/decrement a ref count in an atomic way, depending on the platform*/
00083 /*The following mechanisms are considered in this order
00084 C11 
00085     - will result in #include <stdatomic.h> 
00086     - will use atomic_fetch_add/sub; 
00087     - about the return value: "Atomically, the value pointed to by object immediately before the effects"
00088 windows 
00089     - will result in #include "windows.h"
00090     - will use InterlockedIncrement/InterlockedDecrement; 
00091     - about the return value: https://msdn.microsoft.com/en-us/library/windows/desktop/ms683580(v=vs.85).aspx "The function returns the resulting decremented value"
00092 gcc
00093     - will result in no include (for gcc these are intrinsics build in)
00094     - will use __sync_fetch_and_add/sub
00095     - about the return value: "... returns the value that had previously been in memory." (https://gcc.gnu.org/onlinedocs/gcc-4.4.3/gcc/Atomic-Builtins.html#Atomic-Builtins)
00096 other cases
00097     - if REFCOUNT_ATOMIC_DONTCARE is defined, then 
00098         will result in ++/-- used for increment/decrement.
00099     - if it is not defined, then error out
00100        
00101 It seems windows is "one off" because it returns the value "after" the decrement, as opposed to C11 standard and gcc that return the value "before". 
00102 The macro DEC_RETURN_ZERO will be "0" on windows, and "1" on the other cases.
00103 */
00104 
00105 /*if macro DEC_REF returns DEC_RETURN_ZERO that means the ref count has reached zero.*/
00106 #if defined(REFCOUNT_USE_STD_ATOMIC)
00107 #include <stdatomic.h>
00108 #define DEC_RETURN_ZERO (1)
00109 #define INC_REF(type, var) atomic_fetch_add((&((REFCOUNT_TYPE(type)*)var)->count), 1)
00110 #define DEC_REF(type, var) atomic_fetch_sub((&((REFCOUNT_TYPE(type)*)var)->count), 1)
00111 
00112 #elif defined(WIN32)
00113 #include "windows.h"
00114 #define DEC_RETURN_ZERO (0)
00115 #define INC_REF(type, var) InterlockedIncrement(&(((REFCOUNT_TYPE(type)*)var)->count))
00116 #define DEC_REF(type, var) InterlockedDecrement(&(((REFCOUNT_TYPE(type)*)var)->count))
00117 
00118 #elif defined(__GNUC__)
00119 #define DEC_RETURN_ZERO (0)
00120 #define INC_REF(type, var) __sync_add_and_fetch((&((REFCOUNT_TYPE(type)*)var)->count), 1)
00121 #define DEC_REF(type, var) __sync_sub_and_fetch((&((REFCOUNT_TYPE(type)*)var)->count), 1)
00122 
00123 #else
00124 #if defined(REFCOUNT_ATOMIC_DONTCARE)
00125 #define DEC_RETURN_ZERO (0)
00126 #define INC_REF(type, var) ++((((REFCOUNT_TYPE(type)*)var)->count))
00127 #define DEC_REF(type, var) --((((REFCOUNT_TYPE(type)*)var)->count))
00128 #else
00129 #error do not know how to atomically increment and decrement a uint32_t :(. Platform support needs to be extended to your platform.
00130 #endif /*defined(REFCOUNT_ATOMIC_DONTCARE)*/
00131 #endif
00132 
00133 
00134 
00135 #ifdef __cplusplus
00136 }
00137 #endif
00138 
00139 #endif /*REFCOUNT_H*/
00140 
00141