#include "license_pbs.h" /* See here for the software license */ #include "u_memmgr.h" #include "pbs_error.h" #include #include /* The following three functions are for unit testing purposes * The are overridden in the test code to generate full coverage of all * variations of the functions. * Please do not touch */ void *malloc_track(size_t __size) { return calloc(1, __size); } void *calloc_track(size_t __nmemb, size_t __size) { return calloc(__nmemb, __size); } void free_track(void *__ptr) { free(__ptr); } int memmgr_init(memmgr **mgr, int mgr_size) { int rc = PBSE_NONE; memmgr *mm = NULL; if (mgr == NULL) rc = -3; else if ((mm = (memmgr *)malloc_track(sizeof(memmgr))) == NULL) rc = -1; else { if (mgr_size <= 0) mm->alloc_size = MEMMGR_DEFAULT_SIZE; else mm->alloc_size = mgr_size; mm->the_mem = (unsigned char *)calloc_track(1, mm->alloc_size); if (mm->the_mem == NULL) rc = -2; else { mm->remaining = mm->alloc_size; mm->ref_count = 0; mm->current_pos = mm->the_mem; mm->prev_mgr = NULL; mm->next_mgr = NULL; mm->current_mgr = mm; *mgr = mm; } } if (rc != PBSE_NONE) { if (mm) { if (mm->the_mem) free_track(mm->the_mem); free_track(mm); } } return rc; } int memmgr_extend(memmgr **mgr, int size) { int rc = PBSE_NONE; memmgr *new_mgr = NULL; if ((rc = memmgr_init(&new_mgr, size)) == PBSE_NONE) { (*mgr)->current_mgr->next_mgr = new_mgr; new_mgr->prev_mgr = (*mgr)->current_mgr; (*mgr)->current_mgr = new_mgr; new_mgr->current_mgr = NULL; } return rc; } void *memmgr_calloc(memmgr **mgr, int qty, int size) { int rc = PBSE_MEM_MALLOC; int qps = qty * size; void *new_mem = NULL; memmgr *mm = NULL; /* sizeof(int) == size of requested memory * size == memory requested * 1 == null ptr */ int real_size = sizeof(int) + (qty * size) + 1; if ((mgr != NULL) && (*mgr != NULL) && (qps > 0)) { mm = (*mgr)->current_mgr; if (mm->remaining > real_size) { rc = PBSE_NONE; } else { if (qty*size > MEMMGR_DEFAULT_SIZE) { mm = NULL; rc = memmgr_shuffle(mgr, &mm, qty*size); } else { if ((rc = memmgr_extend(mgr, 0)) == PBSE_NONE) { mm = (*mgr)->current_mgr; } } } } if (rc == PBSE_NONE) { memcpy(mm->current_pos, &size, sizeof(int)); mm->current_pos += sizeof(int); new_mem = mm->current_pos; mm->current_pos[size] = '\0'; mm->current_pos += size + 1; mm->remaining -= real_size; mm->ref_count++; } return new_mem; } char *memmgr_strdup( memmgr **mgr, char *value, int *size) { char *rv = NULL; int t_size = 0; if (value == NULL) t_size = 0; else t_size = strlen(value) + 1; if (t_size <= 0) { } else if ((rv = (char *)memmgr_calloc(mgr, 1, t_size)) != NULL) { strcpy(rv, value); if (size != NULL) *size = t_size; } return(rv); } /* END memmgr_strdup() */ char *memmgr_strcat(memmgr **mgr, char *val1, char *val2, int *size) { int t_size = 0; char *rv = NULL; if (val2 == NULL) return val1; else if (val1 == NULL) return val2; else { t_size = strlen(val1) + strlen(val2) + 1; if ((rv = (char *)memmgr_calloc(mgr, 1, t_size)) != NULL) { rv = (char *)memmgr_calloc(mgr, 1, t_size); strcpy(rv, val1); strcat(rv, val2); } } return rv; } /* finds which memmgr a ptr belongs to, returns NULL if not valid */ memmgr *memmgr_find(memmgr **mmgr, void *ptr) { memmgr *mm = NULL; if ((mmgr == NULL) || (*mmgr == NULL) || (ptr == NULL)) { mm = NULL; } else { mm = *mmgr; while (mm) { if (((unsigned char *)ptr > mm->the_mem) && ((unsigned char *)ptr < (mm->the_mem + mm->alloc_size))) { break; } mm = mm->next_mgr; } } return mm; } /* * Returns null if the pointer is not in an allocated range * or insufficient memory is available. * undefined */ void *memmgr_realloc(memmgr **mgr, void *ptr, int new_size) { void *res_mem = NULL; int new_alloc = sizeof(int) + new_size + 1; int size = 0; memmgr *mm = memmgr_find(mgr, ptr); void *tmp = NULL; if ((new_size > 0) && (mm == NULL)) { if ((mgr != NULL) && (*mgr != NULL)) { res_mem = memmgr_calloc(mgr, 1, new_size); } } else if (new_size > 0) { memcpy(&size, ((int *)ptr) - 1, sizeof(int)); /* Requested realloc is smaller than the current alloc */ if (new_size < size) { memcpy(((unsigned char *)ptr) - sizeof(int), &new_size, sizeof(int)); res_mem = (unsigned char *)ptr; ((unsigned char *)ptr)[new_size] = '\0'; /* As we will move requests for larger allocation, * there is no point in clearing the remaining memory */ /* memset(ptr + new_size, 0, size - new_size); */ /* Only one reference in block, make unused mem available */ if (mm->ref_count == 1) { mm->current_pos = mm->the_mem + new_alloc; mm->remaining = mm->alloc_size - new_alloc; memset(mm->the_mem + new_alloc, 0, size - new_size); memcpy(mm->the_mem, &new_size, sizeof(int)); } } /* Only one reference in this memory chunk. */ else if (mm->ref_count == 1) { /* Larger than all the mem in the chuck */ if (new_size > mm->alloc_size) { /* as it's the only thing, realloc the current block */ if ((tmp = realloc(mm->the_mem, new_alloc)) != NULL) { mm->the_mem = (unsigned char *)tmp; memset(mm->the_mem + mm->alloc_size, 0, new_alloc - mm->alloc_size); res_mem = mm->the_mem + sizeof(int); mm->alloc_size = new_alloc; mm->remaining = 0; mm->current_pos = NULL; memcpy(mm->the_mem, &new_size, sizeof(int)); } else { free(mm->the_mem); mm->the_mem = NULL; } } /* new_size > existing, less than total and only one ref */ else { memset(mm->the_mem + sizeof(int) + size, 0, new_size - size); mm->the_mem[new_size - 1] = '\0'; mm->remaining = mm->alloc_size - new_alloc; mm->current_pos = mm->the_mem + new_alloc; res_mem = mm->the_mem + sizeof(int); memcpy(mm->the_mem, &new_size, sizeof(int)); } } else { res_mem = memmgr_calloc(mgr, 1, new_size); memcpy(res_mem, ptr, size); /* Return value is not checked as the ptr was validated in * memmgr_find above */ memmgr_free(&mm, ptr); } } return res_mem; } int memmgr_free(memmgr **mgr, void *ptr) { int rc = PBSE_MEM_MALLOC; int size = 0; char *size_ptr = NULL; memmgr *mm = memmgr_find(mgr, ptr); memmgr *new_head = NULL; if (mm != NULL) { size_ptr = (char *)ptr - sizeof(int); memcpy(&size, size_ptr, sizeof(int)); memset(size_ptr, 0, size+sizeof(int)); mm->ref_count--; if (mm->ref_count == 0) { mm->current_pos = mm->the_mem; if (mm->current_mgr == NULL) { if (((*mgr)->current_mgr != *mgr) && ((*mgr)->current_mgr != mm)) { memmgr_remove(&mm); } } else { if ((*mgr)->next_mgr != NULL) { new_head = (*mgr)->next_mgr; new_head->current_mgr = (*mgr)->current_mgr; } memmgr_remove(&mm); *mgr = new_head; } } rc = PBSE_NONE; } return rc; } /* free the memmgr chain */ void memmgr_destroy(memmgr **mgr) { memmgr *mm = *mgr; memmgr *next_mgr = NULL; while (mm != NULL) { next_mgr = mm->next_mgr; free_track(mm->the_mem); mm->the_mem = NULL; free_track(mm); mm = NULL; mm = next_mgr; } *mgr = NULL; } int memmgr_shuffle(memmgr **mgr, memmgr **new_mgr, int size) { int rc = memmgr_init(new_mgr, size + sizeof(int) + 1); memmgr *mm = NULL; if (rc == PBSE_NONE) { mm = (*mgr)->current_mgr; (*new_mgr)->next_mgr = mm; if (mm->prev_mgr == NULL) { mm->prev_mgr = (*new_mgr); /* The head node got replaced with new_mgr, move the current_mgr ptr * to point to the old head node */ (*new_mgr)->current_mgr = mm; mm->current_mgr = NULL; *mgr = *new_mgr; } else { (*new_mgr)->prev_mgr = mm->prev_mgr; mm->prev_mgr->next_mgr = (*new_mgr); mm->prev_mgr = (*new_mgr); (*new_mgr)->current_mgr = NULL; } } return rc; } /* removes an individual memmgr from a chain */ void memmgr_remove(memmgr **mgr) { if ((*mgr)->prev_mgr != NULL) (*mgr)->prev_mgr->next_mgr = (*mgr)->next_mgr; if ((*mgr)->next_mgr != NULL) (*mgr)->next_mgr->prev_mgr = (*mgr)->prev_mgr; free_track((*mgr)->the_mem); free_track(*mgr); *mgr = NULL; }