Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of azure_c_shared_utility by
gballoc.c
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 #include <stdlib.h> 00005 #include <stdint.h> 00006 #include <stddef.h> 00007 #include "azure_c_shared_utility/lock.h" 00008 #include "azure_c_shared_utility/optimize_size.h" 00009 #include "azure_c_shared_utility/xlogging.h" 00010 00011 #ifndef SIZE_MAX 00012 #define SIZE_MAX ((size_t)~(size_t)0) 00013 #endif 00014 00015 typedef struct ALLOCATION_TAG 00016 { 00017 size_t size; 00018 void* ptr; 00019 void* next; 00020 } ALLOCATION; 00021 00022 typedef enum GBALLOC_STATE_TAG 00023 { 00024 GBALLOC_STATE_INIT, 00025 GBALLOC_STATE_NOT_INIT 00026 } GBALLOC_STATE; 00027 00028 static ALLOCATION* head = NULL; 00029 static size_t totalSize = 0; 00030 static size_t maxSize = 0; 00031 static GBALLOC_STATE gballocState = GBALLOC_STATE_NOT_INIT; 00032 00033 static LOCK_HANDLE gballocThreadSafeLock = NULL; 00034 00035 int gballoc_init(void) 00036 { 00037 int result; 00038 00039 if (gballocState != GBALLOC_STATE_NOT_INIT) 00040 { 00041 /* Codes_SRS_GBALLOC_01_025: [Init after Init shall fail and return a non-zero value.] */ 00042 result = __FAILURE__; 00043 } 00044 /* Codes_SRS_GBALLOC_01_026: [gballoc_Init shall create a lock handle that will be used to make the other gballoc APIs thread-safe.] */ 00045 else if ((gballocThreadSafeLock = Lock_Init()) == NULL) 00046 { 00047 /* Codes_SRS_GBALLOC_01_027: [If the Lock creation fails, gballoc_init shall return a non-zero value.]*/ 00048 result = __FAILURE__; 00049 } 00050 else 00051 { 00052 gballocState = GBALLOC_STATE_INIT; 00053 00054 /* Codes_ SRS_GBALLOC_01_002: [Upon initialization the total memory used and maximum total memory used tracked by the module shall be set to 0.] */ 00055 totalSize = 0; 00056 maxSize = 0; 00057 00058 /* Codes_SRS_GBALLOC_01_024: [gballoc_init shall initialize the gballoc module and return 0 upon success.] */ 00059 result = 0; 00060 } 00061 00062 return result; 00063 } 00064 00065 void gballoc_deinit(void) 00066 { 00067 if (gballocState == GBALLOC_STATE_INIT) 00068 { 00069 /* Codes_SRS_GBALLOC_01_028: [gballoc_deinit shall free all resources allocated by gballoc_init.] */ 00070 (void)Lock_Deinit(gballocThreadSafeLock); 00071 } 00072 00073 gballocState = GBALLOC_STATE_NOT_INIT; 00074 } 00075 00076 void* gballoc_malloc(size_t size) 00077 { 00078 void* result; 00079 00080 if (gballocState != GBALLOC_STATE_INIT) 00081 { 00082 /* Codes_SRS_GBALLOC_01_039: [If gballoc was not initialized gballoc_malloc shall simply call malloc without any memory tracking being performed.] */ 00083 result = malloc(size); 00084 } 00085 /* Codes_SRS_GBALLOC_01_030: [gballoc_malloc shall ensure thread safety by using the lock created by gballoc_Init.] */ 00086 else if (LOCK_OK != Lock(gballocThreadSafeLock)) 00087 { 00088 /* Codes_SRS_GBALLOC_01_048: [If acquiring the lock fails, gballoc_malloc shall return NULL.] */ 00089 LogError("Failed to get the Lock."); 00090 result = NULL; 00091 } 00092 else 00093 { 00094 ALLOCATION* allocation = (ALLOCATION*)malloc(sizeof(ALLOCATION)); 00095 if (allocation == NULL) 00096 { 00097 result = NULL; 00098 } 00099 else 00100 { 00101 /* Codes_SRS_GBALLOC_01_003: [gb_malloc shall call the C99 malloc function and return its result.] */ 00102 result = malloc(size); 00103 if (result == NULL) 00104 { 00105 /* Codes_SRS_GBALLOC_01_012: [When the underlying malloc call fails, gballoc_malloc shall return NULL and size should not be counted towards total memory used.] */ 00106 free(allocation); 00107 } 00108 else 00109 { 00110 /* Codes_SRS_GBALLOC_01_004: [If the underlying malloc call is successful, gb_malloc shall increment the total memory used with the amount indicated by size.] */ 00111 allocation->ptr = result; 00112 allocation->size = size; 00113 allocation->next = head; 00114 head = allocation; 00115 00116 totalSize += size; 00117 /* Codes_SRS_GBALLOC_01_011: [The maximum total memory used shall be the maximum of the total memory used at any point.] */ 00118 if (maxSize < totalSize) 00119 { 00120 maxSize = totalSize; 00121 } 00122 } 00123 } 00124 00125 (void)Unlock(gballocThreadSafeLock); 00126 } 00127 00128 return result; 00129 } 00130 00131 void* gballoc_calloc(size_t nmemb, size_t size) 00132 { 00133 void* result; 00134 00135 if (gballocState != GBALLOC_STATE_INIT) 00136 { 00137 /* Codes_SRS_GBALLOC_01_040: [If gballoc was not initialized gballoc_calloc shall simply call calloc without any memory tracking being performed.] */ 00138 result = calloc(nmemb, size); 00139 } 00140 /* Codes_SRS_GBALLOC_01_031: [gballoc_calloc shall ensure thread safety by using the lock created by gballoc_Init] */ 00141 else if (LOCK_OK != Lock(gballocThreadSafeLock)) 00142 { 00143 /* Codes_SRS_GBALLOC_01_046: [If acquiring the lock fails, gballoc_calloc shall return NULL.] */ 00144 LogError("Failed to get the Lock."); 00145 result = NULL; 00146 } 00147 else 00148 { 00149 ALLOCATION* allocation = (ALLOCATION*)malloc(sizeof(ALLOCATION)); 00150 if (allocation == NULL) 00151 { 00152 result = NULL; 00153 } 00154 else 00155 { 00156 /* Codes_SRS_GBALLOC_01_020: [gballoc_calloc shall call the C99 calloc function and return its result.] */ 00157 result = calloc(nmemb, size); 00158 if (result == NULL) 00159 { 00160 /* Codes_SRS_GBALLOC_01_022: [When the underlying calloc call fails, gballoc_calloc shall return NULL and size should not be counted towards total memory used.] */ 00161 free(allocation); 00162 } 00163 else 00164 { 00165 /* Codes_SRS_GBALLOC_01_021: [If the underlying calloc call is successful, gballoc_calloc shall increment the total memory used with nmemb*size.] */ 00166 allocation->ptr = result; 00167 allocation->size = nmemb * size; 00168 allocation->next = head; 00169 head = allocation; 00170 00171 totalSize += allocation->size; 00172 /* Codes_SRS_GBALLOC_01_011: [The maximum total memory used shall be the maximum of the total memory used at any point.] */ 00173 if (maxSize < totalSize) 00174 { 00175 maxSize = totalSize; 00176 } 00177 } 00178 } 00179 00180 (void)Unlock(gballocThreadSafeLock); 00181 } 00182 00183 return result; 00184 } 00185 00186 void* gballoc_realloc(void* ptr, size_t size) 00187 { 00188 ALLOCATION* curr; 00189 void* result; 00190 ALLOCATION* allocation = NULL; 00191 00192 if (gballocState != GBALLOC_STATE_INIT) 00193 { 00194 /* Codes_SRS_GBALLOC_01_041: [If gballoc was not initialized gballoc_realloc shall shall simply call realloc without any memory tracking being performed.] */ 00195 result = realloc(ptr, size); 00196 } 00197 /* Codes_SRS_GBALLOC_01_032: [gballoc_realloc shall ensure thread safety by using the lock created by gballoc_Init.] */ 00198 else if (LOCK_OK != Lock(gballocThreadSafeLock)) 00199 { 00200 /* Codes_SRS_GBALLOC_01_047: [If acquiring the lock fails, gballoc_realloc shall return NULL.] */ 00201 LogError("Failed to get the Lock."); 00202 result = NULL; 00203 } 00204 else 00205 { 00206 if (ptr == NULL) 00207 { 00208 /* Codes_SRS_GBALLOC_01_017: [When ptr is NULL, gballoc_realloc shall call the underlying realloc with ptr being NULL and the realloc result shall be tracked by gballoc.] */ 00209 allocation = (ALLOCATION*)malloc(sizeof(ALLOCATION)); 00210 } 00211 else 00212 { 00213 curr = head; 00214 while (curr != NULL) 00215 { 00216 if (curr->ptr == ptr) 00217 { 00218 allocation = curr; 00219 break; 00220 } 00221 else 00222 { 00223 curr = (ALLOCATION*)curr->next; 00224 } 00225 } 00226 } 00227 00228 if (allocation == NULL) 00229 { 00230 /* Codes_SRS_GBALLOC_01_015: [When allocating memory used for tracking by gballoc_realloc fails, gballoc_realloc shall return NULL and no change should be made to the counted total memory usage.] */ 00231 /* Codes_SRS_GBALLOC_01_016: [When the ptr pointer cannot be found in the pointers tracked by gballoc, gballoc_realloc shall return NULL and the underlying realloc shall not be called.] */ 00232 result = NULL; 00233 } 00234 else 00235 { 00236 result = realloc(ptr, size); 00237 if (result == NULL) 00238 { 00239 /* Codes_SRS_GBALLOC_01_014: [When the underlying realloc call fails, gballoc_realloc shall return NULL and no change should be made to the counted total memory usage.] */ 00240 if (ptr == NULL) 00241 { 00242 free(allocation); 00243 } 00244 } 00245 else 00246 { 00247 if (ptr != NULL) 00248 { 00249 /* Codes_SRS_GBALLOC_01_006: [If the underlying realloc call is successful, gballoc_realloc shall look up the size associated with the pointer ptr and decrease the total memory used with that size.] */ 00250 allocation->ptr = result; 00251 totalSize -= allocation->size; 00252 allocation->size = size; 00253 } 00254 else 00255 { 00256 /* add block */ 00257 allocation->ptr = result; 00258 allocation->size = size; 00259 allocation->next = head; 00260 head = allocation; 00261 } 00262 00263 /* Codes_SRS_GBALLOC_01_007: [If realloc is successful, gballoc_realloc shall also increment the total memory used value tracked by this module.] */ 00264 totalSize += size; 00265 00266 /* Codes_SRS_GBALLOC_01_011: [The maximum total memory used shall be the maximum of the total memory used at any point.] */ 00267 if (maxSize < totalSize) 00268 { 00269 maxSize = totalSize; 00270 } 00271 } 00272 } 00273 00274 (void)Unlock(gballocThreadSafeLock); 00275 } 00276 00277 return result; 00278 } 00279 00280 void gballoc_free(void* ptr) 00281 { 00282 ALLOCATION* curr = head; 00283 ALLOCATION* prev = NULL; 00284 00285 if (gballocState != GBALLOC_STATE_INIT) 00286 { 00287 /* Codes_SRS_GBALLOC_01_042: [If gballoc was not initialized gballoc_free shall shall simply call free.] */ 00288 free(ptr); 00289 } 00290 /* Codes_SRS_GBALLOC_01_033: [gballoc_free shall ensure thread safety by using the lock created by gballoc_Init.] */ 00291 else if (LOCK_OK != Lock(gballocThreadSafeLock)) 00292 { 00293 /* Codes_SRS_GBALLOC_01_049: [If acquiring the lock fails, gballoc_free shall do nothing.] */ 00294 LogError("Failed to get the Lock."); 00295 } 00296 else 00297 { 00298 /* Codes_SRS_GBALLOC_01_009: [gballoc_free shall also look up the size associated with the ptr pointer and decrease the total memory used with the associated size amount.] */ 00299 while (curr != NULL) 00300 { 00301 if (curr->ptr == ptr) 00302 { 00303 /* Codes_SRS_GBALLOC_01_008: [gballoc_free shall call the C99 free function.] */ 00304 free(ptr); 00305 totalSize -= curr->size; 00306 if (prev != NULL) 00307 { 00308 prev->next = curr->next; 00309 } 00310 else 00311 { 00312 head = (ALLOCATION*)curr->next; 00313 } 00314 00315 free(curr); 00316 break; 00317 } 00318 00319 prev = curr; 00320 curr = (ALLOCATION*)curr->next; 00321 } 00322 00323 if ((curr == NULL) && (ptr != NULL)) 00324 { 00325 /* Codes_SRS_GBALLOC_01_019: [When the ptr pointer cannot be found in the pointers tracked by gballoc, gballoc_free shall not free any memory.] */ 00326 00327 /* could not find the allocation */ 00328 LogError("Could not free allocation for address %p (not found)", ptr); 00329 } 00330 (void)Unlock(gballocThreadSafeLock); 00331 } 00332 } 00333 00334 size_t gballoc_getMaximumMemoryUsed(void) 00335 { 00336 size_t result; 00337 00338 /* Codes_SRS_GBALLOC_01_038: [If gballoc was not initialized gballoc_getMaximumMemoryUsed shall return MAX_INT_SIZE.] */ 00339 if (gballocState != GBALLOC_STATE_INIT) 00340 { 00341 LogError("gballoc is not initialized."); 00342 result = SIZE_MAX; 00343 } 00344 /* Codes_SRS_GBALLOC_01_034: [gballoc_getMaximumMemoryUsed shall ensure thread safety by using the lock created by gballoc_Init.] */ 00345 else if (LOCK_OK != Lock(gballocThreadSafeLock)) 00346 { 00347 /* Codes_SRS_GBALLOC_01_050: [If the lock cannot be acquired, gballoc_getMaximumMemoryUsed shall return SIZE_MAX.] */ 00348 LogError("Failed to get the Lock."); 00349 result = SIZE_MAX; 00350 } 00351 else 00352 { 00353 /* Codes_SRS_GBALLOC_01_010: [gballoc_getMaximumMemoryUsed shall return the maximum amount of total memory used recorded since the module initialization.] */ 00354 result = maxSize; 00355 (void)Unlock(gballocThreadSafeLock); 00356 } 00357 00358 return result; 00359 } 00360 00361 size_t gballoc_getCurrentMemoryUsed(void) 00362 { 00363 size_t result; 00364 00365 /* Codes_SRS_GBALLOC_01_044: [If gballoc was not initialized gballoc_getCurrentMemoryUsed shall return SIZE_MAX.] */ 00366 if (gballocState != GBALLOC_STATE_INIT) 00367 { 00368 LogError("gballoc is not initialized."); 00369 result = SIZE_MAX; 00370 } 00371 /* Codes_SRS_GBALLOC_01_036: [gballoc_getCurrentMemoryUsed shall ensure thread safety by using the lock created by gballoc_Init.]*/ 00372 else if (LOCK_OK != Lock(gballocThreadSafeLock)) 00373 { 00374 /* Codes_SRS_GBALLOC_01_051: [If the lock cannot be acquired, gballoc_getCurrentMemoryUsed shall return SIZE_MAX.] */ 00375 LogError("Failed to get the Lock."); 00376 result = SIZE_MAX; 00377 } 00378 else 00379 { 00380 /*Codes_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ 00381 result = totalSize; 00382 (void)Unlock(gballocThreadSafeLock); 00383 } 00384 00385 return result; 00386 }
Generated on Tue Jul 12 2022 19:14:38 by
1.7.2
