diff options
author | Happy <markaizer@gmail.com> | 2014-08-21 04:50:46 +0800 |
---|---|---|
committer | Happy <markaizer@gmail.com> | 2014-08-21 04:50:46 +0800 |
commit | f52e1007fe08c67003c0bc4c78231904dd3fd5cc (patch) | |
tree | 99907d827264e501774e58ab4630e41fa7103c02 /src/common/ers.c | |
parent | 2410110dece79b4598c12f1c953219f1d0d1904a (diff) | |
parent | 769b1d05aa5cfa8cddfe7d21b35d5c5e4da3bbd6 (diff) | |
download | hercules-f52e1007fe08c67003c0bc4c78231904dd3fd5cc.tar.gz hercules-f52e1007fe08c67003c0bc4c78231904dd3fd5cc.tar.bz2 hercules-f52e1007fe08c67003c0bc4c78231904dd3fd5cc.tar.xz hercules-f52e1007fe08c67003c0bc4c78231904dd3fd5cc.zip |
Merge pull request #1 from HerculesWS/master
Update from original
Diffstat (limited to 'src/common/ers.c')
-rw-r--r-- | src/common/ers.c | 115 |
1 files changed, 60 insertions, 55 deletions
diff --git a/src/common/ers.c b/src/common/ers.c index 22269a51f..c8a11d2a9 100644 --- a/src/common/ers.c +++ b/src/common/ers.c @@ -13,16 +13,16 @@ * If it has reusable entries (freed entry), it uses one. * * So no assumption should be made about the data of the entry. * * Entries should be freed in the manager they where allocated from. * - * Failure to do so can lead to unexpected behaviours. * + * Failure to do so can lead to unexpected behaviors. * * * * <H2>Advantages:</H2> * * - The same manager is used for entries of the same size. * * So entries freed in one instance of the manager can be used by other * * instances of the manager. * * - Much less memory allocation/deallocation - program will be faster. * - * - Avoids memory fragmentaion - program will run better for longer. * + * - Avoids memory fragmentation - program will run better for longer. * * * - * <H2>Disavantages:</H2> * + * <H2>Disadvantages:</H2> * * - Unused entries are almost inevitable - memory being wasted. * * - A manager will only auto-destroy when all of its instances are * * destroyed so memory will usually only be recovered near the end. * @@ -39,12 +39,18 @@ * @encoding US-ASCII * * @see common#ers.h * \*****************************************************************************/ + +#define HERCULES_CORE + +#include "ers.h" + #include <stdlib.h> +#include <string.h> #include "../common/cbasetypes.h" #include "../common/malloc.h" // CREATE, RECREATE, aMalloc, aFree +#include "../common/nullpo.h" #include "../common/showmsg.h" // ShowMessage, ShowError, ShowFatalError, CL_BOLD, CL_NORMAL -#include "ers.h" #ifndef DISABLE_ERS @@ -72,7 +78,7 @@ typedef struct ers_cache // Memory blocks array unsigned char **Blocks; - // Max number of blocks + // Max number of blocks unsigned int Max; // Free objects count @@ -87,6 +93,9 @@ typedef struct ers_cache // Default = ERS_BLOCK_ENTRIES, can be adjusted for performance for individual cache sizes. unsigned int ChunkSize; + // Misc options, some options are shared from the instance + enum ERSOptions Options; + // Linked list struct ers_cache *Next, *Prev; } ers_cache_t; @@ -95,7 +104,7 @@ struct ers_instance_t { // Interface to ERS struct eri VTable; - // Name, used for debbuging purpouses + // Name, used for debugging purposes char *Name; // Misc options @@ -110,24 +119,23 @@ struct ers_instance_t { #ifdef DEBUG /* for data analysis [Ind/Hercules] */ unsigned int Peak; - struct ers_instance_t *Next, *Prev; #endif - + struct ers_instance_t *Next, *Prev; }; // Array containing a pointer for all ers_cache structures static ers_cache_t *CacheList = NULL; -#ifdef DEBUG - static struct ers_instance_t *InstanceList = NULL; -#endif +static struct ers_instance_t *InstanceList = NULL; -static ers_cache_t *ers_find_cache(unsigned int size) -{ +/** + * @param Options the options from the instance seeking a cache, we use it to give it a cache with matching configuration + **/ +static ers_cache_t *ers_find_cache(unsigned int size, enum ERSOptions Options) { ers_cache_t *cache; for (cache = CacheList; cache; cache = cache->Next) - if (cache->ObjectSize == size) + if ( cache->ObjectSize == size && cache->Options == ( Options & ERS_CACHE_OPTIONS ) ) return cache; CREATE(cache, ers_cache_t, 1); @@ -140,6 +148,7 @@ static ers_cache_t *ers_find_cache(unsigned int size) cache->UsedObjs = 0; cache->Max = 0; cache->ChunkSize = ERS_BLOCK_ENTRIES; + cache->Options = (Options & ERS_CACHE_OPTIONS); if (CacheList == NULL) { @@ -172,34 +181,28 @@ static void ers_free_cache(ers_cache_t *cache, bool remove) CacheList = cache->Next; aFree(cache->Blocks); + aFree(cache); } -static void *ers_obj_alloc_entry(ERS self) +static void *ers_obj_alloc_entry(ERS *self) { struct ers_instance_t *instance = (struct ers_instance_t *)self; void *ret; - if (instance == NULL) - { + if (instance == NULL) { ShowError("ers_obj_alloc_entry: NULL object, aborting entry freeing.\n"); return NULL; } - if (instance->Cache->ReuseList != NULL) - { + if (instance->Cache->ReuseList != NULL) { ret = (void *)((unsigned char *)instance->Cache->ReuseList + sizeof(struct ers_list)); instance->Cache->ReuseList = instance->Cache->ReuseList->Next; - } - else if (instance->Cache->Free > 0) - { + } else if (instance->Cache->Free > 0) { instance->Cache->Free--; ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; - } - else - { - if (instance->Cache->Used == instance->Cache->Max) - { + } else { + if (instance->Cache->Used == instance->Cache->Max) { instance->Cache->Max = (instance->Cache->Max * 4) + 3; RECREATE(instance->Cache->Blocks, unsigned char *, instance->Cache->Max); } @@ -222,47 +225,45 @@ static void *ers_obj_alloc_entry(ERS self) return ret; } -static void ers_obj_free_entry(ERS self, void *entry) +static void ers_obj_free_entry(ERS *self, void *entry) { struct ers_instance_t *instance = (struct ers_instance_t *)self; struct ers_list *reuse = (struct ers_list *)((unsigned char *)entry - sizeof(struct ers_list)); - if (instance == NULL) - { + if (instance == NULL) { ShowError("ers_obj_free_entry: NULL object, aborting entry freeing.\n"); return; - } - else if (entry == NULL) - { + } else if (entry == NULL) { ShowError("ers_obj_free_entry: NULL entry, nothing to free.\n"); return; } + if( instance->Cache->Options & ERS_OPT_CLEAN ) + memset((unsigned char*)reuse + sizeof(struct ers_list), 0, instance->Cache->ObjectSize - sizeof(struct ers_list)); + reuse->Next = instance->Cache->ReuseList; instance->Cache->ReuseList = reuse; instance->Count--; instance->Cache->UsedObjs--; } -static size_t ers_obj_entry_size(ERS self) +static size_t ers_obj_entry_size(ERS *self) { struct ers_instance_t *instance = (struct ers_instance_t *)self; - if (instance == NULL) - { + if (instance == NULL) { ShowError("ers_obj_entry_size: NULL object, aborting entry freeing.\n"); return 0; - } + } return instance->Cache->ObjectSize; } -static void ers_obj_destroy(ERS self) +static void ers_obj_destroy(ERS *self) { struct ers_instance_t *instance = (struct ers_instance_t *)self; - if (instance == NULL) - { + if (instance == NULL) { ShowError("ers_obj_destroy: NULL object, aborting entry freeing.\n"); return; } @@ -274,7 +275,6 @@ static void ers_obj_destroy(ERS self) if (--instance->Cache->ReferenceCount <= 0) ers_free_cache(instance->Cache, true); -#ifdef DEBUG if (instance->Next) instance->Next->Prev = instance->Prev; @@ -282,7 +282,6 @@ static void ers_obj_destroy(ERS self) instance->Prev->Next = instance->Next; else InstanceList = instance->Next; -#endif if( instance->Options & ERS_OPT_FREE_NAME ) aFree(instance->Name); @@ -290,19 +289,20 @@ static void ers_obj_destroy(ERS self) aFree(instance); } -void ers_cache_size(ERS self, unsigned int new_size) { +void ers_cache_size(ERS *self, unsigned int new_size) { struct ers_instance_t *instance = (struct ers_instance_t *)self; - if (instance == NULL) {//change as per piotrhalaczkiewicz comment - ShowError("ers_cache_size: NULL object, skipping...\n"); - return; + nullpo_retv(instance); + + if( !(instance->Cache->Options&ERS_OPT_FLEX_CHUNK) ) { + ShowWarning("ers_cache_size: '%s' has adjusted its chunk size to '%d', however ERS_OPT_FLEX_CHUNK is missing!\n",instance->Name,new_size); } instance->Cache->ChunkSize = new_size; } -ERS ers_new(uint32 size, char *name, enum ERSOptions options) +ERS *ers_new(uint32 size, char *name, enum ERSOptions options) { struct ers_instance_t *instance; CREATE(instance,struct ers_instance_t, 1); @@ -320,9 +320,10 @@ ERS ers_new(uint32 size, char *name, enum ERSOptions options) instance->Name = ( options & ERS_OPT_FREE_NAME ) ? aStrdup(name) : name; instance->Options = options; - instance->Cache = ers_find_cache(size); + instance->Cache = ers_find_cache(size,instance->Options); + instance->Cache->ReferenceCount++; -#ifdef DEBUG + if (InstanceList == NULL) { InstanceList = instance; } else { @@ -331,7 +332,6 @@ ERS ers_new(uint32 size, char *name, enum ERSOptions options) InstanceList = instance; InstanceList->Prev = NULL; } -#endif instance->Count = 0; @@ -379,12 +379,17 @@ void ers_report(void) { ShowInfo("ers_report: '"CL_WHITE"%u"CL_NORMAL"' blocks total, consuming '"CL_WHITE"%.2f MB"CL_NORMAL"' \n",blocks_a,(double)((memory_t)/1024)/1024); } -void ers_force_destroy_all(void) -{ - ers_cache_t *cache; +/** + * Call on shutdown to clear remaining entries + **/ +void ers_final(void) { + struct ers_instance_t *instance = InstanceList, *next; - for (cache = CacheList; cache; cache = cache->Next) - ers_free_cache(cache, false); + while( instance ) { + next = instance->Next; + ers_obj_destroy((ERS*)instance); + instance = next; + } } #endif |