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 gballoc.c Source File

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 }