Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
cn-context.c
00001 #ifdef USE_CBOR_CONTEXT 00002 #include "cn-cbor.h" 00003 #include "cbor.h" 00004 #include <stdlib.h> 00005 #include <string.h> 00006 00007 cn_cbor_context context_obj; 00008 cn_cbor_context *cbor_context = &context_obj; 00009 cbor_mem_pool mem_pool_internal; 00010 00011 #ifdef USE_CBOR_CONTEXT_STATS 00012 uint32_t calloc_heap_cntr = 0; 00013 uint32_t free_heap_cntr = 0; 00014 uint32_t calloc_pool_cntr = 0; 00015 uint32_t free_pool_cntr = 0; 00016 uint32_t bytes_heap_allocated = 0; 00017 uint32_t total_bytes_heap_allocated = 0; 00018 uint32_t max_bytes_heap_allocated = 0; 00019 uint32_t bytes_pool_allocated = 0; 00020 uint32_t total_bytes_pool_allocated = 0; 00021 uint32_t max_bytes_pool_allocated = 0; 00022 uint32_t number_of_pools_allocated = 0; 00023 uint32_t total_bytes_allocated_for_pools = 0; 00024 #endif // USE_CBOR_CONTEXT_STATS 00025 00026 //#include <strings.h> 00027 00028 #define BITMAP_ENTRY_SIZE_IN_BITS ( sizeof(mem_pool->bitmap[0]) * 8 ) 00029 #define BITMAP_FULL (-1) 00030 00031 #ifdef USE_CBOR_CONTEXT_STATS 00032 #define CBOR_STATS_FREE(mem) do { \ 00033 free_##mem##_cntr++; \ 00034 bytes_##mem##_allocated -= sizeof(cn_cbor); \ 00035 } while(0) 00036 00037 #define CBOR_STATS_CALLOC(mem, size, count) do { \ 00038 calloc_##mem##_cntr++; \ 00039 bytes_##mem##_allocated += size * count; \ 00040 total_bytes_##mem##_allocated += size * count; \ 00041 if (bytes_##mem##_allocated > max_bytes_##mem##_allocated) { \ 00042 max_bytes_##mem##_allocated = bytes_##mem##_allocated; \ 00043 } \ 00044 } while (0) 00045 #else 00046 #define CBOR_STATS_FREE(mem) 00047 #define CBOR_STATS_CALLOC(mem, size, count) 00048 #endif //USE_CBOR_CONTEXT_STATS 00049 00050 // Count leading zeros in pure C (https://stackoverflow.com/questions/23856596/counting-leading-zeros-in-a-32-bit-unsigned-integer-with-best-algorithm-in-c-pro) 00051 static int clz_pure_c(uint32_t a) 00052 { 00053 static const char debruijn32[32] = { 00054 0, 31, 9, 30, 3, 8, 13, 29, 2, 5, 7, 21, 12, 24, 28, 19, 00055 1, 10, 4, 14, 6, 22, 25, 20, 11, 15, 23, 26, 16, 27, 17, 18 00056 }; 00057 00058 // This algorithm does work correctly for input 0, so we handle it independently 00059 if (a == 0) { 00060 return 32; 00061 } 00062 00063 a |= a >> 1; 00064 a |= a >> 2; 00065 a |= a >> 4; 00066 a |= a >> 8; 00067 a |= a >> 16; 00068 a++; 00069 00070 return debruijn32[a * 0x076be629 >> 27]; 00071 } 00072 00073 // Count leading zeros. Use compiler functions that use direct machine instructions if possible 00074 static int count_leading_zeros(uint32_t a) 00075 { 00076 // If GCC 00077 #if defined(__GNUC__) 00078 return __builtin_clz(a); 00079 #elif defined(__arm__) 00080 return __clz(a); 00081 00082 #else // If not GCC or ARMCC, use pure C implementation 00083 return clz_pure_c(); 00084 00085 #endif 00086 } 00087 00088 // Count trailing zeros using using the count leading zeros command (https://community.arm.com/community-help/f/discussions/2114/count-trailing-zeros) 00089 static int ctz(uint32_t a) 00090 { 00091 int c = count_leading_zeros(a & -a); 00092 return a ? 31 - c : c; 00093 } 00094 00095 // Get the index of the first 0 bit in bitmap_entry 00096 static int find_first_open_slot(int32_t bitmap_entry) 00097 { 00098 int pos = ctz(~bitmap_entry); 00099 00100 return (pos < 32) ? pos : -1; 00101 } 00102 00103 // NOTE: CBOR library uses only calloc(1, sizeof(cn_cbor)). Currently only calloc(1,sizeof(cn_cbor)) is supported by the allocator 00104 /** 00105 * Allocate space for count (currently must be 1) CBOR elements. 00106 * 00107 * NOTE: CBOR library uses only calloc(1, sizeof(cn_cbor)). Currently only calloc(1,sizeof(cn_cbor)) currently supported by allocator. 00108 * @param[in] count Count of number of elements in allocated array. Currently must be 1. 00109 * @param[in] size Size of each element in the allocated array. Must be sizeof(cn_cbor) 00110 * @param[in] context Pointer to the CBOR context. 00111 * @return The address of the allocated memory. 00112 */ 00113 void *cbor_calloc(size_t count, size_t size, void *context) 00114 { 00115 void *ret_mem; 00116 int bitmap_idx, pos, bit_pos, max_bitmap_idx; 00117 cbor_mem_pool *mem_pool = (cbor_mem_pool *)(context); 00118 00119 // Currently supports only allocations of 1 slot. CBOR lib never allocates more than that. 00120 if (count != 1 || size != sizeof(cn_cbor)) { 00121 return NULL; 00122 } 00123 00124 // Get the index of the last entry in the bitmap array 00125 max_bitmap_idx = mem_pool->pool_size_in_cbors / BITMAP_ENTRY_SIZE_IN_BITS; 00126 00127 // If number of CBOR objects in pool is not divisible by 8, there is an additional entry to the bitmap for the residue 00128 if (mem_pool->pool_size_in_cbors % BITMAP_ENTRY_SIZE_IN_BITS != 0) { 00129 max_bitmap_idx++; 00130 } 00131 00132 for (bitmap_idx = 0; bitmap_idx < max_bitmap_idx; bitmap_idx++) { 00133 // If bitmap entry is full, try next 00134 if (mem_pool->bitmap[bitmap_idx] == BITMAP_FULL) { 00135 continue; 00136 } 00137 // Find first open slot in bitmap[bitmap_idx] 00138 bit_pos = find_first_open_slot(mem_pool->bitmap[bitmap_idx]); 00139 // If found open slot 00140 if (bit_pos >= 0) { 00141 00142 // Adjust position for CBOR pool 00143 pos = bit_pos + (bitmap_idx * BITMAP_ENTRY_SIZE_IN_BITS); 00144 00145 // If position not in pool (since the size is not divisible by the size of each entry in the bitmap array in bits) 00146 if (pos >= mem_pool->pool_size_in_cbors) { 00147 break; 00148 } 00149 00150 ret_mem = &(mem_pool->pool[pos]); 00151 00152 // Zero the returned memory (CBOR lib demands this) 00153 memset(ret_mem, 0, sizeof(mem_pool->pool[pos])); 00154 00155 // Set the bit in index pos 00156 mem_pool->bitmap[bitmap_idx] = mem_pool->bitmap[bitmap_idx] | (1ULL << bit_pos); 00157 00158 CBOR_STATS_CALLOC(pool, size, count); 00159 return ret_mem; 00160 } 00161 } 00162 00163 // If no space in pool, use LIBC calloc 00164 CBOR_STATS_CALLOC(heap, size, count); 00165 return calloc(count, size); 00166 } 00167 00168 // Return whether a given address resides within the allocated CBOR pool 00169 #define IS_IN_POOL(cbor_ptr, mem_pool) (( (uint8_t*)cbor_ptr >= ((uint8_t*) &(mem_pool->pool[0]))) && ( (uint8_t*)cbor_ptr <= ((uint8_t*) &(mem_pool->pool[mem_pool->pool_size_in_cbors - 1])))) 00170 00171 // Assuming cbor_ptr points to a cn_cbor object in the pool, return its index in the pool. Use this macro ONLY after asserting that cbor_ptr is in pool using IS_IN_POOL(). 00172 #define POS_IN_POOL(cbor_ptr, mem_pool) ( ((uint8_t*)cbor_ptr - ((uint8_t*) &(mem_pool->pool[0]))) / sizeof(mem_pool->pool[0]) ) 00173 00174 // Get the index of the bitmap array, in which the bit corresponding to mem_pool->pool[position_in_pool] resides. 00175 #define INDEX_IN_BITMAP(position_in_pool, mem_pool) ( position_in_pool / (sizeof(mem_pool->bitmap[0]) * 8 ) ) 00176 00177 // Get the position of the bit in the bitmap, corresponding to mem_pool->pool[position_in_pool]. 00178 #define POS_IN_INDEX(position_in_pool) ( position_in_pool % (sizeof(mem_pool->bitmap[0]) * 8 ) ) 00179 00180 /** 00181 * Free a cn_cbor object. 00182 * If the cn_cbor pointed to by ptr is in the pool, simply unset the corresponding bit in the bitmap. 00183 * If the cn_cbor pointed to by ptr is not in the pool, assume it was allocated with LIBC calloc (since pool was full), and free it using LIBC free. 00184 * 00185 * @param[in] ptr Pointer to a cn_cbor object we wish to free 00186 * @param[in] context Pointer to the CBOR context. 00187 * @return The address of the allocated memory. 00188 */ 00189 00190 void cbor_free(void *ptr, void *context) 00191 { 00192 int pos, bitmap_idx; 00193 cbor_mem_pool *mem_pool = (cbor_mem_pool *)(context); 00194 00195 // If ptr is in internal pool simply unset its bit in the bitmap 00196 if (IS_IN_POOL(ptr, mem_pool)) { 00197 // Get position of the bit 00198 pos = POS_IN_POOL(ptr, mem_pool); 00199 00200 bitmap_idx = INDEX_IN_BITMAP(pos, mem_pool); 00201 int pos_in_index = POS_IN_INDEX(pos); 00202 // Set the bit in the corresponding offset in the correct index of the bitmap 00203 mem_pool->bitmap[bitmap_idx] = mem_pool->bitmap[bitmap_idx] & ~(1ULL << pos_in_index); 00204 00205 CBOR_STATS_FREE(pool); 00206 } else { // If not in pool - allocated with libc calloc(), so we use libc free() 00207 free(ptr); 00208 00209 CBOR_STATS_FREE(heap); 00210 } 00211 } 00212 00213 cn_cbor_context *cn_cbor_init_context(size_t num_of_cbors_in_pool) 00214 { 00215 if (num_of_cbors_in_pool > MAX_SIZE_POOL_IN_CBORS) { 00216 return NULL; 00217 } 00218 00219 memset(&mem_pool_internal, 0, sizeof(mem_pool_internal)); 00220 00221 cbor_context->calloc_func = cbor_calloc; 00222 cbor_context->free_func = cbor_free; 00223 00224 mem_pool_internal.pool = calloc(num_of_cbors_in_pool, sizeof(cn_cbor)); 00225 mem_pool_internal.pool_size_in_cbors = num_of_cbors_in_pool; 00226 00227 cbor_context->context = &mem_pool_internal; 00228 00229 #ifdef USE_CBOR_CONTEXT_STATS 00230 number_of_pools_allocated++; 00231 total_bytes_allocated_for_pools += (num_of_cbors_in_pool * sizeof(cn_cbor)); 00232 #endif // USE_CBOR_CONTEXT_STATS 00233 00234 return cbor_context; 00235 } 00236 00237 void cn_cbor_free_context(cn_cbor_context *ctx) 00238 { 00239 if (ctx && ctx->context) { 00240 free(((cbor_mem_pool *)(ctx->context))->pool); 00241 } 00242 } 00243 00244 #ifdef USE_CBOR_CONTEXT_STATS 00245 #include <inttypes.h> 00246 void cn_cbor_context_print_stats() 00247 { 00248 printf(" ***************** CBOR Memory Statistics *****************\n"); 00249 printf(" * Total bytes allocated on heap: %" PRIu32 "\n", total_bytes_heap_allocated); 00250 printf(" * Number of heap allocations: %" PRIu32 "\n", calloc_heap_cntr); 00251 printf(" * Number of heap frees: %" PRIu32 "\n", free_heap_cntr); 00252 printf(" * Max peak ever allocated (heap): %" PRIu32 "\n", max_bytes_heap_allocated); 00253 printf(" *\n"); 00254 printf(" * Total bytes allocated in pool: %" PRIu32 "\n", total_bytes_pool_allocated); 00255 printf(" * Number of pool allocations: %" PRIu32 "\n", calloc_pool_cntr); 00256 printf(" * Number of pool frees: %" PRIu32 "\n", free_pool_cntr); 00257 printf(" * Max peak ever allocated (pool): %" PRIu32 "\n", max_bytes_pool_allocated); 00258 printf(" *\n"); 00259 printf(" * Total size of All CBOR pools ever allocated (bytes): %" PRIu32 "\n", total_bytes_allocated_for_pools); 00260 printf(" * Number of pools allocated: %" PRIu32 "\n", number_of_pools_allocated); 00261 printf(" ***********************************************************\n"); 00262 } 00263 00264 void cn_cbor_context_reset_stats() 00265 { 00266 calloc_heap_cntr = 0; 00267 free_heap_cntr = 0; 00268 calloc_pool_cntr = 0; 00269 free_pool_cntr = 0; 00270 bytes_heap_allocated = 0; 00271 total_bytes_heap_allocated = 0; 00272 max_bytes_heap_allocated = 0; 00273 bytes_pool_allocated = 0; 00274 total_bytes_pool_allocated = 0; 00275 max_bytes_pool_allocated = 0; 00276 number_of_pools_allocated = 0; 00277 total_bytes_allocated_for_pools = 0; 00278 } 00279 00280 #endif // USE_CBOR_CONTEXT_STATS 00281 00282 #endif // USE_CBOR_CONTEXT
Generated on Tue Jul 12 2022 19:01:33 by 1.7.2